From b21dbbb420d25c3274b76642f407d9dd3ba56094 Mon Sep 17 00:00:00 2001 From: Gonzalo Chumillas Date: Tue, 20 May 2025 13:41:57 +0100 Subject: [PATCH] jsgen: alias types are not properly resolved (fix #24486) (fix #24507) (#24514) --- vlib/v/gen/js/auto_eq_methods.v | 13 +++- vlib/v/gen/js/infix.v | 25 ++++++-- vlib/v/gen/js/tests/alias.v | 105 ++++++++++++++++++++++++++++++-- vlib/v/gen/js/util.v | 27 +++++++- 4 files changed, 158 insertions(+), 12 deletions(-) diff --git a/vlib/v/gen/js/auto_eq_methods.v b/vlib/v/gen/js/auto_eq_methods.v index 4f654b331..48b2284db 100644 --- a/vlib/v/gen/js/auto_eq_methods.v +++ b/vlib/v/gen/js/auto_eq_methods.v @@ -2,6 +2,7 @@ module js import v.ast import strings +import arrays fn (mut g JsGen) gen_sumtype_equality_fn(left_type ast.Type) string { left := g.unwrap(left_type) @@ -19,9 +20,19 @@ fn (mut g JsGen) gen_sumtype_equality_fn(left_type ast.Type) string { fn_builder.writeln('\tlet aProto = Object.getPrototypeOf(a);') fn_builder.writeln('\tlet bProto = Object.getPrototypeOf(b);') fn_builder.writeln('\tif (aProto !== bProto) { return new bool(false); }') + mut variants := []Type{} for typ in info.variants { variant := g.unwrap(typ) - fn_builder.writeln('\tif (aProto == ${g.js_name(variant.sym.name)}) {') + if variant.unaliased_sym.info is ast.SumType { + variants << g.unwrap_sum_type(typ) + } else { + variants << variant + } + } + variants = arrays.distinct(variants) + for variant in variants { + typ := variant.typ + fn_builder.writeln('\tif (aProto == ${g.js_name(variant.unaliased_sym.name)}.prototype) {') if variant.sym.kind == .string { fn_builder.writeln('\t\treturn new bool(a.str == b.str);') } else if variant.sym.kind == .sum_type && !typ.is_ptr() { diff --git a/vlib/v/gen/js/infix.v b/vlib/v/gen/js/infix.v index d9116b820..0663942b8 100644 --- a/vlib/v/gen/js/infix.v +++ b/vlib/v/gen/js/infix.v @@ -337,12 +337,27 @@ fn (mut g JsGen) infix_in_not_in_op(node ast.InfixExpr) { } fn (mut g JsGen) infix_is_not_is_op(node ast.InfixExpr) { - g.expr(node.left) - rsym := g.table.sym(g.unwrap(node.right_type).typ) + rsym := g.unwrap(node.right_type).unaliased_sym - g.gen_deref_ptr(node.left_type) - g.write(' instanceof ') - g.write(g.js_name(rsym.name)) + if rsym.info is ast.SumType { + g.write('[') + variants := g.unwrap_sum_type(node.right_type) + for i, v in variants { + g.write(g.js_name(v.unaliased_sym.name)) + if i < variants.len - 1 { + g.write(', ') + } + } + g.write('].some(t => ') + g.expr(node.left) + g.gen_deref_ptr(node.left_type) + g.write(' instanceof t.valueOf())') + } else { + g.expr(node.left) + g.gen_deref_ptr(node.left_type) + g.write(' instanceof ') + g.write(g.js_name(rsym.name)) + } } fn (mut g JsGen) infix_expr(node ast.InfixExpr) { diff --git a/vlib/v/gen/js/tests/alias.v b/vlib/v/gen/js/tests/alias.v index f1f2bd79d..99f3a08a4 100644 --- a/vlib/v/gen/js/tests/alias.v +++ b/vlib/v/gen/js/tests/alias.v @@ -1,30 +1,127 @@ type Type0 = string type Type1 = int | string type Type2 = string | int +type Type3 = Type0 | int +type Type4 = Type3 | Type1 | f32 +type Type5 = Type4 | bool struct Foo { field_0 Type0 field_1 Type1 field_2 Type2 + field_3 Type3 + field_4 Type4 + field_5 Type5 } -fn main() { +fn basic_assertion() { + foo := Type1('') + assert foo == Type1('') +} + +fn struct_with_default_values() { foo := Foo{} - // checks alias types assert foo.field_0 == '' - // checks sum types if foo.field_1 is int { assert foo.field_1 == 0 } else { assert false } - // checks sum types if foo.field_2 is string { assert foo.field_2 == '' } else { assert false } + + if foo.field_3 is Type0 { + assert foo.field_3 == '' + assert foo.field_3 == Type0('') + } else { + assert false + } + + // TODO: uncomment until the C backend is improved + // if foo.field_4 is Type3 { + // assert foo.field_4 == Type3(Type0('')) + // } else { + // assert false + // } + + // TODO: uncomment until the C backend is improved + // if foo.field_5 is Type4 { + // assert foo.field_4 == Type4(Type3(Type0(''))) + // } else { + // assert false + // } +} + +fn struct_with_values() { + // test 0 + f0 := Foo{ + field_0: 'hello' + field_1: 'world' + field_2: 100 + field_3: 200 + field_4: f32(3.14) + field_5: true + } + + assert f0.field_0 == 'hello' + + if f0.field_1 is string { + assert f0.field_1 == 'world' + } else { + assert false + } + + if f0.field_2 is int { + assert f0.field_2 == 100 + } else { + assert false + } + + if f0.field_3 is int { + assert f0.field_3 == 200 + } else { + assert false + } + + if f0.field_4 is f32 { + assert f0.field_4 == 3.14 + } else { + assert false + } + + if f0.field_5 is bool { + assert f0.field_5 + } else { + assert false + } + + // test 1 + f1 := Foo{ + field_4: Type3(100) + field_5: Type4(Type3(Type0('hello'))) + } + + if f1.field_4 is Type3 { + assert f1.field_4 == Type3(100) + } else { + assert false + } + + if f1.field_5 is Type4 { + assert f1.field_5 == Type4(Type3(Type0('hello'))) + } else { + assert false + } +} + +fn main() { + basic_assertion() + struct_with_default_values() + struct_with_values() } diff --git a/vlib/v/gen/js/util.v b/vlib/v/gen/js/util.v index a764abe4c..110df1cfe 100644 --- a/vlib/v/gen/js/util.v +++ b/vlib/v/gen/js/util.v @@ -1,6 +1,7 @@ module js import v.ast +import arrays struct Type { // typ is the original type @@ -12,6 +13,14 @@ struct Type { unaliased_sym &ast.TypeSymbol = unsafe { nil } @[required] } +fn (a Type) == (b Type) bool { + return a.unaliased == b.unaliased +} + +fn (a Type) < (b Type) bool { + return a.unaliased_sym.name < b.unaliased_sym.name +} + // unwrap returns the following variants of a type: // * generics unwrapped // * alias unwrapped @@ -26,10 +35,24 @@ fn (mut g JsGen) unwrap(typ ast.Type) Type { unaliased_sym: no_generic_sym } } + no_generic_unaliased := g.table.unaliased_type(no_generic) return Type{ typ: no_generic sym: no_generic_sym - unaliased: ast.idx_to_type(no_generic_sym.parent_idx) - unaliased_sym: g.table.sym(ast.idx_to_type(no_generic_sym.parent_idx)) + unaliased: no_generic_unaliased + unaliased_sym: g.table.sym(no_generic_unaliased) + } +} + +fn (mut g JsGen) unwrap_sum_type(typ ast.Type) []Type { + mut types := []Type{} + sym := g.table.sym(typ) + if sym.info is ast.SumType { + for v in sym.info.variants { + types << g.unwrap_sum_type(v) + } + } else { + types << g.unwrap(typ) } + return arrays.distinct(types) } -- 2.39.5