cgen: fix anon_fn redefinition (#8961)

pull/8968/head
yuyi 2021-02-25 19:16:35 +08:00 committed by GitHub
parent fdc60817d3
commit c762d150c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 50 additions and 22 deletions

View File

@ -300,8 +300,9 @@ pub:
// anonymous function
pub struct AnonFn {
pub mut:
decl FnDecl
typ table.Type // the type of anonymous fn. Both .typ and .decl.name are auto generated
decl FnDecl
typ table.Type // the type of anonymous fn. Both .typ and .decl.name are auto generated
has_gen bool // has been generated
}
// function or method declaration
@ -360,9 +361,8 @@ pub:
// function or method call expr
pub struct CallExpr {
pub:
pos token.Position
left Expr // `user` in `user.register()`
mod string
pos token.Position
mod string
pub mut:
name string // left.name()
is_method bool
@ -371,6 +371,7 @@ pub mut:
expected_arg_types []table.Type
language table.Language
or_block OrExpr
left Expr // `user` in `user.register()`
left_type table.Type // type of `user`
receiver_type table.Type // User
return_type table.Type

View File

@ -150,11 +150,11 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
g.writeln('for (int $i = 0; $i < ${tmp}_len; ++$i) {')
g.writeln('\t$inp_elem_type it = (($inp_elem_type*) ${tmp}_orig.data)[$i];')
mut is_embed_map_filter := false
expr := node.args[0].expr
match expr {
mut expr := node.args[0].expr
match mut expr {
ast.AnonFn {
g.write('\t$ret_elem_type ti = ')
g.gen_anon_fn_decl(expr)
g.gen_anon_fn_decl(mut expr)
g.write('${expr.decl.name}(it)')
}
ast.Ident {
@ -324,11 +324,11 @@ fn (mut g Gen) gen_array_filter(node ast.CallExpr) {
g.writeln('for (int $i = 0; $i < ${tmp}_len; ++$i) {')
g.writeln('\t$elem_type_str it = (($elem_type_str*) ${tmp}_orig.data)[$i];')
mut is_embed_map_filter := false
expr := node.args[0].expr
match expr {
mut expr := node.args[0].expr
match mut expr {
ast.AnonFn {
g.write('\tif (')
g.gen_anon_fn_decl(expr)
g.gen_anon_fn_decl(mut expr)
g.write('${expr.decl.name}(it)')
}
ast.Ident {

View File

@ -2502,12 +2502,15 @@ fn (mut g Gen) autofree_var_call(free_fn_name string, v ast.Var) {
}
}
fn (mut g Gen) gen_anon_fn_decl(it ast.AnonFn) {
pos := g.out.len
g.stmt(it.decl)
fn_body := g.out.after(pos)
g.out.go_back(fn_body.len)
g.anon_fn_definitions << fn_body
fn (mut g Gen) gen_anon_fn_decl(mut node ast.AnonFn) {
if !node.has_gen {
pos := g.out.len
g.stmt(node.decl)
fn_body := g.out.after(pos)
g.out.go_back(fn_body.len)
g.anon_fn_definitions << fn_body
node.has_gen = true
}
}
fn (mut g Gen) map_fn_ptrs(key_typ table.TypeSymbol) (string, string, string, string) {
@ -2560,10 +2563,10 @@ fn (mut g Gen) map_fn_ptrs(key_typ table.TypeSymbol) (string, string, string, st
fn (mut g Gen) expr(node ast.Expr) {
// println('cgen expr() line_nr=$node.pos.line_nr')
// NB: please keep the type names in the match here in alphabetical order:
match node {
match mut node {
ast.AnonFn {
// TODO: dont fiddle with buffers
g.gen_anon_fn_decl(node)
g.gen_anon_fn_decl(mut node)
fsym := g.table.get_type_symbol(node.typ)
g.write(fsym.name)
}
@ -5877,7 +5880,7 @@ fn (mut g Gen) go_expr(node ast.GoExpr) {
fn (mut g Gen) go_stmt(node ast.GoStmt, joinable bool) string {
mut handle := ''
tmp := g.new_tmp_var()
expr := node.call_expr
mut expr := node.call_expr
mut name := expr.name // util.no_dots(expr.name)
// TODO: fn call is duplicated. merge with fn_call().
for i, generic_type in expr.generic_types {
@ -5893,8 +5896,8 @@ fn (mut g Gen) go_stmt(node ast.GoStmt, joinable bool) string {
if expr.is_method {
receiver_sym := g.table.get_type_symbol(expr.receiver_type)
name = receiver_sym.name + '_' + name
} else if expr.left is ast.AnonFn {
g.gen_anon_fn_decl(expr.left)
} else if mut expr.left is ast.AnonFn {
g.gen_anon_fn_decl(mut expr.left)
fsym := g.table.get_type_symbol(expr.left.typ)
name = fsym.name
}

View File

@ -0,0 +1,24 @@
const default_logger = Example{}
struct Example {
structs []Another = [Another{}]
}
pub struct Another {
function fn (string) = fn (value string) {
println('$value')
}
}
pub fn (e Example) useless() string {
return 'ok'
}
fn test_anon_fn_redefinition() {
e1 := Example{}
assert e1.useless() == 'ok'
e2 := Example{}
assert e2.useless() == 'ok'
e3 := Example{}
assert e3.useless() == 'ok'
}