Skip to content

Commit 45fd7eb

Browse files
authored
checker: implement option unwrapping on else branch (#22504)
1 parent e1e44e3 commit 45fd7eb

File tree

2 files changed

+52
-5
lines changed

2 files changed

+52
-5
lines changed

vlib/v/checker/if.v

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
363363
}
364364
} else {
365365
// smartcast sumtypes and interfaces when using `is`
366-
c.smartcast_if_conds(mut branch.cond, mut branch.scope)
366+
c.smartcast_if_conds(mut branch.cond, mut branch.scope, node)
367367
if node_is_expr {
368368
c.stmts_ending_with_expression(mut branch.stmts, c.expected_or_type)
369369
} else {
@@ -535,11 +535,11 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
535535
return node.typ
536536
}
537537

538-
fn (mut c Checker) smartcast_if_conds(mut node ast.Expr, mut scope ast.Scope) {
538+
fn (mut c Checker) smartcast_if_conds(mut node ast.Expr, mut scope ast.Scope, control_expr ast.Expr) {
539539
if mut node is ast.InfixExpr {
540540
if node.op == .and {
541-
c.smartcast_if_conds(mut node.left, mut scope)
542-
c.smartcast_if_conds(mut node.right, mut scope)
541+
c.smartcast_if_conds(mut node.left, mut scope, control_expr)
542+
c.smartcast_if_conds(mut node.right, mut scope, control_expr)
543543
} else if node.left is ast.Ident && node.op == .ne && node.right is ast.None {
544544
if node.left is ast.Ident && c.comptime.get_ct_type_var(node.left) == .smartcast {
545545
node.left_type = c.comptime.get_comptime_var_type(node.left)
@@ -624,7 +624,26 @@ fn (mut c Checker) smartcast_if_conds(mut node ast.Expr, mut scope ast.Scope) {
624624
}
625625
}
626626
} else if mut node is ast.Likely {
627-
c.smartcast_if_conds(mut node.expr, mut scope)
627+
c.smartcast_if_conds(mut node.expr, mut scope, control_expr)
628+
} else if control_expr is ast.IfExpr && mut node is ast.NodeError { // IfExpr else branch
629+
if control_expr.branches.len != 2 {
630+
return
631+
}
632+
mut first_cond := control_expr.branches[0].cond
633+
// handles unwrapping on if var == none { /**/ } else { /*unwrapped var*/ }
634+
if mut first_cond is ast.InfixExpr {
635+
if first_cond.left is ast.Ident && first_cond.op == .eq && first_cond.right is ast.None {
636+
if first_cond.left is ast.Ident
637+
&& c.comptime.get_ct_type_var(first_cond.left) == .smartcast {
638+
first_cond.left_type = c.comptime.get_comptime_var_type(first_cond.left)
639+
c.smartcast(mut first_cond.left, first_cond.left_type, first_cond.left_type.clear_flag(.option), mut
640+
scope, true)
641+
} else {
642+
c.smartcast(mut first_cond.left, first_cond.left_type, first_cond.left_type.clear_flag(.option), mut
643+
scope, false)
644+
}
645+
}
646+
}
628647
}
629648
}
630649

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
type TestSmart = ?string | int
2+
3+
fn test_simple_case() {
4+
o := ?string('abc')
5+
dump(o)
6+
a := if o == none {
7+
'none'
8+
} else {
9+
'${o} exists'
10+
}
11+
dump(a)
12+
assert a == 'abc exists'
13+
}
14+
15+
fn test_comptime_smartcast() {
16+
t := TestSmart(?string('foobar'))
17+
$for v in TestSmart.variants {
18+
if t is v {
19+
$if t is ?string {
20+
if t == none {
21+
panic('error')
22+
} else {
23+
assert t == 'foobar'
24+
}
25+
}
26+
}
27+
}
28+
}

0 commit comments

Comments
 (0)