1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

ast, cgen: fix generic closures with different generic types (fix #17829) (#17834)

This commit is contained in:
yuyi 2023-03-31 23:08:42 +08:00 committed by GitHub
parent 6ff1c0a0b2
commit e1b8617c94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 44 additions and 11 deletions

View File

@ -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
}

View File

@ -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

View File

@ -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(';')
@ -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) {
@ -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}){')
@ -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)

View File

@ -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 {

View File

@ -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
}