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:
@@ -168,10 +168,43 @@ fn (mut g Gen) struct_init(node ast.StructInit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if field.name in inited_fields {
|
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 {
|
if sfield.typ == 0 {
|
||||||
continue
|
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)
|
g.struct_init_field(sfield, sym.language)
|
||||||
if is_multiline {
|
if is_multiline {
|
||||||
g.writeln(',')
|
g.writeln(',')
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user