checker: implement if smartcast multi conds (part 1) (#10477)

pull/10484/head
yuyi 2021-06-17 00:16:15 +08:00 committed by GitHub
parent d56219a986
commit 1dca06495d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 62 additions and 103 deletions

View File

@ -4658,19 +4658,15 @@ pub fn (mut c Checker) expr(node ast.Expr) ast.Type {
c.ensure_type_exists(node.typ, node.pos) or {}
if !c.table.sumtype_has_variant(node.expr_type, node.typ) {
c.error('cannot cast `$expr_type_sym.name` to `$type_sym.name`', node.pos)
// c.error('only $info.variants can be casted to `$typ`', node.pos)
}
} else {
mut s := 'cannot cast non-sum type `$expr_type_sym.name` using `as`'
if type_sym.kind == .sum_type {
s += ' - use e.g. `${type_sym.name}(some_expr)` instead.'
}
c.error(s, node.pos)
// mut s := 'cannot cast non-sum type `$expr_type_sym.name` using `as`'
// if type_sym.kind == .sum_type {
// s += ' - use e.g. `${type_sym.name}(some_expr)` instead.'
// }
// c.error(s, node.pos)
}
if expr_type_sym.kind == .sum_type {
return node.typ
}
return node.typ.to_ptr()
return node.typ
}
ast.Assoc {
v := node.scope.find_var(node.var_name) or { panic(err) }
@ -6038,50 +6034,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
c.skip_flags = cur_skip_flags
} else {
// smartcast sumtypes and interfaces when using `is`
pos := branch.cond.position()
if branch.cond is ast.InfixExpr {
if branch.cond.op == .key_is {
right_expr := branch.cond.right
right_type := match right_expr {
ast.TypeNode {
right_expr.typ
}
ast.None {
ast.none_type_idx
}
else {
c.error('invalid type `$right_expr`', right_expr.position())
ast.Type(0)
}
}
if right_type != ast.Type(0) {
left_sym := c.table.get_type_symbol(branch.cond.left_type)
expr_type := c.expr(branch.cond.left)
if left_sym.kind == .interface_ {
c.type_implements(right_type, expr_type, pos)
} else if !c.check_types(right_type, expr_type) {
expect_str := c.table.type_to_str(right_type)
expr_str := c.table.type_to_str(expr_type)
c.error('cannot use type `$expect_str` as type `$expr_str`',
pos)
}
if (branch.cond.left is ast.Ident || branch.cond.left is ast.SelectorExpr)
&& branch.cond.right is ast.TypeNode {
is_variable := if mut branch.cond.left is ast.Ident {
branch.cond.left.kind == .variable
} else {
true
}
if is_variable {
if left_sym.kind in [.interface_, .sum_type] {
c.smartcast(branch.cond.left, branch.cond.left_type,
right_type, mut branch.scope)
}
}
}
}
}
}
c.smartcast_if_conds(branch.cond, mut branch.scope)
c.stmts(branch.stmts)
}
if expr_required {

View File

@ -5,10 +5,10 @@ vlib/v/checker/tests/is_type_invalid.vv:14:12: error: `IoS` has no variant `byte
| ~~
15 | println('not cool')
16 | }
vlib/v/checker/tests/is_type_invalid.vv:18:5: error: `Cat` doesn't implement method `speak` of interface `Animal`
vlib/v/checker/tests/is_type_invalid.vv:18:7: error: `Cat` doesn't implement method `speak` of interface `Animal`
16 | }
17 | a := Animal(Dog{})
18 | if a is Cat {
| ~~~~~~~~
| ~~
19 | println('not cool either')
20 | }

View File

@ -1,28 +0,0 @@
vlib/v/checker/tests/sum.vv:5:8: error: cannot cast non-sum type `int` using `as`
3 | fn non_sum() {
4 | v := 4
5 | _ = v as rune
| ~~
6 | _ = v as Var
7 | }
vlib/v/checker/tests/sum.vv:6:8: error: cannot cast non-sum type `int` using `as` - use e.g. `Var(some_expr)` instead.
4 | v := 4
5 | _ = v as rune
6 | _ = v as Var
| ~~
7 | }
8 |
vlib/v/checker/tests/sum.vv:10:7: error: cannot cast `rune` to `Var`
8 |
9 | fn sum() {
10 | _ := Var(`J`)
| ~~~~~~~~
11 | mut s2 := Var('')
12 | s2 = true
vlib/v/checker/tests/sum.vv:12:7: error: cannot assign to `s2`: expected `Var`, not `bool`
10 | _ := Var(`J`)
11 | mut s2 := Var('')
12 | s2 = true
| ~~~~
13 | _ = s2
14 | }

View File

@ -1,14 +0,0 @@
type Var = int | string
fn non_sum() {
v := 4
_ = v as rune
_ = v as Var
}
fn sum() {
_ := Var(`J`)
mut s2 := Var('')
s2 = true
_ = s2
}

View File

@ -301,8 +301,8 @@ fn (f Fmt) should_insert_newline_before_node(node ast.Node, prev_node ast.Node)
prev_line_nr := prev_node.position().last_line
// The nodes are Stmts
if node is ast.Stmt && prev_node is ast.Stmt {
stmt := node as ast.Stmt
prev_stmt := prev_node as ast.Stmt
stmt := node
prev_stmt := prev_node
// Force a newline after a block of HashStmts
if prev_stmt is ast.HashStmt && stmt !is ast.HashStmt && stmt !is ast.ExprStmt {
return true
@ -1662,8 +1662,7 @@ pub fn (mut f Fmt) call_args(args []ast.CallArg) {
}
for i, arg in args {
if i == args.len - 1 && arg.expr is ast.StructInit {
struct_expr := arg.expr as ast.StructInit
if struct_expr.typ == ast.void_type {
if arg.expr.typ == ast.void_type {
f.use_short_fn_args = true
}
}
@ -2477,7 +2476,7 @@ pub fn (mut f Fmt) prefix_expr_cast_expr(node ast.Expr) {
mut is_pe_amp_ce := false
if node is ast.PrefixExpr {
if node.right is ast.CastExpr && node.op == .amp {
mut ce := node.right as ast.CastExpr
mut ce := node.right
ce.typname = f.table.get_type_symbol(ce.typ).name
is_pe_amp_ce = true
f.expr(ce)

View File

@ -6422,6 +6422,8 @@ fn (mut g Gen) as_cast(node ast.AsCast) {
variant_sym := g.table.get_type_symbol(variant)
g.as_cast_type_names[idx] = variant_sym.name
}
} else {
g.expr(node.expr)
}
}

View File

@ -0,0 +1,47 @@
struct Empty {}
struct SourcePosition {
source_line u32
source_column u32
}
type SourcePositionType = Empty | SourcePosition
type NameIndexType = Empty | u32
struct GenPosition {
gen_line u32
gen_column u32
}
struct Mapping {
GenPosition
sources_ind u32
names_ind NameIndexType
source_position SourcePositionType
}
fn ok(mapping_a Mapping, mapping_b Mapping) bool {
if mapping_a.source_position is SourcePosition && mapping_b.source_position is SourcePosition {
return mapping_a.source_position.source_line != mapping_b.source_position.source_line
|| mapping_a.source_position.source_column != mapping_b.source_position.source_column
}
return false
}
fn test_if_smartcast_multi_conds() {
a := Mapping{
source_position: SourcePosition{
source_line: 11
source_column: 22
}
}
b := Mapping{
source_position: SourcePosition{
source_line: 22
source_column: 11
}
}
ret := ok(a, b)
println(ret)
assert ret
}