From 9f3bab2894150a1fa0b2f7fe5ef6d399f01ab290 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Tue, 21 Apr 2026 06:25:02 +0300 Subject: [PATCH] parser: fix calling function wrapped in a parexpr (fixes #22652) --- vlib/v/parser/expr.v | 35 +++++++++++++++++-- ...nthesized_propagated_index_or_block_test.v | 17 +++++++++ vlib/v/tests/fns/fn_index_direct_call_test.v | 8 +++++ 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/vlib/v/parser/expr.v b/vlib/v/parser/expr.v index ce1af9df4..33c1802b6 100644 --- a/vlib/v/parser/expr.v +++ b/vlib/v/parser/expr.v @@ -693,7 +693,7 @@ fn (mut p Parser) expr_with_left(left ast.Expr, precedence int, is_stmt_ident bo // Infix for { if p.tok.kind == .lpar && p.tok.line_nr == p.prev_tok.line_nr - && node in [ast.CallExpr, ast.IndexExpr, ast.SelectorExpr] { + && node in [ast.CallExpr, ast.IndexExpr, ast.ParExpr, ast.SelectorExpr] { p.promote_if_expr_to_value(mut node) node = p.call_expr_with_left(node) p.is_stmt_ident = is_stmt_ident @@ -848,14 +848,45 @@ fn (mut p Parser) promote_if_expr_to_value(mut expr ast.Expr) { } } +fn unwrap_parenthesized_call_left(expr ast.Expr) ast.Expr { + return match expr { + ast.ParExpr { unwrap_parenthesized_call_left(expr.expr) } + else { expr } + } +} + fn (mut p Parser) call_expr_with_left(left ast.Expr) ast.CallExpr { p.next() pos := p.tok.pos() args := p.call_args() p.check(.rpar) or_block := p.gen_or_block() + unwrapped_left := unwrap_parenthesized_call_left(left) + mut name := '' + mut name_pos := token.Pos{} + mut mod := '' + mut kind := ast.CallKind.unknown + if unwrapped_left is ast.Ident { + ident := unwrapped_left as ast.Ident + mut fn_name := ident.name + if p.is_imported_symbol(fn_name) { + check := !p.imported_symbols_used[fn_name] + fn_name = p.imported_symbols[fn_name] + if check { + p.register_used_import_for_symbol_name(fn_name) + } + } + name = fn_name + name_pos = ident.pos + mod = p.mod + kind = p.call_kind(fn_name) + } return ast.CallExpr{ - left: left + name: name + name_pos: name_pos + mod: mod + kind: kind + left: unwrapped_left args: args pos: pos scope: p.scope diff --git a/vlib/v/parser/parenthesized_propagated_index_or_block_test.v b/vlib/v/parser/parenthesized_propagated_index_or_block_test.v index 0f3b1022e..d313c1825 100644 --- a/vlib/v/parser/parenthesized_propagated_index_or_block_test.v +++ b/vlib/v/parser/parenthesized_propagated_index_or_block_test.v @@ -30,3 +30,20 @@ log.info('42') mut checker_ := checker.new_checker(table, vpref) checker_.check(mut prog) } + +fn test_parenthesized_function_can_be_called() { + source_text := ' +fn add(a int, b int) int { + return a + b +} + +fn main() { + assert (add)(2, 4) == 6 +} +' + mut table := ast.new_table() + vpref := &pref.Preferences{} + mut prog := parse_text(source_text, '', mut table, .skip_comments, vpref) + mut checker_ := checker.new_checker(table, vpref) + checker_.check(mut prog) +} diff --git a/vlib/v/tests/fns/fn_index_direct_call_test.v b/vlib/v/tests/fns/fn_index_direct_call_test.v index 0ff266a8c..1aade3ca5 100644 --- a/vlib/v/tests/fns/fn_index_direct_call_test.v +++ b/vlib/v/tests/fns/fn_index_direct_call_test.v @@ -35,3 +35,11 @@ fn test_fn_map_direct_call() { assert a['aaa']() == 'aaa' assert a['bbb']() == 'bbb' } + +fn add(a int, b int) int { + return a + b +} + +fn test_parenthesized_fn_direct_call() { + assert (add)(2, 4) == 6 +} -- 2.39.5