Skip to content

Commit

Permalink
checker: implement autocast in if conditions (#18573)
Browse files Browse the repository at this point in the history
  • Loading branch information
yuyi98 committed Jun 27, 2023
1 parent e48b55f commit 8508c55
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 0 deletions.
40 changes: 40 additions & 0 deletions vlib/v/checker/infix.v
Expand Up @@ -13,6 +13,24 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
node.left_type = left_type
c.expected_type = left_type

// `if n is ast.Ident && n.is_mut { ... }`
if node.op == .and {
mut left_node := node.left
for mut left_node is ast.InfixExpr {
if left_node.op == .key_is {
// search `n is ast.Ident`
from_type := c.expr(left_node.left)
to_type := c.expr(left_node.right)
c.autocast_in_if_conds(mut node.right, left_node.left, from_type, to_type)
break
} else if left_node.op == .and {
left_node = left_node.left
} else {
break
}
}
}

if node.op == .key_is {
c.inside_x_is_type = true
}
Expand Down Expand Up @@ -793,3 +811,25 @@ fn (mut c Checker) invalid_operator_error(op token.Kind, left_type ast.Type, rig
right_name := c.table.type_to_str(right_type)
c.error('invalid operator `${op}` to `${left_name}` and `${right_name}`', pos)
}

// `if node is ast.Ident && node.is_mut { ... }` -> `if node is ast.Ident && (node as ast.Ident).is_mut { ... }`
fn (mut c Checker) autocast_in_if_conds(mut right ast.Expr, from_expr ast.Expr, from_type ast.Type, to_type ast.Type) {
match mut right {
ast.SelectorExpr {
if right.expr.str() == from_expr.str() {
right.expr = ast.ParExpr{
expr: ast.AsCast{
typ: to_type
expr: from_expr
expr_type: from_type
}
}
}
}
ast.InfixExpr {
c.autocast_in_if_conds(mut right.left, from_expr, from_type, to_type)
c.autocast_in_if_conds(mut right.right, from_expr, from_type, to_type)
}
else {}
}
}
24 changes: 24 additions & 0 deletions vlib/v/tests/autocast_in_if_conds_test.v
@@ -0,0 +1,24 @@
type MySumType = S1 | S2

struct S1 {
is_name bool
name string
}

struct S2 {
field2 bool
}

fn test_autocast_in_if_conds() {
s := MySumType(S1{
is_name: true
name: 'bob'
})

if s is S1 && s.is_name && s.name == 'bob' {
println('ok')
assert true
} else {
assert false
}
}

0 comments on commit 8508c55

Please sign in to comment.