diff --git a/cmd/tools/vast/vast.v b/cmd/tools/vast/vast.v index 28e4c642a91316..e65f0d56ec6f37 100644 --- a/cmd/tools/vast/vast.v +++ b/cmd/tools/vast/vast.v @@ -581,7 +581,11 @@ fn (t Tree) anon_fn(node ast.AnonFn) &Node { obj.add_terse('decl', t.fn_decl(node.decl)) obj.add('inherited_vars', t.array_node_arg(node.inherited_vars)) obj.add_terse('typ', t.type_node(node.typ)) - obj.add('has_gen', t.bool_node(node.has_gen)) + symbol_obj := new_object() + for key, val in node.has_gen { + symbol_obj.add_terse(key.str(), t.bool_node(val)) + } + obj.add_terse('has_gen', symbol_obj) return obj } diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 601403ca626d6f..e8498f64927bb4 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -508,7 +508,7 @@ pub mut: decl FnDecl inherited_vars []Param typ Type // the type of anonymous fn. Both .typ and .decl.name are auto generated - has_gen bool // has been generated + has_gen map[string]bool // has been generated } // function or method declaration diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index f613205e6558e8..c6645ba4eb584d 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -204,7 +204,7 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) { is_closure := node.scope.has_inherited_vars() mut cur_closure_ctx := '' if is_closure { - cur_closure_ctx = closure_ctx(node) + cur_closure_ctx = g.closure_ctx(node) // declare the struct before its implementation g.definitions.write_string(cur_closure_ctx) g.definitions.writeln(';') @@ -461,8 +461,12 @@ fn (mut g Gen) c_fn_name(node &ast.FnDecl) !string { const closure_ctx = '_V_closure_ctx' -fn closure_ctx(node ast.FnDecl) string { - return 'struct _V_${node.name}_Ctx' +fn (mut g Gen) closure_ctx(node ast.FnDecl) string { + mut fn_name := node.name + if node.generic_names.len > 0 { + fn_name = g.generic_fn_name(g.cur_concrete_types, fn_name) + } + return 'struct _V_${fn_name}_Ctx' } fn (mut g Gen) gen_anon_fn(mut node ast.AnonFn) { @@ -476,7 +480,7 @@ fn (mut g Gen) gen_anon_fn(mut node ast.AnonFn) { g.write(fn_name) return } - ctx_struct := closure_ctx(node.decl) + ctx_struct := g.closure_ctx(node.decl) // it may be possible to optimize `memdup` out if the closure never leaves current scope // TODO in case of an assignment, this should only call "__closure_set_data" and "__closure_set_function" (and free the former data) g.write('__closure_create(${fn_name}, (${ctx_struct}*) memdup_uncollectable(&(${ctx_struct}){') @@ -520,14 +524,18 @@ fn (mut g Gen) gen_anon_fn(mut node ast.AnonFn) { } fn (mut g Gen) gen_anon_fn_decl(mut node ast.AnonFn) { - if node.has_gen { + mut fn_name := node.decl.name + if node.decl.generic_names.len > 0 { + fn_name = g.generic_fn_name(g.cur_concrete_types, fn_name) + } + if node.has_gen[fn_name] { return } - node.has_gen = true + node.has_gen[fn_name] = true mut builder := strings.new_builder(256) builder.writeln('/*F*/') if node.inherited_vars.len > 0 { - ctx_struct := closure_ctx(node.decl) + ctx_struct := g.closure_ctx(node.decl) builder.writeln('${ctx_struct} {') for var in node.inherited_vars { var_sym := g.table.sym(var.typ) diff --git a/vlib/v/gen/js/fn.v b/vlib/v/gen/js/fn.v index 8434704096ae99..5e998f234aa3e9 100644 --- a/vlib/v/gen/js/fn.v +++ b/vlib/v/gen/js/fn.v @@ -766,10 +766,14 @@ fn (mut g JsGen) fn_args(args []ast.Param, is_variadic bool) { } fn (mut g JsGen) gen_anon_fn(mut fun ast.AnonFn) { - if fun.has_gen { + mut fn_name := fun.decl.name + if fun.decl.generic_names.len > 0 { + fn_name = g.generic_fn_name(g.cur_concrete_types, fn_name) + } + if fun.has_gen[fn_name] { return } - fun.has_gen = true + fun.has_gen[fn_name] = true it := fun.decl cur_fn_decl := g.fn_decl unsafe { diff --git a/vlib/v/tests/generics_closures_with_different_generic_types_test.v b/vlib/v/tests/generics_closures_with_different_generic_types_test.v new file mode 100644 index 00000000000000..c719f0eec6f0e8 --- /dev/null +++ b/vlib/v/tests/generics_closures_with_different_generic_types_test.v @@ -0,0 +1,17 @@ +fn abc[T](x T) fn (p T) T { + return fn [x] [T](p T) T { + return p * x + } +} + +fn test_generic_closures_with_different_generic_types() { + f := abc[int](12345) + a := f(2) + dump(a) + assert a == 24690 + + g := abc[u8](5) + b := g(2) + dump(b) + assert b == 10 +}