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`
|
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:
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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 | }
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;')
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
Loading…
Reference in New Issue