1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

cgen: fix generic struct init with inconsistent generic optional types (#16766)

This commit is contained in:
yuyi 2022-12-25 18:06:13 +08:00 committed by GitHub
parent 21d6bd930e
commit 64ed007f94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 128 additions and 1 deletions

View File

@ -168,10 +168,43 @@ fn (mut g Gen) struct_init(node ast.StructInit) {
}
}
if field.name in inited_fields {
sfield := node.fields[inited_fields[field.name]]
mut sfield := node.fields[inited_fields[field.name]]
if sfield.typ == 0 {
continue
}
if sfield.expected_type.has_flag(.generic) && g.cur_fn != unsafe { nil } {
mut mut_table := unsafe { &ast.Table(g.table) }
mut t_generic_names := g.table.cur_fn.generic_names.clone()
mut t_concrete_types := g.cur_concrete_types.clone()
ts := g.table.sym(node.typ)
if ts.generic_types.len > 0 && ts.generic_types.len == info.generic_types.len
&& ts.generic_types != info.generic_types {
t_generic_names = info.generic_types.map(g.table.sym(it).name)
t_concrete_types = []
for t_typ in ts.generic_types {
if !t_typ.has_flag(.generic) {
t_concrete_types << t_typ
} else if g.table.sym(t_typ).kind == .any {
tname := g.table.sym(t_typ).name
index := g.table.cur_fn.generic_names.index(tname)
if index >= 0 && index < g.cur_concrete_types.len {
t_concrete_types << g.cur_concrete_types[index]
}
} else {
if tt := mut_table.resolve_generic_to_concrete(t_typ,
g.table.cur_fn.generic_names, g.cur_concrete_types)
{
t_concrete_types << tt
}
}
}
}
if tt := mut_table.resolve_generic_to_concrete(sfield.expected_type,
t_generic_names, t_concrete_types)
{
sfield.expected_type = tt
}
}
g.struct_init_field(sfield, sym.language)
if is_multiline {
g.writeln(',')

View File

@ -0,0 +1,94 @@
struct Tuple2[A, B] {
a ?A // Option
b ?B // Option
}
// map to array of Tuple2[int, Tuple2[key, value]] tuples
fn map_to_array_int_kv[K, V](m map[K]V) []Tuple2[int, Tuple2[K, V]] {
mut r := []Tuple2[int, Tuple2[K, V]]{cap: m.len}
mut i := 0
for k, v in m {
r << Tuple2[int, Tuple2[K, V]]{i, Tuple2[K, V]{k, v}}
i += 1
}
return r
}
// map to array of Tuple2[int, Tuple2[Tuple2[key, value], Tuple2[value, key]]] tuples
fn map_to_array_int_kv_vk[K, V](m map[K]V) []Tuple2[int, Tuple2[Tuple2[K, V], Tuple2[V, K]]] {
mut r := []Tuple2[int, Tuple2[Tuple2[K, V], Tuple2[V, K]]]{cap: m.len}
mut i := 0
for k, v in m {
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}}}
i += 1
}
return r
}
fn test_generics_struct_init_with_inconsistent_generic_types() {
x := {
'one': 1
'two': 2
}
y := {
3: 'three'
4: 'four'
}
println(x)
rx1 := map_to_array_int_kv(x)
println(rx1)
assert rx1[0].a? == 0
assert rx1[0].b?.a? == 'one'
assert rx1[0].b?.b? == 1
assert rx1[1].a? == 1
assert rx1[1].b?.a? == 'two'
assert rx1[1].b?.b? == 2
rx2 := map_to_array_int_kv_vk(x)
println(rx2)
assert rx2[0].a? == 0
assert rx2[0].b?.a?.a? == 'one'
assert rx2[0].b?.a?.b? == 1
assert rx2[0].b?.b?.a? == 1
assert rx2[0].b?.b?.b? == 'one'
assert rx2[1].a? == 1
assert rx2[1].b?.a?.a? == 'two'
assert rx2[1].b?.a?.b? == 2
assert rx2[1].b?.b?.a? == 2
assert rx2[1].b?.b?.b? == 'two'
println(y)
ry1 := map_to_array_int_kv(y)
println(ry1)
assert ry1[0].a? == 0
assert ry1[0].b?.a? == 3
assert ry1[0].b?.b? == 'three'
assert ry1[1].a? == 1
assert ry1[1].b?.a? == 4
assert ry1[1].b?.b? == 'four'
ry2 := map_to_array_int_kv_vk(y)
println(ry2)
assert ry2[0].a? == 0
assert ry2[0].b?.a?.a? == 3
assert ry2[0].b?.a?.b? == 'three'
assert ry2[0].b?.b?.a? == 'three'
assert ry2[0].b?.b?.b? == 3
assert ry2[1].a? == 1
assert ry2[1].b?.a?.a? == 4
assert ry2[1].b?.a?.b? == 'four'
assert ry2[1].b?.b?.a? == 'four'
assert ry2[1].b?.b?.b? == 4
zx1 := []Tuple2[int, Tuple2[string, int]]{}
println(typeof(zx1).name)
println(typeof(rx1).name)
zx2 := []Tuple2[int, Tuple2[Tuple2[string, int], Tuple2[int, string]]]{}
println(typeof(zx2).name)
println(typeof(rx2).name)
assert typeof(zx1).name == '[]Tuple2[int, Tuple2[string, int]]'
assert typeof(zx2).name == '[]Tuple2[int, Tuple2[Tuple2[string, int], Tuple2[int, string]]]'
assert typeof(zx1).name == typeof(rx1).name
assert typeof(zx2).name == typeof(rx2).name
}