From 2643d6645fe7c9e05aa0a4bbd733ddc83500500e Mon Sep 17 00:00:00 2001 From: yuyi Date: Tue, 14 Mar 2023 19:24:52 +0800 Subject: [PATCH] ast, parser, cgen: fix generic struct init with inconsistent generic types (#17639) --- vlib/v/ast/table.v | 9 ++++++++- vlib/v/ast/types.v | 1 + vlib/v/checker/check_types.v | 6 +++++- vlib/v/gen/c/cgen.v | 2 +- vlib/v/parser/parse_type.v | 1 + ...t_init_with_inconsistent_generic_types_7_test.v | 14 ++++++++++++++ 6 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 vlib/v/tests/generics_struct_init_with_inconsistent_generic_types_7_test.v diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index ce50cc2feb..07edfec0f5 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -1714,6 +1714,7 @@ 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 rnrt := '${sym.rname}[' mut t_generic_names := generic_names.clone() mut t_concrete_types := concrete_types.clone() if sym.generic_types.len > 0 && sym.generic_types.len == sym.info.generic_types.len @@ -1744,17 +1745,23 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name { gts := t.sym(ct) nrt += gts.name + rnrt += gts.name if i != sym.info.generic_types.len - 1 { nrt += ', ' + rnrt += ', ' } } else { return none } } nrt += ']' + rnrt += ']' mut idx := t.type_idxs[nrt] if idx == 0 { - idx = t.add_placeholder_type(nrt, .v) + idx = t.type_idxs[rnrt] + if idx == 0 { + idx = t.add_placeholder_type(nrt, .v) + } } return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic) } diff --git a/vlib/v/ast/types.v b/vlib/v/ast/types.v index d031e1c7c9..1fdcb967e7 100644 --- a/vlib/v/ast/types.v +++ b/vlib/v/ast/types.v @@ -94,6 +94,7 @@ pub mut: kind Kind name string // the internal & source name of the type, i.e. `[5]int`. cname string // the name with no dots for use in the generated C code + rname string // the raw name methods []Fn generic_types []Type mod string diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index a555f30ffd..01a979f011 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -983,7 +983,11 @@ fn (mut c Checker) infer_fn_generic_types(func ast.Fn, mut node ast.CallExpr) { mut concrete_types := []ast.Type{} match arg_sym.info { ast.Struct, ast.Interface, ast.SumType { - generic_types = arg_sym.info.generic_types.clone() + if param_type_sym.generic_types.len > 0 { + generic_types = param_type_sym.generic_types.clone() + } else { + generic_types = arg_sym.info.generic_types.clone() + } concrete_types = arg_sym.info.concrete_types.clone() } else {} diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index dbaaaa1d9f..cf118456fc 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -1325,7 +1325,7 @@ fn (mut g Gen) cc_type(typ ast.Type, is_prefix_struct bool) string { // TODO: this needs to be removed; cgen shouldn't resolve generic types (job of checker) match sym.info { ast.Struct, ast.Interface, ast.SumType { - if sym.info.is_generic { + if sym.info.is_generic && sym.generic_types.len == 0 { mut sgtyps := '_T' for gt in sym.info.generic_types { gts := g.table.sym(g.unwrap_generic(gt)) diff --git a/vlib/v/parser/parse_type.v b/vlib/v/parser/parse_type.v index 62e641965f..5ed5da8ac5 100644 --- a/vlib/v/parser/parse_type.v +++ b/vlib/v/parser/parse_type.v @@ -682,6 +682,7 @@ pub fn (mut p Parser) find_type_or_add_placeholder(name string, language ast.Lan idx = p.table.register_sym(ast.TypeSymbol{ ...sym name: sym_name + rname: sym.name generic_types: p.struct_init_generic_types.clone() }) } diff --git a/vlib/v/tests/generics_struct_init_with_inconsistent_generic_types_7_test.v b/vlib/v/tests/generics_struct_init_with_inconsistent_generic_types_7_test.v new file mode 100644 index 0000000000..10654d6a8e --- /dev/null +++ b/vlib/v/tests/generics_struct_init_with_inconsistent_generic_types_7_test.v @@ -0,0 +1,14 @@ +struct MyData[T] { +} + +fn myfunc[U](a MyData[U]) string { + println(a) + return '${a}' +} + +fn test_generics_struct_init_with_inconsistent_generic_types() { + d1 := MyData[int]{} + r1 := myfunc(d1) + println(r1) + assert r1 == 'MyData[int]{}' +}