From 36ab78d6da3e59ae8d30e1c68659cfc9f758362f Mon Sep 17 00:00:00 2001 From: yuyi Date: Thu, 29 Dec 2022 23:53:17 +0800 Subject: [PATCH] parser, cgen: fix anon fn optional call in if expr (#16803) --- vlib/v/gen/c/fn.v | 5 ++- vlib/v/parser/expr.v | 24 +++++++++++++ .../anon_fn_optional_call_in_if_expr_test.v | 35 +++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 vlib/v/tests/anon_fn_optional_call_in_if_expr_test.v diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 4570e6f9cd..a8e2a8157c 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -652,7 +652,7 @@ fn (mut g Gen) call_expr(node ast.CallExpr) { g.expr(node.left) g.writeln(';') g.write(tmp_var) - } else { + } else if node.or_block.kind == .absent { g.expr(node.left) } } else if node.left is ast.IndexExpr && node.name == '' { @@ -695,6 +695,9 @@ fn (mut g Gen) call_expr(node ast.CallExpr) { g.write('${tmp_opt} = ') } else { g.write('${styp} ${tmp_opt} = ') + if node.left is ast.AnonFn { + g.expr(node.left) + } } } if node.is_method && !node.is_field { diff --git a/vlib/v/parser/expr.v b/vlib/v/parser/expr.v index 05533e1520..dd1e7fa026 100644 --- a/vlib/v/parser/expr.v +++ b/vlib/v/parser/expr.v @@ -387,11 +387,35 @@ pub fn (mut p Parser) check_expr(precedence int) !ast.Expr { pos := p.tok.pos() args := p.call_args() p.check(.rpar) + mut or_kind := ast.OrKind.absent + mut or_stmts := []ast.Stmt{} // TODO remove unnecessary allocations by just using .absent + mut or_pos := p.tok.pos() + if p.tok.kind == .key_orelse { + // `foo() or {}`` + or_kind = .block + or_stmts, or_pos = p.or_block(.with_err_var) + } + if p.tok.kind in [.question, .not] { + is_not := p.tok.kind == .not + // `foo()?` + p.next() + if p.inside_defer { + p.error_with_pos('error propagation not allowed inside `defer` blocks', + p.prev_tok.pos()) + } + or_kind = if is_not { .propagate_result } else { .propagate_option } + } + node = ast.CallExpr{ name: 'anon' left: node args: args pos: pos + or_block: ast.OrExpr{ + stmts: or_stmts + kind: or_kind + pos: or_pos + } scope: p.scope } } diff --git a/vlib/v/tests/anon_fn_optional_call_in_if_expr_test.v b/vlib/v/tests/anon_fn_optional_call_in_if_expr_test.v new file mode 100644 index 0000000000..ee613b430c --- /dev/null +++ b/vlib/v/tests/anon_fn_optional_call_in_if_expr_test.v @@ -0,0 +1,35 @@ +fn test_anon_fn_optional_call_in_if_expr_1() { + if fn () ?bool { + return true + }() or { false } + { + println('ok') + assert true + } else { + assert false + } +} + +fn test_anon_fn_optional_call_in_if_expr_2() { + if fn () ?bool { + return true + }()? + { + println('ok') + assert true + } else { + assert false + } +} + +fn test_anon_fn_optional_call_in_if_expr_3() { + if fn () !bool { + return true + }()! + { + println('ok') + assert true + } else { + assert false + } +}