Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v: implement option unwrapping on else branch #22504

Merged
merged 2 commits into from
Oct 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions vlib/v/checker/if.v
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
}
} else {
// smartcast sumtypes and interfaces when using `is`
c.smartcast_if_conds(mut branch.cond, mut branch.scope)
c.smartcast_if_conds(mut branch.cond, mut branch.scope, node)
if node_is_expr {
c.stmts_ending_with_expression(mut branch.stmts, c.expected_or_type)
} else {
Expand Down Expand Up @@ -535,11 +535,11 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
return node.typ
}

fn (mut c Checker) smartcast_if_conds(mut node ast.Expr, mut scope ast.Scope) {
fn (mut c Checker) smartcast_if_conds(mut node ast.Expr, mut scope ast.Scope, control_expr ast.Expr) {
if mut node is ast.InfixExpr {
if node.op == .and {
c.smartcast_if_conds(mut node.left, mut scope)
c.smartcast_if_conds(mut node.right, mut scope)
c.smartcast_if_conds(mut node.left, mut scope, control_expr)
c.smartcast_if_conds(mut node.right, mut scope, control_expr)
} else if node.left is ast.Ident && node.op == .ne && node.right is ast.None {
if node.left is ast.Ident && c.comptime.get_ct_type_var(node.left) == .smartcast {
node.left_type = c.comptime.get_comptime_var_type(node.left)
Expand Down Expand Up @@ -624,7 +624,26 @@ fn (mut c Checker) smartcast_if_conds(mut node ast.Expr, mut scope ast.Scope) {
}
}
} else if mut node is ast.Likely {
c.smartcast_if_conds(mut node.expr, mut scope)
c.smartcast_if_conds(mut node.expr, mut scope, control_expr)
} else if control_expr is ast.IfExpr && mut node is ast.NodeError { // IfExpr else branch
if control_expr.branches.len != 2 {
return
}
mut first_cond := control_expr.branches[0].cond
// handles unwrapping on if var == none { /**/ } else { /*unwrapped var*/ }
if mut first_cond is ast.InfixExpr {
if first_cond.left is ast.Ident && first_cond.op == .eq && first_cond.right is ast.None {
if first_cond.left is ast.Ident
&& c.comptime.get_ct_type_var(first_cond.left) == .smartcast {
first_cond.left_type = c.comptime.get_comptime_var_type(first_cond.left)
c.smartcast(mut first_cond.left, first_cond.left_type, first_cond.left_type.clear_flag(.option), mut
scope, true)
} else {
c.smartcast(mut first_cond.left, first_cond.left_type, first_cond.left_type.clear_flag(.option), mut
scope, false)
}
}
}
}
}

Expand Down
28 changes: 28 additions & 0 deletions vlib/v/tests/options/option_unwrap_ifexpr_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
type TestSmart = ?string | int

fn test_simple_case() {
o := ?string('abc')
dump(o)
a := if o == none {
'none'
} else {
'${o} exists'
}
dump(a)
assert a == 'abc exists'
}

fn test_comptime_smartcast() {
t := TestSmart(?string('foobar'))
$for v in TestSmart.variants {
if t is v {
$if t is ?string {
if t == none {
panic('error')
} else {
assert t == 'foobar'
}
}
}
}
}
Loading