diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 8ddf297c00..4c7823793a 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -1703,9 +1703,13 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name Struct, Interface, SumType { if sym.info.is_generic { mut nrt := '${sym.name}[' + mut t_generic_names := generic_names.clone() + if generic_names.len == sym.info.generic_types.len { + t_generic_names = sym.info.generic_types.map(t.sym(it).name) + } for i in 0 .. sym.info.generic_types.len { if ct := t.resolve_generic_to_concrete(sym.info.generic_types[i], - generic_names, concrete_types) + t_generic_names, concrete_types) { gts := t.sym(ct) nrt += gts.name @@ -1834,10 +1838,14 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr if !ts.info.is_generic { return typ } + mut t_generic_names := generic_names.clone() + if generic_names.len == ts.info.generic_types.len { + t_generic_names = ts.info.generic_types.map(t.sym(it).name) + } nrt = '${ts.name}[' c_nrt = '${ts.cname}_T_' for i in 0 .. ts.info.generic_types.len { - if ct := t.resolve_generic_to_concrete(ts.info.generic_types[i], generic_names, + if ct := t.resolve_generic_to_concrete(ts.info.generic_types[i], t_generic_names, concrete_types) { gts := t.sym(ct) @@ -1860,10 +1868,10 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr if fields[i].typ.has_flag(.generic) { sym := t.sym(fields[i].typ) if sym.kind == .struct_ && fields[i].typ.idx() != typ.idx() { - fields[i].typ = t.unwrap_generic_type(fields[i].typ, generic_names, + fields[i].typ = t.unwrap_generic_type(fields[i].typ, t_generic_names, concrete_types) } else { - if t_typ := t.resolve_generic_to_concrete(fields[i].typ, generic_names, + if t_typ := t.resolve_generic_to_concrete(fields[i].typ, t_generic_names, concrete_types) { fields[i].typ = t_typ @@ -1874,7 +1882,7 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr // update concrete types for i in 0 .. ts.info.generic_types.len { if t_typ := t.resolve_generic_to_concrete(ts.info.generic_types[i], - generic_names, concrete_types) + t_generic_names, concrete_types) { final_concrete_types << t_typ } @@ -2005,48 +2013,6 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr return typ } -// Foo[U]{ bar: U } to Foo[T]{ bar: T } -pub fn (mut t Table) replace_generic_type(typ Type, generic_types []Type) { - mut ts := t.sym(typ) - match mut ts.info { - Array { - mut elem_type := ts.info.elem_type - mut elem_sym := t.sym(elem_type) - mut dims := 1 - for mut elem_sym.info is Array { - elem_type = elem_sym.info.elem_type - elem_sym = t.sym(elem_type) - dims++ - } - t.replace_generic_type(elem_type, generic_types) - } - ArrayFixed { - t.replace_generic_type(ts.info.elem_type, generic_types) - } - Chan { - t.replace_generic_type(ts.info.elem_type, generic_types) - } - Map { - t.replace_generic_type(ts.info.key_type, generic_types) - t.replace_generic_type(ts.info.value_type, generic_types) - } - Struct, Interface, SumType { - generic_names := ts.info.generic_types.map(t.sym(it).name) - for i in 0 .. ts.info.fields.len { - if ts.info.fields[i].typ.has_flag(.generic) { - if t_typ := t.resolve_generic_to_concrete(ts.info.fields[i].typ, generic_names, - generic_types) - { - ts.info.fields[i].typ = t_typ - } - } - } - ts.info.generic_types = generic_types - } - else {} - } -} - // generic struct instantiations to concrete types pub fn (mut t Table) generic_insts_to_concrete() { for mut sym in t.type_symbols { diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index c86af5079f..24d6917fee 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -131,7 +131,10 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) { c.error('fixed array cannot be returned by function', node.return_type_pos) } // Ensure each generic type of the parameter was declared in the function's definition - if node.return_type.has_flag(.generic) { + // TODO: fix inconsistent return_type type case + if node.return_type.has_flag(.generic) && (return_sym.kind == .any + || (return_sym.kind == .array + && c.table.sym((return_sym.info as ast.Array).elem_type).kind == .any)) { generic_names := c.table.generic_type_names(node.return_type) for name in generic_names { if name !in node.generic_names { diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index 856656c7b8..e1c6bb59e7 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -286,10 +286,6 @@ fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type { c.error('a non generic struct `${node.typ_str}` used like a generic struct', node.name_pos) } - if node.generic_types.len > 0 && struct_sym.info.generic_types.len == node.generic_types.len - && struct_sym.info.generic_types != node.generic_types { - c.table.replace_generic_type(node.typ, node.generic_types) - } } else if struct_sym.info is ast.Alias { parent_sym := c.table.sym(struct_sym.info.parent_type) // e.g. ´x := MyMapAlias{}´, should be a cast to alias type ´x := MyMapAlias(map[...]...)´ diff --git a/vlib/v/tests/generics_struct_init_with_inconsistent_generic_types_test.v b/vlib/v/tests/generics_struct_init_with_inconsistent_generic_types_1_test.v similarity index 100% rename from vlib/v/tests/generics_struct_init_with_inconsistent_generic_types_test.v rename to vlib/v/tests/generics_struct_init_with_inconsistent_generic_types_1_test.v diff --git a/vlib/v/tests/generics_struct_init_with_inconsistent_generic_types_2_test.v b/vlib/v/tests/generics_struct_init_with_inconsistent_generic_types_2_test.v new file mode 100644 index 0000000000..98ad453fcd --- /dev/null +++ b/vlib/v/tests/generics_struct_init_with_inconsistent_generic_types_2_test.v @@ -0,0 +1,28 @@ +struct Tuple[A, B] { + a A + b B +} + +// map to array of key-value tuples +fn map_to_array[K, V](m map[K]V) []Tuple[K, V] { + mut r := []Tuple[K, V]{cap: m.len} + for k, v in m { + r << Tuple[K, V]{k, v} + } + return r +} + +fn test_generics_struct_init_with_inconsistent_generic_types() { + x := { + 'one': 1 + 'two': 2 + } + println(x) + arr := map_to_array(x) + println(arr) + assert arr.len == 2 + assert arr[0].a == 'one' + assert arr[0].b == 1 + assert arr[1].a == 'two' + assert arr[1].b == 2 +}