From 16d14c660bd5bb79b6de3c2d202081aa83e90cf1 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Tue, 21 Apr 2026 16:02:13 +0300 Subject: [PATCH] checker: fix assert expression with -(-2) or +2 sub expression (fixes #26815) --- vlib/v/checker/checker.v | 4 ++-- vlib/v/parser/expr.v | 11 ++++++++--- vlib/v/tests/prefix_expr_test.v | 17 +++++++++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 731b8295e..057f30616 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -7625,8 +7625,8 @@ fn (mut c Checker) prefix_expr(mut node ast.PrefixExpr) ast.Type { // FIXME // there are currently other issues to investigate if right_type // is unwrapped directly as initialization, so do it here - if node.op == .minus && !right_sym.is_number() { - c.type_error_for_operator('-', 'numeric', right_sym.name, node.pos) + if node.op in [.plus, .minus] && !right_sym.is_number() { + c.type_error_for_operator(node.op.str(), 'numeric', right_sym.name, node.pos) } if node.op == .arrow { raw_right_sym := c.table.final_sym(right_type) diff --git a/vlib/v/parser/expr.v b/vlib/v/parser/expr.v index cfe8a0182..ce1af9df4 100644 --- a/vlib/v/parser/expr.v +++ b/vlib/v/parser/expr.v @@ -177,6 +177,10 @@ fn (mut p Parser) check_expr(precedence int) !ast.Expr { .power { node = p.power_prefix_expr() } + .plus { + // +1, +a + node = p.prefix_expr() + } .minus { // -1, -a if p.peek_tok.kind == .number && !(p.peek_token(2).kind == .power @@ -1057,11 +1061,12 @@ fn (mut p Parser) infix_expr(left ast.Expr) ast.Expr { right = p.expr(if op == .power { precedence - 1 } else { precedence }) } p.inside_assign_rhs = old_assign_rhs - if op in [.plus, .minus, .mul, .power, .div, .mod, .lt, .eq] && mut right is ast.PrefixExpr { + // Keep rejecting doubled operator forms like `5 - - -5`, but allow valid + // infix rhs expressions such as `a == -(-2)` and `a == +2`. + if op in [.plus, .minus, .mul] && mut right is ast.PrefixExpr { mut right_expr := right.right right_expr = right_expr.remove_par() - if right.op in [.plus, .minus, .mul, .power, .div, .mod, .lt, .eq] - && right_expr.is_pure_literal() { + if right.op == op && right_expr.is_pure_literal() { p.error_with_pos('invalid expression: unexpected token `${op}`', right_op_pos) } } diff --git a/vlib/v/tests/prefix_expr_test.v b/vlib/v/tests/prefix_expr_test.v index 2e3aae3d8..72c777f49 100644 --- a/vlib/v/tests/prefix_expr_test.v +++ b/vlib/v/tests/prefix_expr_test.v @@ -1,3 +1,5 @@ +import strconv + fn value(n int) int { return n } @@ -27,3 +29,18 @@ fn test_negative() { assert -arr[0] == -1 assert -arr[1] == -2 } + +fn test_positive() { + two := 2 + assert +two == 2 + assert +(two - 1) == 1 +} + +fn test_prefix_expr_in_assert_comparison() ! { + i := 2 + assert strconv.atoi('1')! == 1 + assert strconv.atoi('-2')! == -2 + assert strconv.atoi('+2')! == i - 1 + 1 + assert strconv.atoi('+2')! == -(-2) + assert strconv.atoi('+2')! == +2 +} -- 2.39.5