Skip to content

Commit 64ed007

Browse files
authored
cgen: fix generic struct init with inconsistent generic optional types (#16766)
1 parent 21d6bd9 commit 64ed007

File tree

2 files changed

+128
-1
lines changed

2 files changed

+128
-1
lines changed

vlib/v/gen/c/struct.v

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,43 @@ fn (mut g Gen) struct_init(node ast.StructInit) {
168168
}
169169
}
170170
if field.name in inited_fields {
171-
sfield := node.fields[inited_fields[field.name]]
171+
mut sfield := node.fields[inited_fields[field.name]]
172172
if sfield.typ == 0 {
173173
continue
174174
}
175+
if sfield.expected_type.has_flag(.generic) && g.cur_fn != unsafe { nil } {
176+
mut mut_table := unsafe { &ast.Table(g.table) }
177+
mut t_generic_names := g.table.cur_fn.generic_names.clone()
178+
mut t_concrete_types := g.cur_concrete_types.clone()
179+
ts := g.table.sym(node.typ)
180+
if ts.generic_types.len > 0 && ts.generic_types.len == info.generic_types.len
181+
&& ts.generic_types != info.generic_types {
182+
t_generic_names = info.generic_types.map(g.table.sym(it).name)
183+
t_concrete_types = []
184+
for t_typ in ts.generic_types {
185+
if !t_typ.has_flag(.generic) {
186+
t_concrete_types << t_typ
187+
} else if g.table.sym(t_typ).kind == .any {
188+
tname := g.table.sym(t_typ).name
189+
index := g.table.cur_fn.generic_names.index(tname)
190+
if index >= 0 && index < g.cur_concrete_types.len {
191+
t_concrete_types << g.cur_concrete_types[index]
192+
}
193+
} else {
194+
if tt := mut_table.resolve_generic_to_concrete(t_typ,
195+
g.table.cur_fn.generic_names, g.cur_concrete_types)
196+
{
197+
t_concrete_types << tt
198+
}
199+
}
200+
}
201+
}
202+
if tt := mut_table.resolve_generic_to_concrete(sfield.expected_type,
203+
t_generic_names, t_concrete_types)
204+
{
205+
sfield.expected_type = tt
206+
}
207+
}
175208
g.struct_init_field(sfield, sym.language)
176209
if is_multiline {
177210
g.writeln(',')
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
struct Tuple2[A, B] {
2+
a ?A // Option
3+
b ?B // Option
4+
}
5+
6+
// map to array of Tuple2[int, Tuple2[key, value]] tuples
7+
fn map_to_array_int_kv[K, V](m map[K]V) []Tuple2[int, Tuple2[K, V]] {
8+
mut r := []Tuple2[int, Tuple2[K, V]]{cap: m.len}
9+
mut i := 0
10+
for k, v in m {
11+
r << Tuple2[int, Tuple2[K, V]]{i, Tuple2[K, V]{k, v}}
12+
i += 1
13+
}
14+
return r
15+
}
16+
17+
// map to array of Tuple2[int, Tuple2[Tuple2[key, value], Tuple2[value, key]]] tuples
18+
fn map_to_array_int_kv_vk[K, V](m map[K]V) []Tuple2[int, Tuple2[Tuple2[K, V], Tuple2[V, K]]] {
19+
mut r := []Tuple2[int, Tuple2[Tuple2[K, V], Tuple2[V, K]]]{cap: m.len}
20+
mut i := 0
21+
for k, v in m {
22+
r << Tuple2[int, Tuple2[Tuple2[K, V], Tuple2[V, K]]]{i, Tuple2[Tuple2[K, V], Tuple2[V, K]]{Tuple2[K, V]{k, v}, Tuple2[V, K]{v, k}}}
23+
i += 1
24+
}
25+
return r
26+
}
27+
28+
fn test_generics_struct_init_with_inconsistent_generic_types() {
29+
x := {
30+
'one': 1
31+
'two': 2
32+
}
33+
y := {
34+
3: 'three'
35+
4: 'four'
36+
}
37+
38+
println(x)
39+
rx1 := map_to_array_int_kv(x)
40+
println(rx1)
41+
assert rx1[0].a? == 0
42+
assert rx1[0].b?.a? == 'one'
43+
assert rx1[0].b?.b? == 1
44+
assert rx1[1].a? == 1
45+
assert rx1[1].b?.a? == 'two'
46+
assert rx1[1].b?.b? == 2
47+
48+
rx2 := map_to_array_int_kv_vk(x)
49+
println(rx2)
50+
assert rx2[0].a? == 0
51+
assert rx2[0].b?.a?.a? == 'one'
52+
assert rx2[0].b?.a?.b? == 1
53+
assert rx2[0].b?.b?.a? == 1
54+
assert rx2[0].b?.b?.b? == 'one'
55+
assert rx2[1].a? == 1
56+
assert rx2[1].b?.a?.a? == 'two'
57+
assert rx2[1].b?.a?.b? == 2
58+
assert rx2[1].b?.b?.a? == 2
59+
assert rx2[1].b?.b?.b? == 'two'
60+
61+
println(y)
62+
ry1 := map_to_array_int_kv(y)
63+
println(ry1)
64+
assert ry1[0].a? == 0
65+
assert ry1[0].b?.a? == 3
66+
assert ry1[0].b?.b? == 'three'
67+
assert ry1[1].a? == 1
68+
assert ry1[1].b?.a? == 4
69+
assert ry1[1].b?.b? == 'four'
70+
71+
ry2 := map_to_array_int_kv_vk(y)
72+
println(ry2)
73+
assert ry2[0].a? == 0
74+
assert ry2[0].b?.a?.a? == 3
75+
assert ry2[0].b?.a?.b? == 'three'
76+
assert ry2[0].b?.b?.a? == 'three'
77+
assert ry2[0].b?.b?.b? == 3
78+
assert ry2[1].a? == 1
79+
assert ry2[1].b?.a?.a? == 4
80+
assert ry2[1].b?.a?.b? == 'four'
81+
assert ry2[1].b?.b?.a? == 'four'
82+
assert ry2[1].b?.b?.b? == 4
83+
84+
zx1 := []Tuple2[int, Tuple2[string, int]]{}
85+
println(typeof(zx1).name)
86+
println(typeof(rx1).name)
87+
zx2 := []Tuple2[int, Tuple2[Tuple2[string, int], Tuple2[int, string]]]{}
88+
println(typeof(zx2).name)
89+
println(typeof(rx2).name)
90+
assert typeof(zx1).name == '[]Tuple2[int, Tuple2[string, int]]'
91+
assert typeof(zx2).name == '[]Tuple2[int, Tuple2[Tuple2[string, int], Tuple2[int, string]]]'
92+
assert typeof(zx1).name == typeof(rx1).name
93+
assert typeof(zx2).name == typeof(rx2).name
94+
}

0 commit comments

Comments
 (0)