From 178dfbf872faa8e759f28a764ef448b5f0286ac7 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 25 Mar 2026 16:42:19 +0300 Subject: [PATCH] checker: fix duplicate case value for match with u8 and int (fixes #26627) --- vlib/v/checker/match.v | 62 +++++++++++++++++-- ...ch_duplicate_branch_mixed_int_literals.out | 14 +++++ ...tch_duplicate_branch_mixed_int_literals.vv | 29 +++++++++ 3 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 vlib/v/checker/tests/match_duplicate_branch_mixed_int_literals.out create mode 100644 vlib/v/checker/tests/match_duplicate_branch_mixed_int_literals.vv diff --git a/vlib/v/checker/match.v b/vlib/v/checker/match.v index fd5824105..14cdb3bae 100644 --- a/vlib/v/checker/match.v +++ b/vlib/v/checker/match.v @@ -570,15 +570,51 @@ fn (mut c Checker) check_match_branch_last_stmt(last_stmt ast.ExprStmt, ret_type } } +fn char_literal_number_value(value string) ?i64 { + if value.len == 2 && value[0] == `\\` { + return match value[1] { + `a` { 7 } + `b` { 8 } + `t` { 9 } + `n` { 10 } + `v` { 11 } + `f` { 12 } + `r` { 13 } + `e` { 27 } + `$` { 36 } + `"` { 34 } + `'` { 39 } + `?` { 63 } + `@` { 64 } + `\\` { 92 } + `\`` { 96 } + `{` { 123 } + `}` { 125 } + else { none } + } + } + runes := value.runes() + if runes.len == 1 { + return runes[0] + } + return none +} + fn (mut c Checker) get_comptime_number_value(mut expr ast.Expr) ?i64 { + if mut expr is ast.ParExpr { + return c.get_comptime_number_value(mut expr.expr) + } + if mut expr is ast.PrefixExpr && expr.op == .minus { + return -c.get_comptime_number_value(mut expr.right)? + } if mut expr is ast.CharLiteral { - return expr.val[0] + return char_literal_number_value(expr.val) } if mut expr is ast.IntegerLiteral { return expr.val.i64() } - if mut expr is ast.CastExpr && expr.expr is ast.IntegerLiteral { - return expr.expr.val.i64() + if mut expr is ast.CastExpr { + return c.get_comptime_number_value(mut expr.expr) } if mut expr is ast.Ident { if mut obj := c.table.global_scope.find_const(expr.full_name()) { @@ -591,6 +627,24 @@ fn (mut c Checker) get_comptime_number_value(mut expr ast.Expr) ?i64 { return none } +fn (mut c Checker) get_match_case_int_key(mut expr ast.Expr, cond_sym ast.TypeSymbol) ?string { + if !cond_sym.is_int() { + return none + } + if value := c.get_comptime_number_value(mut expr) { + return value.str() + } + if value := c.eval_comptime_const_expr(expr, 0) { + if signed_value := value.i64() { + return signed_value.str() + } + if unsigned_value := value.u64() { + return unsigned_value.str() + } + } + return none +} + fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym ast.TypeSymbol) { c.expected_type = node.expected_type if node.cond_type.idx() == 0 { @@ -721,7 +775,7 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym ast.TypeSym } } else { - key = (*expr).str() + key = c.get_match_case_int_key(mut expr, cond_sym) or { (*expr).str() } } } val := if key in branch_exprs { branch_exprs[key] } else { 0 } diff --git a/vlib/v/checker/tests/match_duplicate_branch_mixed_int_literals.out b/vlib/v/checker/tests/match_duplicate_branch_mixed_int_literals.out new file mode 100644 index 000000000..2e7876ea9 --- /dev/null +++ b/vlib/v/checker/tests/match_duplicate_branch_mixed_int_literals.out @@ -0,0 +1,14 @@ +vlib/v/checker/tests/match_duplicate_branch_mixed_int_literals.vv:3:3: error: match case `10` is handled more than once + 1 | fn parse(ch u8) ! { + 2 | match ch { + 3 | ` `, `\t`, `\n`, 10 { + | ~~~~~~~~~~~~~~~~~~~ + 4 | // consume blanks + 5 | } +vlib/v/checker/tests/match_duplicate_branch_mixed_int_literals.vv:17:3: error: match case `10` is handled more than once + 15 | fn parse_cast(ch u8) ! { + 16 | match ch { + 17 | `\n`, u8(10) { + | ~~~~~~~~~~~~ + 18 | println('line feed') + 19 | } diff --git a/vlib/v/checker/tests/match_duplicate_branch_mixed_int_literals.vv b/vlib/v/checker/tests/match_duplicate_branch_mixed_int_literals.vv new file mode 100644 index 000000000..3090c5be8 --- /dev/null +++ b/vlib/v/checker/tests/match_duplicate_branch_mixed_int_literals.vv @@ -0,0 +1,29 @@ +fn parse(ch u8) ! { + match ch { + ` `, `\t`, `\n`, 10 { + // consume blanks + } + `<` { + println('open') + } + else { + return error('root invalid char') + } + } +} + +fn parse_cast(ch u8) ! { + match ch { + `\n`, u8(10) { + println('line feed') + } + else { + return error('root invalid char') + } + } +} + +fn main() { + parse(`<`)! + parse_cast(`\n`)! +} -- 2.39.5