From 40c0a8cbaf829ed36b5acaeb08b5d088e205353f Mon Sep 17 00:00:00 2001 From: yuyi Date: Thu, 25 Aug 2022 19:12:56 +0800 Subject: [PATCH] parser, checker, cgen: implement generics anon fn (#15529) --- vlib/v/checker/return.v | 5 +++++ vlib/v/gen/c/fn.v | 9 +++++++-- vlib/v/parser/fn.v | 3 ++- vlib/v/tests/generics_closure_fn_test.v | 20 ++++++++++++++++++++ 4 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 vlib/v/tests/generics_closure_fn_test.v diff --git a/vlib/v/checker/return.v b/vlib/v/checker/return.v index d0e983cf38..cd7f27246e 100644 --- a/vlib/v/checker/return.v +++ b/vlib/v/checker/return.v @@ -122,6 +122,11 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) { } continue } + if got_typ_sym.kind == .function && exp_typ_sym.kind == .function { + if (got_typ_sym.info as ast.FnType).is_anon { + continue + } + } pos := node.exprs[expr_idxs[i]].pos() c.error('cannot use `$got_typ_sym.name` as type `${c.table.type_to_str(exp_type)}` in return argument', pos) diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index fb2f154130..899524e2e8 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -445,14 +445,19 @@ fn closure_ctx(node ast.FnDecl) string { fn (mut g Gen) gen_anon_fn(mut node ast.AnonFn) { g.gen_anon_fn_decl(mut node) + 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, true) + } + if !node.decl.scope.has_inherited_vars() { - g.write(node.decl.name) + g.write(fn_name) return } ctx_struct := 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($node.decl.name, ($ctx_struct*) memdup_uncollectable(&($ctx_struct){') + g.write('__closure_create($fn_name, ($ctx_struct*) memdup_uncollectable(&($ctx_struct){') g.indent++ for var in node.inherited_vars { g.writeln('.$var.name = $var.name,') diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 3c2b407e13..f01696f6dd 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -677,7 +677,7 @@ fn (mut p Parser) anon_fn() ast.AnonFn { } p.scope.detached_from_parent = true inherited_vars := if p.tok.kind == .lsbr { p.closure_vars() } else { []ast.Param{} } - // TODO generics + _, generic_names := p.parse_generic_types() args, _, is_variadic := p.fn_args() for arg in args { if arg.name.len == 0 && p.table.sym(arg.typ).kind != .placeholder { @@ -759,6 +759,7 @@ fn (mut p Parser) anon_fn() ast.AnonFn { params: args is_variadic: is_variadic is_method: false + generic_names: generic_names is_anon: true no_body: no_body pos: pos.extend(p.prev_tok.pos()) diff --git a/vlib/v/tests/generics_closure_fn_test.v b/vlib/v/tests/generics_closure_fn_test.v new file mode 100644 index 0000000000..e9905ab095 --- /dev/null +++ b/vlib/v/tests/generics_closure_fn_test.v @@ -0,0 +1,20 @@ +fn setter(mut m map[T]int) fn (T, int) { + return fn [mut m] (x T, k int) { + m[x] = k + } +} + +fn test_generics_closure_fn() { + mut m := { + f32(0.1): 1 + } + + f := setter(mut m) + f(0.2, 2) + + println(m) + assert m == { + f32(0.1): 1 + 0.2: 2 + } +}