checker: fix smartcast inside smartcast (#7215)

pull/7229/head
Daniel Däschle 2020-12-10 00:59:39 +01:00 committed by GitHub
parent 4a35a75b64
commit a38fe4fca9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 83 additions and 33 deletions

View File

@ -114,6 +114,16 @@ pub mut:
name_type table.Type // T in `T.name` or typeof in `typeof(expr).name` name_type table.Type // T in `T.name` or typeof in `typeof(expr).name`
} }
// root_ident returns the origin ident where the selector started.
pub fn (e &SelectorExpr) root_ident() Ident {
mut root := e.expr
for root is SelectorExpr {
selector_expr := root as SelectorExpr
root = selector_expr.expr
}
return root as Ident
}
// module declaration // module declaration
pub struct Module { pub struct Module {
pub: pub:

View File

@ -2977,9 +2977,10 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
mut is_mut := false mut is_mut := false
if mut node.right.left is ast.Ident { if mut node.right.left is ast.Ident {
ident := node.right.left ident := node.right.left
if ident.obj is ast.Var { // TODO: temporary, remove this
v := ident.obj as ast.Var ident_obj := ident.obj
is_mut = v.is_mut if ident_obj is ast.Var {
is_mut = ident_obj.is_mut
} }
} }
if !c.inside_unsafe && is_mut { if !c.inside_unsafe && is_mut {
@ -3611,7 +3612,12 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
mut sum_type_casts := []table.Type{} mut sum_type_casts := []table.Type{}
expr_sym := c.table.get_type_symbol(node.cond.expr_type) expr_sym := c.table.get_type_symbol(node.cond.expr_type)
if field := c.table.struct_find_field(expr_sym, node.cond.field_name) { if field := c.table.struct_find_field(expr_sym, node.cond.field_name) {
is_mut = field.is_mut if field.is_mut {
root_ident := node.cond.root_ident()
if v := scope.find_var(root_ident.name) {
is_mut = v.is_mut
}
}
} }
if field := scope.find_struct_field(node.cond.expr_type, node.cond.field_name) { if field := scope.find_struct_field(node.cond.expr_type, node.cond.field_name) {
sum_type_casts << field.sum_type_casts sum_type_casts << field.sum_type_casts
@ -3864,6 +3870,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
is_variable := if mut infix.left is ast.Ident { infix.left.kind == .variable } else { true } is_variable := if mut infix.left is ast.Ident { infix.left.kind == .variable } else { true }
// Register shadow variable or `as` variable with actual type // Register shadow variable or `as` variable with actual type
if is_variable { if is_variable {
// TODO: merge this code with match_expr because it has the same logic implemented
if left_sym.kind in [.interface_, .sum_type] { if left_sym.kind in [.interface_, .sum_type] {
mut is_mut := false mut is_mut := false
mut scope := c.file.scope.innermost(branch.body_pos.pos) mut scope := c.file.scope.innermost(branch.body_pos.pos)
@ -3902,7 +3909,12 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
mut sum_type_casts := []table.Type{} mut sum_type_casts := []table.Type{}
expr_sym := c.table.get_type_symbol(infix.left.expr_type) expr_sym := c.table.get_type_symbol(infix.left.expr_type)
if field := c.table.struct_find_field(expr_sym, infix.left.field_name) { if field := c.table.struct_find_field(expr_sym, infix.left.field_name) {
is_mut = field.is_mut if field.is_mut {
root_ident := infix.left.root_ident()
if v := scope.find_var(root_ident.name) {
is_mut = v.is_mut
}
}
} }
if field := scope.find_struct_field(infix.left.expr_type, if field := scope.find_struct_field(infix.left.expr_type,
infix.left.field_name) { infix.left.field_name) {

View File

@ -4,18 +4,11 @@ vlib/v/checker/tests/sum_type_mutable_cast_err.vv:23:10: error: cannot use opera
23 | _ := x + 5 23 | _ := x + 5
| ^ | ^
24 | } 24 | }
25 | f := Foo{Bar{Abc(0)}} 25 | mut f2 := Foo2{Bar2{Abc(0)}}
vlib/v/checker/tests/sum_type_mutable_cast_err.vv:27:14: error: cannot use operator `+` with `Abc` vlib/v/checker/tests/sum_type_mutable_cast_err.vv:27:8: error: undefined ident: `f`
25 | f := Foo{Bar{Abc(0)}} 25 | mut f2 := Foo2{Bar2{Abc(0)}}
26 | if f.b.a is int { 26 | if f2.b.a is int {
27 | _ := f.b.a + 5 27 | _ := f.b.a + 5
| ^ | ^
28 | } 28 | }
29 | mut f2 := Foo2{Bar2{Abc(0)}} 29 | }
vlib/v/checker/tests/sum_type_mutable_cast_err.vv:31:14: error: cannot use operator `+` with `Abc`
29 | mut f2 := Foo2{Bar2{Abc(0)}}
30 | if f2.b.a is int {
31 | _ := f.b.a + 5
| ^
32 | }
33 | }

View File

@ -22,10 +22,6 @@ fn main() {
if x is int { if x is int {
_ := x + 5 _ := x + 5
} }
f := Foo{Bar{Abc(0)}}
if f.b.a is int {
_ := f.b.a + 5
}
mut f2 := Foo2{Bar2{Abc(0)}} mut f2 := Foo2{Bar2{Abc(0)}}
if f2.b.a is int { if f2.b.a is int {
_ := f.b.a + 5 _ := f.b.a + 5

View File

@ -1740,8 +1740,10 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
// id_info := ident.var_info() // id_info := ident.var_info()
// var_type = id_info.typ // var_type = id_info.typ
blank_assign = left.kind == .blank_ident blank_assign = left.kind == .blank_ident
if left.info is ast.IdentVar { // TODO: temporary, remove this
share := (left.info as ast.IdentVar).share left_info := left.info
if left_info is ast.IdentVar {
share := left_info.share
if share == .shared_t { if share == .shared_t {
var_type = var_type.set_flag(.shared_f) var_type = var_type.set_flag(.shared_f)
} }
@ -3413,19 +3415,20 @@ fn (mut g Gen) ident(node ast.Ident) {
g.write('_const_') g.write('_const_')
} }
mut name := c_name(node.name) mut name := c_name(node.name)
if node.info is ast.IdentVar { // TODO: temporary, remove this
ident_var := node.info as ast.IdentVar node_info := node.info
if node_info is ast.IdentVar {
// x ?int // x ?int
// `x = 10` => `x.data = 10` (g.right_is_opt == false) // `x = 10` => `x.data = 10` (g.right_is_opt == false)
// `x = new_opt()` => `x = new_opt()` (g.right_is_opt == true) // `x = new_opt()` => `x = new_opt()` (g.right_is_opt == true)
// `println(x)` => `println(*(int*)x.data)` // `println(x)` => `println(*(int*)x.data)`
if ident_var.is_optional && !(g.is_assign_lhs && g.right_is_opt) { if node_info.is_optional && !(g.is_assign_lhs && g.right_is_opt) {
g.write('/*opt*/') g.write('/*opt*/')
styp := g.base_type(ident_var.typ) styp := g.base_type(node_info.typ)
g.write('(*($styp*)${name}.data)') g.write('(*($styp*)${name}.data)')
return return
} }
if !g.is_assign_lhs && ident_var.share == .shared_t { if !g.is_assign_lhs && node_info.share == .shared_t {
g.write('${name}.val') g.write('${name}.val')
return return
} }

View File

@ -304,10 +304,11 @@ fn (mut g Gen) comp_for(node ast.CompFor) {
} }
} else if node.kind == .fields { } else if node.kind == .fields {
// TODO add fields // TODO add fields
if sym.info is table.Struct { // TODO: temporary, remove this
info := sym.info as table.Struct sym_info := sym.info
mut fields := info.fields.filter(it.attrs.len == 0) if sym_info is table.Struct {
fields_with_attrs := info.fields.filter(it.attrs.len > 0) mut fields := sym_info.fields.filter(it.attrs.len == 0)
fields_with_attrs := sym_info.fields.filter(it.attrs.len > 0)
fields << fields_with_attrs fields << fields_with_attrs
if fields.len > 0 { if fields.len > 0 {
g.writeln('\tFieldData $node.val_var;') g.writeln('\tFieldData $node.val_var;')

View File

@ -216,6 +216,41 @@ fn test_match() {
} }
} }
type WrapperType = FoodWrapper | string
fn test_non_mut_ident_mut_selector_cast_match() {
w := WrapperType(FoodWrapper{Food(Eggs{'test'})})
match w {
FoodWrapper {
match w.food {
Eggs {
assert w.food.name + '2' == 'test2'
}
else {
assert false
}
}
}
else {
assert false
}
}
}
fn test_non_mut_ident_mut_selector_cast_if() {
w := WrapperType(FoodWrapper{Food(Eggs{'test'})})
if w is FoodWrapper {
if w.food is Eggs {
assert w.food.name + '2' == 'test2'
} else {
assert false
}
} else {
assert false
}
}
type Abc = int | string type Abc = int | string
fn test_string_cast_to_sumtype() { fn test_string_cast_to_sumtype() {