diff --git a/vlib/v/checker/infix.v b/vlib/v/checker/infix.v index 0b91411948..c905f4b0f1 100644 --- a/vlib/v/checker/infix.v +++ b/vlib/v/checker/infix.v @@ -17,6 +17,16 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { if node.op == .and { mut left_node := node.left for mut left_node is ast.InfixExpr { + if left_node.op == .and && mut left_node.right is ast.InfixExpr { + if left_node.right.op == .key_is { + // search last `n is ast.Ident` in the left + from_type := c.expr(left_node.right.left) + to_type := c.expr(left_node.right.right) + c.autocast_in_if_conds(mut node.right, left_node.right.left, from_type, + to_type) + break + } + } if left_node.op == .key_is { // search `n is ast.Ident` from_type := c.expr(left_node.left) @@ -835,6 +845,16 @@ fn (mut c Checker) autocast_in_if_conds(mut right ast.Expr, from_expr ast.Expr, c.autocast_in_if_conds(mut right.right, from_expr, from_type, to_type) } ast.CallExpr { + if right.left.str() == from_expr.str() + && c.table.sym(to_type).has_method_with_generic_parent(right.name) { + right.left = ast.ParExpr{ + expr: ast.AsCast{ + typ: to_type + expr: from_expr + expr_type: from_type + } + } + } c.autocast_in_if_conds(mut right.left, from_expr, from_type, to_type) for mut arg in right.args { c.autocast_in_if_conds(mut arg.expr, from_expr, from_type, to_type) diff --git a/vlib/v/tests/autocast_in_if_conds_3_test.v b/vlib/v/tests/autocast_in_if_conds_3_test.v new file mode 100644 index 0000000000..ffe7093587 --- /dev/null +++ b/vlib/v/tests/autocast_in_if_conds_3_test.v @@ -0,0 +1,45 @@ +type MySumType = S1 | S2 + +struct Info { + name string +} + +struct Node { + left MySumType +} + +struct S1 { + is_info bool + info Info +} + +fn (s1 S1) is_info() bool { + return s1.is_info +} + +struct S2 { + field2 string +} + +fn get_name(name string) string { + return name +} + +fn test_autocast_in_if_conds() { + node := Node{ + left: MySumType(S1{ + is_info: false + info: Info{'foo'} + }) + } + + a := 22 + + if a > 0 && node.left is S1 && !node.left.is_info && get_name(node.left.info.name) == 'foo' + && !node.left.is_info() { + println('ok') + assert true + } else { + assert false + } +}