checker: fix smartcast inside smartcast (#7215)
parent
4a35a75b64
commit
a38fe4fca9
|
@ -114,6 +114,16 @@ pub mut:
|
|||
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
|
||||
pub struct Module {
|
||||
pub:
|
||||
|
|
|
@ -2977,9 +2977,10 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
|||
mut is_mut := false
|
||||
if mut node.right.left is ast.Ident {
|
||||
ident := node.right.left
|
||||
if ident.obj is ast.Var {
|
||||
v := ident.obj as ast.Var
|
||||
is_mut = v.is_mut
|
||||
// TODO: temporary, remove this
|
||||
ident_obj := ident.obj
|
||||
if ident_obj is ast.Var {
|
||||
is_mut = ident_obj.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{}
|
||||
expr_sym := c.table.get_type_symbol(node.cond.expr_type)
|
||||
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) {
|
||||
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 }
|
||||
// Register shadow variable or `as` variable with actual type
|
||||
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] {
|
||||
mut is_mut := false
|
||||
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{}
|
||||
expr_sym := c.table.get_type_symbol(infix.left.expr_type)
|
||||
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,
|
||||
infix.left.field_name) {
|
||||
|
|
|
@ -4,18 +4,11 @@ vlib/v/checker/tests/sum_type_mutable_cast_err.vv:23:10: error: cannot use opera
|
|||
23 | _ := x + 5
|
||||
| ^
|
||||
24 | }
|
||||
25 | f := Foo{Bar{Abc(0)}}
|
||||
vlib/v/checker/tests/sum_type_mutable_cast_err.vv:27:14: error: cannot use operator `+` with `Abc`
|
||||
25 | f := Foo{Bar{Abc(0)}}
|
||||
26 | if f.b.a is int {
|
||||
25 | mut f2 := Foo2{Bar2{Abc(0)}}
|
||||
vlib/v/checker/tests/sum_type_mutable_cast_err.vv:27:8: error: undefined ident: `f`
|
||||
25 | mut f2 := Foo2{Bar2{Abc(0)}}
|
||||
26 | if f2.b.a is int {
|
||||
27 | _ := f.b.a + 5
|
||||
| ^
|
||||
| ^
|
||||
28 | }
|
||||
29 | mut f2 := Foo2{Bar2{Abc(0)}}
|
||||
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 | }
|
||||
29 | }
|
|
@ -22,10 +22,6 @@ fn main() {
|
|||
if x is int {
|
||||
_ := x + 5
|
||||
}
|
||||
f := Foo{Bar{Abc(0)}}
|
||||
if f.b.a is int {
|
||||
_ := f.b.a + 5
|
||||
}
|
||||
mut f2 := Foo2{Bar2{Abc(0)}}
|
||||
if f2.b.a is int {
|
||||
_ := f.b.a + 5
|
||||
|
|
|
@ -1740,8 +1740,10 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
// id_info := ident.var_info()
|
||||
// var_type = id_info.typ
|
||||
blank_assign = left.kind == .blank_ident
|
||||
if left.info is ast.IdentVar {
|
||||
share := (left.info as ast.IdentVar).share
|
||||
// TODO: temporary, remove this
|
||||
left_info := left.info
|
||||
if left_info is ast.IdentVar {
|
||||
share := left_info.share
|
||||
if share == .shared_t {
|
||||
var_type = var_type.set_flag(.shared_f)
|
||||
}
|
||||
|
@ -3413,19 +3415,20 @@ fn (mut g Gen) ident(node ast.Ident) {
|
|||
g.write('_const_')
|
||||
}
|
||||
mut name := c_name(node.name)
|
||||
if node.info is ast.IdentVar {
|
||||
ident_var := node.info as ast.IdentVar
|
||||
// TODO: temporary, remove this
|
||||
node_info := node.info
|
||||
if node_info is ast.IdentVar {
|
||||
// x ?int
|
||||
// `x = 10` => `x.data = 10` (g.right_is_opt == false)
|
||||
// `x = new_opt()` => `x = new_opt()` (g.right_is_opt == true)
|
||||
// `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*/')
|
||||
styp := g.base_type(ident_var.typ)
|
||||
styp := g.base_type(node_info.typ)
|
||||
g.write('(*($styp*)${name}.data)')
|
||||
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')
|
||||
return
|
||||
}
|
||||
|
|
|
@ -304,10 +304,11 @@ fn (mut g Gen) comp_for(node ast.CompFor) {
|
|||
}
|
||||
} else if node.kind == .fields {
|
||||
// TODO add fields
|
||||
if sym.info is table.Struct {
|
||||
info := sym.info as table.Struct
|
||||
mut fields := info.fields.filter(it.attrs.len == 0)
|
||||
fields_with_attrs := info.fields.filter(it.attrs.len > 0)
|
||||
// TODO: temporary, remove this
|
||||
sym_info := sym.info
|
||||
if sym_info is table.Struct {
|
||||
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
|
||||
if fields.len > 0 {
|
||||
g.writeln('\tFieldData $node.val_var;')
|
||||
|
|
|
@ -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
|
||||
|
||||
fn test_string_cast_to_sumtype() {
|
||||
|
|
Loading…
Reference in New Issue