Skip to content

Commit 163cbee

Browse files
authored
checker: identify return on comptime generic match nested in if else (fix #25461) (#25462)
1 parent 217422d commit 163cbee

3 files changed

Lines changed: 96 additions & 2 deletions

File tree

‎vlib/v/checker/match.v‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -445,12 +445,21 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
445445
}
446446
}
447447
first_iteration = false
448-
if has_return := c.has_return(branch.stmts) {
449-
if has_return {
448+
if node.is_comptime {
449+
// branches may not have been processed by c.stmts()
450+
if has_top_return(branch.stmts) {
450451
nbranches_with_return++
451452
} else {
452453
nbranches_without_return++
453454
}
455+
} else {
456+
if has_return := c.has_return(branch.stmts) {
457+
if has_return {
458+
nbranches_with_return++
459+
} else {
460+
nbranches_without_return++
461+
}
462+
}
454463
}
455464
}
456465
if nbranches_with_return > 0 {

‎vlib/v/checker/return.v‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,14 @@ fn has_top_return(stmts []ast.Stmt) bool {
367367
if has_top_return(stmt.expr.stmts) {
368368
return true
369369
}
370+
} else if stmt.expr is ast.IfExpr {
371+
if has_top_return_in_if_expr(stmt.expr) {
372+
return true
373+
}
374+
} else if stmt.expr is ast.MatchExpr {
375+
if has_top_return_in_match_expr(stmt.expr) {
376+
return true
377+
}
370378
}
371379
}
372380
else {}
@@ -375,6 +383,57 @@ fn has_top_return(stmts []ast.Stmt) bool {
375383
return false
376384
}
377385

386+
fn has_top_return_in_if_expr(if_expr ast.IfExpr) bool {
387+
if if_expr.branches.len < 2 || !if_expr.has_else {
388+
return false
389+
}
390+
for branch in if_expr.branches {
391+
if !has_top_return(branch.stmts) {
392+
return false
393+
}
394+
}
395+
return true
396+
}
397+
398+
fn has_top_return_in_match_expr(match_expr ast.MatchExpr) bool {
399+
if match_expr.branches.len == 0 {
400+
return false
401+
}
402+
if match_expr.is_comptime {
403+
mut has_else := false
404+
for branch in match_expr.branches {
405+
if branch.is_else {
406+
has_else = true
407+
break
408+
}
409+
for expr in branch.exprs {
410+
if expr is ast.Ident && expr.name == '\$else' {
411+
has_else = true
412+
break
413+
}
414+
}
415+
if has_else {
416+
break
417+
}
418+
}
419+
if has_else {
420+
for branch in match_expr.branches {
421+
if !has_top_return(branch.stmts) {
422+
return false
423+
}
424+
}
425+
return true
426+
}
427+
return false
428+
}
429+
for branch in match_expr.branches {
430+
if !has_top_return(branch.stmts) {
431+
return false
432+
}
433+
}
434+
return true
435+
}
436+
378437
fn (mut c Checker) check_noreturn_fn_decl(mut node ast.FnDecl) {
379438
if !node.is_noreturn {
380439
return
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
fn strange[T](a T, b T) T {
2+
if a != 0 {
3+
$match T {
4+
u8 {
5+
return a
6+
}
7+
i8 {
8+
if a > 0 {
9+
return a
10+
} else {
11+
return b
12+
}
13+
}
14+
$else {
15+
$compile_error('unknown')
16+
}
17+
}
18+
} else {
19+
return b
20+
}
21+
}
22+
23+
fn test_main() {
24+
assert strange[u8](0, 1) == 1
25+
assert strange[i8](0, 1) == 1
26+
}

0 commit comments

Comments
 (0)