Skip to content

Commit

Permalink
ast, cgen: fix generic closures with different generic types (fix vla…
Browse files Browse the repository at this point in the history
  • Loading branch information
yuyi98 authored and l1mey112 committed Jun 7, 2023
1 parent 587b4db commit 2cedff2
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 11 deletions.
6 changes: 5 additions & 1 deletion cmd/tools/vast/vast.v
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
2 changes: 1 addition & 1 deletion vlib/v/ast/ast.v
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
22 changes: 15 additions & 7 deletions vlib/v/gen/c/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -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(';')
Expand Down Expand Up @@ -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) {
Expand All @@ -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}){')
Expand Down Expand Up @@ -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)
Expand Down
8 changes: 6 additions & 2 deletions vlib/v/gen/js/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
17 changes: 17 additions & 0 deletions vlib/v/tests/generics_closures_with_different_generic_types_test.v
Original file line number Diff line number Diff line change
@@ -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
}

0 comments on commit 2cedff2

Please sign in to comment.