Skip to content

Commit b21dbbb

Browse files
authored
jsgen: alias types are not properly resolved (fix #24486) (fix #24507) (#24514)
1 parent c72d77d commit b21dbbb

4 files changed

Lines changed: 158 additions & 12 deletions

File tree

‎vlib/v/gen/js/auto_eq_methods.v‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ module js
22

33
import v.ast
44
import strings
5+
import arrays
56

67
fn (mut g JsGen) gen_sumtype_equality_fn(left_type ast.Type) string {
78
left := g.unwrap(left_type)
@@ -19,9 +20,19 @@ fn (mut g JsGen) gen_sumtype_equality_fn(left_type ast.Type) string {
1920
fn_builder.writeln('\tlet aProto = Object.getPrototypeOf(a);')
2021
fn_builder.writeln('\tlet bProto = Object.getPrototypeOf(b);')
2122
fn_builder.writeln('\tif (aProto !== bProto) { return new bool(false); }')
23+
mut variants := []Type{}
2224
for typ in info.variants {
2325
variant := g.unwrap(typ)
24-
fn_builder.writeln('\tif (aProto == ${g.js_name(variant.sym.name)}) {')
26+
if variant.unaliased_sym.info is ast.SumType {
27+
variants << g.unwrap_sum_type(typ)
28+
} else {
29+
variants << variant
30+
}
31+
}
32+
variants = arrays.distinct(variants)
33+
for variant in variants {
34+
typ := variant.typ
35+
fn_builder.writeln('\tif (aProto == ${g.js_name(variant.unaliased_sym.name)}.prototype) {')
2536
if variant.sym.kind == .string {
2637
fn_builder.writeln('\t\treturn new bool(a.str == b.str);')
2738
} else if variant.sym.kind == .sum_type && !typ.is_ptr() {

‎vlib/v/gen/js/infix.v‎

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -337,12 +337,27 @@ fn (mut g JsGen) infix_in_not_in_op(node ast.InfixExpr) {
337337
}
338338

339339
fn (mut g JsGen) infix_is_not_is_op(node ast.InfixExpr) {
340-
g.expr(node.left)
341-
rsym := g.table.sym(g.unwrap(node.right_type).typ)
340+
rsym := g.unwrap(node.right_type).unaliased_sym
342341

343-
g.gen_deref_ptr(node.left_type)
344-
g.write(' instanceof ')
345-
g.write(g.js_name(rsym.name))
342+
if rsym.info is ast.SumType {
343+
g.write('[')
344+
variants := g.unwrap_sum_type(node.right_type)
345+
for i, v in variants {
346+
g.write(g.js_name(v.unaliased_sym.name))
347+
if i < variants.len - 1 {
348+
g.write(', ')
349+
}
350+
}
351+
g.write('].some(t => ')
352+
g.expr(node.left)
353+
g.gen_deref_ptr(node.left_type)
354+
g.write(' instanceof t.valueOf())')
355+
} else {
356+
g.expr(node.left)
357+
g.gen_deref_ptr(node.left_type)
358+
g.write(' instanceof ')
359+
g.write(g.js_name(rsym.name))
360+
}
346361
}
347362

348363
fn (mut g JsGen) infix_expr(node ast.InfixExpr) {

‎vlib/v/gen/js/tests/alias.v‎

Lines changed: 101 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,127 @@
11
type Type0 = string
22
type Type1 = int | string
33
type Type2 = string | int
4+
type Type3 = Type0 | int
5+
type Type4 = Type3 | Type1 | f32
6+
type Type5 = Type4 | bool
47

58
struct Foo {
69
field_0 Type0
710
field_1 Type1
811
field_2 Type2
12+
field_3 Type3
13+
field_4 Type4
14+
field_5 Type5
915
}
1016

11-
fn main() {
17+
fn basic_assertion() {
18+
foo := Type1('')
19+
assert foo == Type1('')
20+
}
21+
22+
fn struct_with_default_values() {
1223
foo := Foo{}
1324

14-
// checks alias types
1525
assert foo.field_0 == ''
1626

17-
// checks sum types
1827
if foo.field_1 is int {
1928
assert foo.field_1 == 0
2029
} else {
2130
assert false
2231
}
2332

24-
// checks sum types
2533
if foo.field_2 is string {
2634
assert foo.field_2 == ''
2735
} else {
2836
assert false
2937
}
38+
39+
if foo.field_3 is Type0 {
40+
assert foo.field_3 == ''
41+
assert foo.field_3 == Type0('')
42+
} else {
43+
assert false
44+
}
45+
46+
// TODO: uncomment until the C backend is improved
47+
// if foo.field_4 is Type3 {
48+
// assert foo.field_4 == Type3(Type0(''))
49+
// } else {
50+
// assert false
51+
// }
52+
53+
// TODO: uncomment until the C backend is improved
54+
// if foo.field_5 is Type4 {
55+
// assert foo.field_4 == Type4(Type3(Type0('')))
56+
// } else {
57+
// assert false
58+
// }
59+
}
60+
61+
fn struct_with_values() {
62+
// test 0
63+
f0 := Foo{
64+
field_0: 'hello'
65+
field_1: 'world'
66+
field_2: 100
67+
field_3: 200
68+
field_4: f32(3.14)
69+
field_5: true
70+
}
71+
72+
assert f0.field_0 == 'hello'
73+
74+
if f0.field_1 is string {
75+
assert f0.field_1 == 'world'
76+
} else {
77+
assert false
78+
}
79+
80+
if f0.field_2 is int {
81+
assert f0.field_2 == 100
82+
} else {
83+
assert false
84+
}
85+
86+
if f0.field_3 is int {
87+
assert f0.field_3 == 200
88+
} else {
89+
assert false
90+
}
91+
92+
if f0.field_4 is f32 {
93+
assert f0.field_4 == 3.14
94+
} else {
95+
assert false
96+
}
97+
98+
if f0.field_5 is bool {
99+
assert f0.field_5
100+
} else {
101+
assert false
102+
}
103+
104+
// test 1
105+
f1 := Foo{
106+
field_4: Type3(100)
107+
field_5: Type4(Type3(Type0('hello')))
108+
}
109+
110+
if f1.field_4 is Type3 {
111+
assert f1.field_4 == Type3(100)
112+
} else {
113+
assert false
114+
}
115+
116+
if f1.field_5 is Type4 {
117+
assert f1.field_5 == Type4(Type3(Type0('hello')))
118+
} else {
119+
assert false
120+
}
121+
}
122+
123+
fn main() {
124+
basic_assertion()
125+
struct_with_default_values()
126+
struct_with_values()
30127
}

‎vlib/v/gen/js/util.v‎

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module js
22

33
import v.ast
4+
import arrays
45

56
struct Type {
67
// typ is the original type
@@ -12,6 +13,14 @@ struct Type {
1213
unaliased_sym &ast.TypeSymbol = unsafe { nil } @[required]
1314
}
1415

16+
fn (a Type) == (b Type) bool {
17+
return a.unaliased == b.unaliased
18+
}
19+
20+
fn (a Type) < (b Type) bool {
21+
return a.unaliased_sym.name < b.unaliased_sym.name
22+
}
23+
1524
// unwrap returns the following variants of a type:
1625
// * generics unwrapped
1726
// * alias unwrapped
@@ -26,10 +35,24 @@ fn (mut g JsGen) unwrap(typ ast.Type) Type {
2635
unaliased_sym: no_generic_sym
2736
}
2837
}
38+
no_generic_unaliased := g.table.unaliased_type(no_generic)
2939
return Type{
3040
typ: no_generic
3141
sym: no_generic_sym
32-
unaliased: ast.idx_to_type(no_generic_sym.parent_idx)
33-
unaliased_sym: g.table.sym(ast.idx_to_type(no_generic_sym.parent_idx))
42+
unaliased: no_generic_unaliased
43+
unaliased_sym: g.table.sym(no_generic_unaliased)
44+
}
45+
}
46+
47+
fn (mut g JsGen) unwrap_sum_type(typ ast.Type) []Type {
48+
mut types := []Type{}
49+
sym := g.table.sym(typ)
50+
if sym.info is ast.SumType {
51+
for v in sym.info.variants {
52+
types << g.unwrap_sum_type(v)
53+
}
54+
} else {
55+
types << g.unwrap(typ)
3456
}
57+
return arrays.distinct(types)
3558
}

0 commit comments

Comments
 (0)