From 3736e51e627c5e272c78236ac44261a7b1d5ce6d Mon Sep 17 00:00:00 2001 From: yuyi Date: Mon, 7 Oct 2024 16:05:31 +0800 Subject: [PATCH] ast, parser: fix generic fn type with defferent generic type call (#22431) --- vlib/v/ast/table.v | 11 +---- vlib/v/parser/parse_type.v | 42 +++++++++++++++++++ ...fn_type_with_different_generic_type_test.v | 15 +++++++ 3 files changed, 58 insertions(+), 10 deletions(-) create mode 100644 vlib/v/tests/generics/generic_fn_type_with_different_generic_type_test.v diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 7481543176a0aa..40da2e0dc300c5 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -1828,16 +1828,7 @@ pub fn (mut t Table) generic_type_names(generic_type Type) []string { names << t.generic_type_names(sym.info.elem_type) } FnType { - mut func := sym.info.func - if func.return_type.has_flag(.generic) { - names << t.generic_type_names(func.return_type) - } - func.params = func.params.clone() - for mut param in func.params { - if param.typ.has_flag(.generic) { - generic_names_push_with_filter(mut names, t.generic_type_names(param.typ)) - } - } + names << sym.info.func.generic_names } MultiReturn { for ret_type in sym.info.types { diff --git a/vlib/v/parser/parse_type.v b/vlib/v/parser/parse_type.v index e2a1c8eab15448..0c748eb236e713 100644 --- a/vlib/v/parser/parse_type.v +++ b/vlib/v/parser/parse_type.v @@ -841,6 +841,48 @@ fn (mut p Parser) find_type_or_add_placeholder(name string, language ast.Languag typ = ast.new_type(idx) } } + ast.FnType { + if p.struct_init_generic_types.len > 0 && sym.info.func.generic_names.len > 0 { + generic_names := p.types_to_names(p.struct_init_generic_types, p.tok.pos(), + 'struct_init_generic_types') or { return ast.no_type } + if generic_names != sym.info.func.generic_names { + mut sym_name := sym.name + '<' + for i, gt in generic_names { + sym_name += gt + if i != generic_names.len - 1 { + sym_name += ',' + } + } + sym_name += '>' + existing_idx := p.table.type_idxs[sym_name] + if existing_idx > 0 { + idx = existing_idx + } else { + mut func := sym.info.func + func.name = sym_name + func.generic_names = generic_names.clone() + if func.return_type.has_flag(.generic) { + if to_generic_typ := p.table.resolve_generic_to_concrete(func.return_type, + sym.info.func.generic_names, p.struct_init_generic_types) + { + func.return_type = to_generic_typ + } + } + for i in 0 .. func.params.len { + if func.params[i].typ.has_flag(.generic) { + if to_generic_typ := p.table.resolve_generic_to_concrete(func.params[i].typ, + sym.info.func.generic_names, p.struct_init_generic_types) + { + func.params[i].typ = to_generic_typ + } + } + } + idx = p.table.find_or_register_fn_type(func, false, false) + } + typ = ast.new_type(idx) + } + } + } else {} } return typ diff --git a/vlib/v/tests/generics/generic_fn_type_with_different_generic_type_test.v b/vlib/v/tests/generics/generic_fn_type_with_different_generic_type_test.v new file mode 100644 index 00000000000000..47a33b34557c98 --- /dev/null +++ b/vlib/v/tests/generics/generic_fn_type_with_different_generic_type_test.v @@ -0,0 +1,15 @@ +type Fn[T] = fn () T + +fn problem[X](f Fn[X]) X { + return f[X]() +} + +fn foo() int { + return 1 +} + +fn test_generic_fn_type_with_different_generic_type() { + t := problem[int](foo) + println(t) + assert t == 1 +}