checker: fix error for if mut with immutable variable (#13728)

pull/13733/head
yuyi 2022-03-13 22:33:50 +08:00 committed by GitHub
parent 9495aacf3e
commit f7feb634d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 61 additions and 29 deletions

View File

@ -624,7 +624,6 @@ pub struct Stmt {
pub struct Var {
pub:
name string
expr Expr
share ShareType
is_mut bool
is_autofree_tmp bool
@ -632,6 +631,7 @@ pub:
is_auto_deref bool
is_inherited bool
pub mut:
expr Expr
typ Type
orig_type Type // original sumtype type; 0 if it's not a sumtype
smartcasts []Type // nested sum types require nested smart casting, for that a list of types is needed
@ -997,7 +997,6 @@ pub struct ForInStmt {
pub:
key_var string
val_var string
cond Expr
is_range bool
high Expr // `10` in `for i in 0..10 {`
stmts []Stmt
@ -1005,6 +1004,7 @@ pub:
val_is_mut bool // `for mut val in vals {` means that modifying `val` will modify the array
// and the array cannot be indexed inside the loop
pub mut:
cond Expr
key_type Type
val_type Type
cond_type Type

View File

@ -16,7 +16,7 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
node.left_types = []
mut right_len := node.right.len
mut right_type0 := ast.void_type
for i, right in node.right {
for i, mut right in node.right {
if right in [ast.CallExpr, ast.IfExpr, ast.LockExpr, ast.MatchExpr] {
if right in [ast.IfExpr, ast.MatchExpr] && node.left.len == node.right.len && !is_decl
&& node.left[i] in [ast.Ident, ast.SelectorExpr] && !node.left[i].is_blank_ident() {
@ -41,18 +41,18 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
right_len = 0
}
}
if right is ast.InfixExpr {
if mut right is ast.InfixExpr {
if right.op == .arrow {
c.error('cannot use `<-` on the right-hand side of an assignment, as it does not return any values',
right.pos)
}
}
if right is ast.Ident {
if mut right is ast.Ident {
if right.is_mut {
c.error('unexpected `mut` on right-hand side of assignment', right.mut_pos)
}
}
if right is ast.None {
if mut right is ast.None {
c.error('you can not assign a `none` value to a variable', right.pos)
}
}
@ -112,9 +112,9 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
node.right_types << c.check_expr_opt_call(node.right[i], right_type)
}
}
right := if i < node.right.len { node.right[i] } else { node.right[0] }
mut right := if i < node.right.len { node.right[i] } else { node.right[0] }
mut right_type := node.right_types[i]
if right is ast.Ident {
if mut right is ast.Ident {
right_sym := c.table.sym(right_type)
if right_sym.info is ast.Struct {
if right_sym.info.generic_types.len > 0 {
@ -128,12 +128,12 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
}
if is_decl {
// check generic struct init and return unwrap generic struct type
if right is ast.StructInit {
if mut right is ast.StructInit {
if right.typ.has_flag(.generic) {
c.expr(right)
right_type = right.typ
}
} else if right is ast.PrefixExpr {
} else if mut right is ast.PrefixExpr {
if right.op == .amp && right.right is ast.StructInit {
right_type = c.expr(right)
}
@ -144,7 +144,7 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
left_type = ast.mktyp(right_type)
}
if left_type == ast.int_type {
if right is ast.IntegerLiteral {
if mut right is ast.IntegerLiteral {
mut is_large := right.val.len > 13
if !is_large && right.val.len > 8 {
val := right.val.i64()
@ -244,7 +244,7 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
}
}
if left_type in ast.unsigned_integer_type_idxs {
if right is ast.IntegerLiteral {
if mut right is ast.IntegerLiteral {
if right.val[0] == `-` {
c.error('Cannot assign negative value to unsigned integer type',
right.pos)

View File

@ -3280,10 +3280,11 @@ pub fn (mut c Checker) concat_expr(mut node ast.ConcatExpr) ast.Type {
}
// smartcast takes the expression with the current type which should be smartcasted to the target type in the given scope
fn (mut c Checker) smartcast(expr ast.Expr, cur_type ast.Type, to_type_ ast.Type, mut scope ast.Scope) {
fn (mut c Checker) smartcast(expr_ ast.Expr, cur_type ast.Type, to_type_ ast.Type, mut scope ast.Scope) {
sym := c.table.sym(cur_type)
to_type := if sym.kind == .interface_ { to_type_.ref() } else { to_type_ }
match expr {
mut expr := unsafe { expr_ }
match mut expr {
ast.SelectorExpr {
mut is_mut := false
mut smartcasts := []ast.Type{}

View File

@ -102,7 +102,7 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
}
if node.val_is_mut {
value_type = value_type.ref()
match node.cond {
match mut node.cond {
ast.Ident {
if mut node.cond.obj is ast.Var {
if !node.cond.obj.is_mut {

View File

@ -309,12 +309,17 @@ fn (mut c Checker) smartcast_if_conds(node ast.Expr, mut scope ast.Scope) {
c.error('cannot use type `$expect_str` as type `$expr_str`', node.pos)
}
if node.left in [ast.Ident, ast.SelectorExpr] && node.right is ast.TypeNode {
is_variable := if mut node.left is ast.Ident {
is_variable := if node.left is ast.Ident {
node.left.kind == .variable
} else {
true
}
if is_variable {
if (node.left is ast.Ident && (node.left as ast.Ident).is_mut)
|| (node.left is ast.SelectorExpr
&& (node.left as ast.SelectorExpr).is_mut) {
c.fail_if_immutable(node.left)
}
if left_sym.kind in [.interface_, .sum_type] {
c.smartcast(node.left, node.left_type, right_type, mut scope)
}

View File

@ -237,7 +237,7 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym ast.TypeSym
}
}
}
} else if mut cond_type_sym.info is ast.SumType {
} else if cond_type_sym.info is ast.SumType {
if expr_type !in cond_type_sym.info.variants {
expr_str := c.table.type_to_str(expr_type)
expect_str := c.table.type_to_str(node.cond_type)

View File

@ -0,0 +1,14 @@
vlib/v/checker/tests/if_mut_with_immutable_var_err.vv:5:9: error: `i` is immutable, declare it with `mut` to make it mutable
3 | fn main() {
4 | i := Int(0)
5 | if mut i is int {
| ^
6 | i = 1
7 | } else if mut i is byte {
vlib/v/checker/tests/if_mut_with_immutable_var_err.vv:7:16: error: `i` is immutable, declare it with `mut` to make it mutable
5 | if mut i is int {
6 | i = 1
7 | } else if mut i is byte {
| ^
8 | i = 2
9 | }

View File

@ -0,0 +1,11 @@
type Int = byte | int
fn main() {
i := Int(0)
if mut i is int {
i = 1
} else if mut i is byte {
i = 2
}
println(i)
}

View File

@ -1803,7 +1803,7 @@ pub fn (mut f Fmt) enum_val(node ast.EnumVal) {
}
pub fn (mut f Fmt) ident(node ast.Ident) {
if mut node.info is ast.IdentVar {
if node.info is ast.IdentVar {
if node.info.is_mut {
f.write(node.info.share.str() + ' ')
}

View File

@ -7,7 +7,8 @@ import v.ast
import v.util
import v.token
fn (mut g Gen) gen_assign_stmt(node ast.AssignStmt) {
fn (mut g Gen) gen_assign_stmt(node_ ast.AssignStmt) {
mut node := unsafe { node_ }
if node.is_static {
g.write('static ')
}
@ -88,7 +89,7 @@ fn (mut g Gen) gen_assign_stmt(node ast.AssignStmt) {
g.checker_bug('node.left_types.len < node.left.len', node.pos)
}
for i, left in node.left {
for i, mut left in node.left {
mut is_auto_heap := false
mut var_type := node.left_types[i]
mut val_type := node.right_types[i]
@ -163,7 +164,7 @@ fn (mut g Gen) gen_assign_stmt(node ast.AssignStmt) {
g.expr(left)
g.is_assign_lhs = false
g.is_arraymap_set = false
if left is ast.IndexExpr {
if mut left is ast.IndexExpr {
sym := g.table.sym(left.left_type)
if sym.kind in [.map, .array] {
g.expr(val)

View File

@ -3235,7 +3235,7 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
dot := if field.typ.is_ptr() { '->' } else { '.' }
sum_type_deref_field += ')$dot'
}
if mut cast_sym.info is ast.Aggregate {
if cast_sym.info is ast.Aggregate {
agg_sym := g.table.sym(cast_sym.info.types[g.aggregate_type_idx])
sum_type_deref_field += '_$agg_sym.cname'
} else {
@ -3695,7 +3695,7 @@ fn (mut g Gen) ident(node ast.Ident) {
}
}
dot := if is_ptr || is_auto_heap { '->' } else { '.' }
if mut cast_sym.info is ast.Aggregate {
if cast_sym.info is ast.Aggregate {
sym := g.table.sym(cast_sym.info.types[g.aggregate_type_idx])
g.write('${dot}_$sym.cname')
} else {

View File

@ -1342,7 +1342,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
}
}
dot := if is_ptr { '->' } else { '.' }
if mut cast_sym.info is ast.Aggregate {
if cast_sym.info is ast.Aggregate {
sym := g.table.sym(cast_sym.info.types[g.aggregate_type_idx])
g.write('${dot}_$sym.cname')
} else {

View File

@ -373,7 +373,7 @@ fn (mut g Gen) infix_expr_in_op(node ast.InfixExpr) {
}
if right.unaliased_sym.kind == .array {
if left.sym.kind in [.sum_type, .interface_] {
if mut node.right is ast.ArrayInit {
if node.right is ast.ArrayInit {
if node.right.exprs.len > 0 {
mut infix_exprs := []ast.InfixExpr{}
for i in 0 .. node.right.exprs.len {
@ -392,7 +392,7 @@ fn (mut g Gen) infix_expr_in_op(node ast.InfixExpr) {
}
}
}
if mut node.right is ast.ArrayInit {
if node.right is ast.ArrayInit {
if node.right.exprs.len > 0 {
// `a in [1,2,3]` optimization => `a == 1 || a == 2 || a == 3`
// avoids an allocation

View File

@ -200,7 +200,7 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
// fn (mut g Gen) str_int2(node ast.StringInterLiteral) {
if g.inside_comptime_for_field {
mut node_ := unsafe { node }
for i, expr in node_.exprs {
for i, mut expr in node_.exprs {
if mut expr is ast.Ident {
if mut expr.obj is ast.Var {
node_.expr_types[i] = expr.obj.typ

View File

@ -259,10 +259,10 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall {
mut file := parse_comptime(v_code, p.table, p.pref, scope)
file.path = tmpl_path
// copy vars from current fn scope into vweb_tmpl scope
for stmt in file.stmts {
for mut stmt in file.stmts {
if mut stmt is ast.FnDecl {
if stmt.name == 'main.vweb_tmpl_$tmp_fn_name' {
for _, obj in p.scope.objects {
for _, mut obj in p.scope.objects {
if mut obj is ast.Var {
stmt.scope.register(ast.Var{
...obj