diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 9720be1f77..c54a6580b4 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -300,8 +300,9 @@ pub: // anonymous function pub struct AnonFn { pub mut: - decl FnDecl - typ table.Type // the type of anonymous fn. Both .typ and .decl.name are auto generated + decl FnDecl + typ table.Type // the type of anonymous fn. Both .typ and .decl.name are auto generated + has_gen bool // has been generated } // function or method declaration @@ -360,9 +361,8 @@ pub: // function or method call expr pub struct CallExpr { pub: - pos token.Position - left Expr // `user` in `user.register()` - mod string + pos token.Position + mod string pub mut: name string // left.name() is_method bool @@ -371,6 +371,7 @@ pub mut: expected_arg_types []table.Type language table.Language or_block OrExpr + left Expr // `user` in `user.register()` left_type table.Type // type of `user` receiver_type table.Type // User return_type table.Type diff --git a/vlib/v/gen/c/array.v b/vlib/v/gen/c/array.v index 345ad4a265..483f683e46 100644 --- a/vlib/v/gen/c/array.v +++ b/vlib/v/gen/c/array.v @@ -150,11 +150,11 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) { g.writeln('for (int $i = 0; $i < ${tmp}_len; ++$i) {') g.writeln('\t$inp_elem_type it = (($inp_elem_type*) ${tmp}_orig.data)[$i];') mut is_embed_map_filter := false - expr := node.args[0].expr - match expr { + mut expr := node.args[0].expr + match mut expr { ast.AnonFn { g.write('\t$ret_elem_type ti = ') - g.gen_anon_fn_decl(expr) + g.gen_anon_fn_decl(mut expr) g.write('${expr.decl.name}(it)') } ast.Ident { @@ -324,11 +324,11 @@ fn (mut g Gen) gen_array_filter(node ast.CallExpr) { g.writeln('for (int $i = 0; $i < ${tmp}_len; ++$i) {') g.writeln('\t$elem_type_str it = (($elem_type_str*) ${tmp}_orig.data)[$i];') mut is_embed_map_filter := false - expr := node.args[0].expr - match expr { + mut expr := node.args[0].expr + match mut expr { ast.AnonFn { g.write('\tif (') - g.gen_anon_fn_decl(expr) + g.gen_anon_fn_decl(mut expr) g.write('${expr.decl.name}(it)') } ast.Ident { diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 0c49cbb0df..90dcd93975 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -2502,12 +2502,15 @@ fn (mut g Gen) autofree_var_call(free_fn_name string, v ast.Var) { } } -fn (mut g Gen) gen_anon_fn_decl(it ast.AnonFn) { - pos := g.out.len - g.stmt(it.decl) - fn_body := g.out.after(pos) - g.out.go_back(fn_body.len) - g.anon_fn_definitions << fn_body +fn (mut g Gen) gen_anon_fn_decl(mut node ast.AnonFn) { + if !node.has_gen { + pos := g.out.len + g.stmt(node.decl) + fn_body := g.out.after(pos) + g.out.go_back(fn_body.len) + g.anon_fn_definitions << fn_body + node.has_gen = true + } } fn (mut g Gen) map_fn_ptrs(key_typ table.TypeSymbol) (string, string, string, string) { @@ -2560,10 +2563,10 @@ fn (mut g Gen) map_fn_ptrs(key_typ table.TypeSymbol) (string, string, string, st fn (mut g Gen) expr(node ast.Expr) { // println('cgen expr() line_nr=$node.pos.line_nr') // NB: please keep the type names in the match here in alphabetical order: - match node { + match mut node { ast.AnonFn { // TODO: dont fiddle with buffers - g.gen_anon_fn_decl(node) + g.gen_anon_fn_decl(mut node) fsym := g.table.get_type_symbol(node.typ) g.write(fsym.name) } @@ -5877,7 +5880,7 @@ fn (mut g Gen) go_expr(node ast.GoExpr) { fn (mut g Gen) go_stmt(node ast.GoStmt, joinable bool) string { mut handle := '' tmp := g.new_tmp_var() - expr := node.call_expr + mut expr := node.call_expr mut name := expr.name // util.no_dots(expr.name) // TODO: fn call is duplicated. merge with fn_call(). for i, generic_type in expr.generic_types { @@ -5893,8 +5896,8 @@ fn (mut g Gen) go_stmt(node ast.GoStmt, joinable bool) string { if expr.is_method { receiver_sym := g.table.get_type_symbol(expr.receiver_type) name = receiver_sym.name + '_' + name - } else if expr.left is ast.AnonFn { - g.gen_anon_fn_decl(expr.left) + } else if mut expr.left is ast.AnonFn { + g.gen_anon_fn_decl(mut expr.left) fsym := g.table.get_type_symbol(expr.left.typ) name = fsym.name } diff --git a/vlib/v/tests/anon_fn_redefinition_test.v b/vlib/v/tests/anon_fn_redefinition_test.v new file mode 100644 index 0000000000..b4f6864269 --- /dev/null +++ b/vlib/v/tests/anon_fn_redefinition_test.v @@ -0,0 +1,24 @@ +const default_logger = Example{} + +struct Example { + structs []Another = [Another{}] +} + +pub struct Another { + function fn (string) = fn (value string) { + println('$value') + } +} + +pub fn (e Example) useless() string { + return 'ok' +} + +fn test_anon_fn_redefinition() { + e1 := Example{} + assert e1.useless() == 'ok' + e2 := Example{} + assert e2.useless() == 'ok' + e3 := Example{} + assert e3.useless() == 'ok' +}