Skip to content

Commit

Permalink
parser, checker, cgen: implement generics anon fn (#15529)
Browse files Browse the repository at this point in the history
  • Loading branch information
yuyi98 committed Aug 25, 2022
1 parent 723b3d7 commit 40c0a8c
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 3 deletions.
5 changes: 5 additions & 0 deletions vlib/v/checker/return.v
Expand Up @@ -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)
Expand Down
9 changes: 7 additions & 2 deletions vlib/v/gen/c/fn.v
Expand Up @@ -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,')
Expand Down
3 changes: 2 additions & 1 deletion vlib/v/parser/fn.v
Expand Up @@ -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 {
Expand Down Expand Up @@ -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())
Expand Down
20 changes: 20 additions & 0 deletions vlib/v/tests/generics_closure_fn_test.v
@@ -0,0 +1,20 @@
fn setter<T>(mut m map[T]int) fn (T, int) {
return fn [mut m] <T>(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
}
}

0 comments on commit 40c0a8c

Please sign in to comment.