From 163cbeef0e37f12d8dafcdd03fd56ab9591e6e76 Mon Sep 17 00:00:00 2001 From: CreeperFace <165158232+dy-tea@users.noreply.github.com> Date: Thu, 9 Oct 2025 00:09:48 +0100 Subject: [PATCH] checker: identify return on comptime generic match nested in if else (fix #25461) (#25462) --- vlib/v/checker/match.v | 13 +++- vlib/v/checker/return.v | 59 +++++++++++++++++++ .../comptime_match_generic_inside_if_test.v | 26 ++++++++ 3 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 vlib/v/tests/comptime/comptime_match_generic_inside_if_test.v diff --git a/vlib/v/checker/match.v b/vlib/v/checker/match.v index 2c7da8b29..c110e1720 100644 --- a/vlib/v/checker/match.v +++ b/vlib/v/checker/match.v @@ -445,12 +445,21 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type { } } first_iteration = false - if has_return := c.has_return(branch.stmts) { - if has_return { + if node.is_comptime { + // branches may not have been processed by c.stmts() + if has_top_return(branch.stmts) { nbranches_with_return++ } else { nbranches_without_return++ } + } else { + if has_return := c.has_return(branch.stmts) { + if has_return { + nbranches_with_return++ + } else { + nbranches_without_return++ + } + } } } if nbranches_with_return > 0 { diff --git a/vlib/v/checker/return.v b/vlib/v/checker/return.v index bf947dfd8..e8b9614ab 100644 --- a/vlib/v/checker/return.v +++ b/vlib/v/checker/return.v @@ -367,6 +367,14 @@ fn has_top_return(stmts []ast.Stmt) bool { if has_top_return(stmt.expr.stmts) { return true } + } else if stmt.expr is ast.IfExpr { + if has_top_return_in_if_expr(stmt.expr) { + return true + } + } else if stmt.expr is ast.MatchExpr { + if has_top_return_in_match_expr(stmt.expr) { + return true + } } } else {} @@ -375,6 +383,57 @@ fn has_top_return(stmts []ast.Stmt) bool { return false } +fn has_top_return_in_if_expr(if_expr ast.IfExpr) bool { + if if_expr.branches.len < 2 || !if_expr.has_else { + return false + } + for branch in if_expr.branches { + if !has_top_return(branch.stmts) { + return false + } + } + return true +} + +fn has_top_return_in_match_expr(match_expr ast.MatchExpr) bool { + if match_expr.branches.len == 0 { + return false + } + if match_expr.is_comptime { + mut has_else := false + for branch in match_expr.branches { + if branch.is_else { + has_else = true + break + } + for expr in branch.exprs { + if expr is ast.Ident && expr.name == '\$else' { + has_else = true + break + } + } + if has_else { + break + } + } + if has_else { + for branch in match_expr.branches { + if !has_top_return(branch.stmts) { + return false + } + } + return true + } + return false + } + for branch in match_expr.branches { + if !has_top_return(branch.stmts) { + return false + } + } + return true +} + fn (mut c Checker) check_noreturn_fn_decl(mut node ast.FnDecl) { if !node.is_noreturn { return diff --git a/vlib/v/tests/comptime/comptime_match_generic_inside_if_test.v b/vlib/v/tests/comptime/comptime_match_generic_inside_if_test.v new file mode 100644 index 000000000..5cd022f02 --- /dev/null +++ b/vlib/v/tests/comptime/comptime_match_generic_inside_if_test.v @@ -0,0 +1,26 @@ +fn strange[T](a T, b T) T { + if a != 0 { + $match T { + u8 { + return a + } + i8 { + if a > 0 { + return a + } else { + return b + } + } + $else { + $compile_error('unknown') + } + } + } else { + return b + } +} + +fn test_main() { + assert strange[u8](0, 1) == 1 + assert strange[i8](0, 1) == 1 +} -- 2.39.5