From 64ed007f943b8a188fc59622a73d083436477e38 Mon Sep 17 00:00:00 2001 From: yuyi Date: Sun, 25 Dec 2022 18:06:13 +0800 Subject: [PATCH] cgen: fix generic struct init with inconsistent generic optional types (#16766) --- vlib/v/gen/c/struct.v | 35 ++++++- ...t_with_inconsistent_generic_types_6_test.v | 94 +++++++++++++++++++ 2 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 vlib/v/tests/generics_struct_init_with_inconsistent_generic_types_6_test.v diff --git a/vlib/v/gen/c/struct.v b/vlib/v/gen/c/struct.v index 4589fed59f..57aa61ad87 100644 --- a/vlib/v/gen/c/struct.v +++ b/vlib/v/gen/c/struct.v @@ -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(',') diff --git a/vlib/v/tests/generics_struct_init_with_inconsistent_generic_types_6_test.v b/vlib/v/tests/generics_struct_init_with_inconsistent_generic_types_6_test.v new file mode 100644 index 0000000000..b837f0058d --- /dev/null +++ b/vlib/v/tests/generics_struct_init_with_inconsistent_generic_types_6_test.v @@ -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 +}