From 922cee9162e50d589fa4d8b3de8b33c8fb50a61b Mon Sep 17 00:00:00 2001 From: yuyi Date: Mon, 25 Apr 2022 16:26:14 +0800 Subject: [PATCH] parser, checker, cgen: fix error for fn call using anon fn call argument (#14155) --- vlib/v/checker/fn.v | 11 +++++++++++ vlib/v/gen/c/fn.v | 5 +++-- vlib/v/parser/parser.v | 12 ++++++++++++ .../v/tests/fn_call_using_anon_fn_call_args.v | 19 +++++++++++++++++++ 4 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 vlib/v/tests/fn_call_using_anon_fn_call_args.v diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index f497c099ed..d0db191735 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -578,6 +578,17 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) found = true return ast.string_type } + if !found && node.left is ast.CallExpr { + c.expr(node.left) + expr := node.left as ast.CallExpr + sym := c.table.sym(expr.return_type) + if sym.kind == .function { + info := sym.info as ast.FnType + node.return_type = info.func.return_type + found = true + func = info.func + } + } // already prefixed (mod.fn) or C/builtin/main if !found { if f := c.table.find_fn(fn_name) { diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 72ef19b5b0..2208a90e96 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -637,11 +637,12 @@ fn (mut g Gen) call_expr(node ast.CallExpr) { // see my comment in parser near anon_fn if node.left is ast.AnonFn { g.expr(node.left) - } - if node.left is ast.IndexExpr && node.name == '' { + } else if node.left is ast.IndexExpr && node.name == '' { g.is_fn_index_call = true g.expr(node.left) g.is_fn_index_call = false + } else if node.left is ast.CallExpr && node.name == '' { + g.expr(node.left) } if node.should_be_skipped { return diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 1e7200a651..f0fade2121 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -2327,6 +2327,18 @@ pub fn (mut p Parser) name_expr() ast.Expr { p.error_with_pos('unexpected $p.prev_tok', p.prev_tok.pos()) } node = p.call_expr(language, mod) + if p.tok.kind == .lpar && p.prev_tok.line_nr == p.tok.line_nr { + p.next() + pos := p.tok.pos() + args := p.call_args() + p.check(.rpar) + node = ast.CallExpr{ + left: node + args: args + pos: pos + scope: p.scope + } + } } } else if (p.peek_tok.kind == .lcbr || (p.peek_tok.kind == .lt && lit0_is_capital)) && (!p.inside_match || (p.inside_select && prev_tok_kind == .arrow && lit0_is_capital)) diff --git a/vlib/v/tests/fn_call_using_anon_fn_call_args.v b/vlib/v/tests/fn_call_using_anon_fn_call_args.v new file mode 100644 index 0000000000..c140b2fe18 --- /dev/null +++ b/vlib/v/tests/fn_call_using_anon_fn_call_args.v @@ -0,0 +1,19 @@ +fn foofun1(op string) fn () string { + return fn () string { + return 'x passed' + } +} + +fn foofun2(op string) fn () int { + return fn () int { + return 22 + } +} + +fn test_fn_call_using_anon_fn_call_arg() { + println(main.foofun1('1')()) + assert main.foofun1('1')() == 'x passed' + + println(main.foofun2('1')()) + assert main.foofun2('1')() == 22 +}