Skip to content

Commit e1b8617

Browse files
authored
ast, cgen: fix generic closures with different generic types (fix #17829) (#17834)
1 parent 6ff1c0a commit e1b8617

File tree

5 files changed

+44
-11
lines changed

5 files changed

+44
-11
lines changed

cmd/tools/vast/vast.v

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,11 @@ fn (t Tree) anon_fn(node ast.AnonFn) &Node {
581581
obj.add_terse('decl', t.fn_decl(node.decl))
582582
obj.add('inherited_vars', t.array_node_arg(node.inherited_vars))
583583
obj.add_terse('typ', t.type_node(node.typ))
584-
obj.add('has_gen', t.bool_node(node.has_gen))
584+
symbol_obj := new_object()
585+
for key, val in node.has_gen {
586+
symbol_obj.add_terse(key.str(), t.bool_node(val))
587+
}
588+
obj.add_terse('has_gen', symbol_obj)
585589
return obj
586590
}
587591

vlib/v/ast/ast.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,7 @@ pub mut:
508508
decl FnDecl
509509
inherited_vars []Param
510510
typ Type // the type of anonymous fn. Both .typ and .decl.name are auto generated
511-
has_gen bool // has been generated
511+
has_gen map[string]bool // has been generated
512512
}
513513

514514
// function or method declaration

vlib/v/gen/c/fn.v

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
204204
is_closure := node.scope.has_inherited_vars()
205205
mut cur_closure_ctx := ''
206206
if is_closure {
207-
cur_closure_ctx = closure_ctx(node)
207+
cur_closure_ctx = g.closure_ctx(node)
208208
// declare the struct before its implementation
209209
g.definitions.write_string(cur_closure_ctx)
210210
g.definitions.writeln(';')
@@ -461,8 +461,12 @@ fn (mut g Gen) c_fn_name(node &ast.FnDecl) !string {
461461

462462
const closure_ctx = '_V_closure_ctx'
463463

464-
fn closure_ctx(node ast.FnDecl) string {
465-
return 'struct _V_${node.name}_Ctx'
464+
fn (mut g Gen) closure_ctx(node ast.FnDecl) string {
465+
mut fn_name := node.name
466+
if node.generic_names.len > 0 {
467+
fn_name = g.generic_fn_name(g.cur_concrete_types, fn_name)
468+
}
469+
return 'struct _V_${fn_name}_Ctx'
466470
}
467471

468472
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) {
476480
g.write(fn_name)
477481
return
478482
}
479-
ctx_struct := closure_ctx(node.decl)
483+
ctx_struct := g.closure_ctx(node.decl)
480484
// it may be possible to optimize `memdup` out if the closure never leaves current scope
481485
// TODO in case of an assignment, this should only call "__closure_set_data" and "__closure_set_function" (and free the former data)
482486
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) {
520524
}
521525

522526
fn (mut g Gen) gen_anon_fn_decl(mut node ast.AnonFn) {
523-
if node.has_gen {
527+
mut fn_name := node.decl.name
528+
if node.decl.generic_names.len > 0 {
529+
fn_name = g.generic_fn_name(g.cur_concrete_types, fn_name)
530+
}
531+
if node.has_gen[fn_name] {
524532
return
525533
}
526-
node.has_gen = true
534+
node.has_gen[fn_name] = true
527535
mut builder := strings.new_builder(256)
528536
builder.writeln('/*F*/')
529537
if node.inherited_vars.len > 0 {
530-
ctx_struct := closure_ctx(node.decl)
538+
ctx_struct := g.closure_ctx(node.decl)
531539
builder.writeln('${ctx_struct} {')
532540
for var in node.inherited_vars {
533541
var_sym := g.table.sym(var.typ)

vlib/v/gen/js/fn.v

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -766,10 +766,14 @@ fn (mut g JsGen) fn_args(args []ast.Param, is_variadic bool) {
766766
}
767767

768768
fn (mut g JsGen) gen_anon_fn(mut fun ast.AnonFn) {
769-
if fun.has_gen {
769+
mut fn_name := fun.decl.name
770+
if fun.decl.generic_names.len > 0 {
771+
fn_name = g.generic_fn_name(g.cur_concrete_types, fn_name)
772+
}
773+
if fun.has_gen[fn_name] {
770774
return
771775
}
772-
fun.has_gen = true
776+
fun.has_gen[fn_name] = true
773777
it := fun.decl
774778
cur_fn_decl := g.fn_decl
775779
unsafe {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
fn abc[T](x T) fn (p T) T {
2+
return fn [x] [T](p T) T {
3+
return p * x
4+
}
5+
}
6+
7+
fn test_generic_closures_with_different_generic_types() {
8+
f := abc[int](12345)
9+
a := f(2)
10+
dump(a)
11+
assert a == 24690
12+
13+
g := abc[u8](5)
14+
b := g(2)
15+
dump(b)
16+
assert b == 10
17+
}

0 commit comments

Comments
 (0)