diff --git a/vlib/v/checker/assign.v b/vlib/v/checker/assign.v index 5f0b08a38c..03197237c7 100644 --- a/vlib/v/checker/assign.v +++ b/vlib/v/checker/assign.v @@ -227,7 +227,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { } } else { // Make sure the variable is mutable - c.fail_if_immutable(left) + c.fail_if_immutable(mut left) if !is_blank_ident && !left_type.has_flag(.option) && right_type.has_flag(.option) { c.error('cannot assign an Option value to a non-option variable', right.pos()) diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 725cc093d8..2ffbe0e471 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -661,21 +661,21 @@ fn (mut c Checker) expand_iface_embeds(idecl &ast.InterfaceDecl, level int, ifac // returns name and position of variable that needs write lock // also sets `is_changed` to true (TODO update the name to reflect this?) -fn (mut c Checker) fail_if_immutable(expr_ ast.Expr) (string, token.Pos) { +fn (mut c Checker) fail_if_immutable(mut expr ast.Expr) (string, token.Pos) { mut to_lock := '' // name of variable that needs lock mut pos := token.Pos{} // and its position mut explicit_lock_needed := false - mut expr := unsafe { expr_ } match mut expr { ast.CastExpr { // TODO return '', expr.pos } ast.ComptimeSelector { + mut expr_left := expr.left if mut expr.left is ast.Ident { if mut expr.left.obj is ast.Var { if expr.left.obj.ct_type_var != .generic_param { - c.fail_if_immutable(expr.left) + c.fail_if_immutable(mut expr_left) } } } @@ -735,21 +735,21 @@ fn (mut c Checker) fail_if_immutable(expr_ ast.Expr) (string, token.Pos) { c.error('you have to create a handle and `lock` it to modify `shared` ${kind} element', expr.left.pos().extend(expr.pos)) } - to_lock, pos = c.fail_if_immutable(expr.left) + to_lock, pos = c.fail_if_immutable(mut expr.left) } ast.ParExpr { - to_lock, pos = c.fail_if_immutable(expr.expr) + to_lock, pos = c.fail_if_immutable(mut expr.expr) } ast.PrefixExpr { if expr.op == .mul && expr.right is ast.Ident { // Do not fail if dereference is immutable: // `*x = foo()` doesn't modify `x` } else { - to_lock, pos = c.fail_if_immutable(expr.right) + to_lock, pos = c.fail_if_immutable(mut expr.right) } } ast.PostfixExpr { - to_lock, pos = c.fail_if_immutable(expr.expr) + to_lock, pos = c.fail_if_immutable(mut expr.expr) } ast.SelectorExpr { if expr.expr_type == 0 { @@ -792,7 +792,7 @@ fn (mut c Checker) fail_if_immutable(expr_ ast.Expr) (string, token.Pos) { c.error('field `${expr.field_name}` of struct `${type_str}` is immutable', expr.pos) } - to_lock, pos = c.fail_if_immutable(expr.expr) + to_lock, pos = c.fail_if_immutable(mut expr.expr) } if to_lock != '' { // No automatic lock for struct access @@ -812,7 +812,7 @@ fn (mut c Checker) fail_if_immutable(expr_ ast.Expr) (string, token.Pos) { expr.pos) return '', expr.pos } - c.fail_if_immutable(expr.expr) + c.fail_if_immutable(mut expr.expr) } .sum_type { sumtype_info := typ_sym.info as ast.SumType @@ -827,7 +827,7 @@ fn (mut c Checker) fail_if_immutable(expr_ ast.Expr) (string, token.Pos) { expr.pos) return '', expr.pos } - c.fail_if_immutable(expr.expr) + c.fail_if_immutable(mut expr.expr) } .array, .string { // should only happen in `builtin` and unsafe blocks @@ -838,7 +838,7 @@ fn (mut c Checker) fail_if_immutable(expr_ ast.Expr) (string, token.Pos) { } } .aggregate, .placeholder { - c.fail_if_immutable(expr.expr) + c.fail_if_immutable(mut expr.expr) } else { c.error('unexpected symbol `${typ_sym.kind}`', expr.pos) @@ -849,7 +849,7 @@ fn (mut c Checker) fail_if_immutable(expr_ ast.Expr) (string, token.Pos) { ast.CallExpr { // TODO: should only work for builtin method if expr.name == 'slice' { - to_lock, pos = c.fail_if_immutable(expr.left) + to_lock, pos = c.fail_if_immutable(mut expr.left) if to_lock != '' { // No automatic lock for array slicing (yet(?)) explicit_lock_needed = true @@ -2153,7 +2153,7 @@ fn (mut c Checker) asm_ios(mut ios []ast.AsmIO, mut scope ast.Scope, output bool for mut io in ios { typ := c.expr(mut io.expr) if output { - c.fail_if_immutable(io.expr) + c.fail_if_immutable(mut io.expr) } if io.alias != '' { aliases << io.alias diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 5df0b49674..7a97ae05d9 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -1101,7 +1101,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast. call_arg.pos) } if call_arg.is_mut { - to_lock, pos := c.fail_if_immutable(call_arg.expr) + to_lock, pos := c.fail_if_immutable(mut call_arg.expr) if !call_arg.expr.is_lvalue() { if call_arg.expr is ast.StructInit { c.error('cannot pass a struct initialization as `mut`, you may want to use a variable `mut var := ${call_arg.expr}`', @@ -1744,7 +1744,7 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type { arg.pos) } if arg.is_mut { - to_lock, pos := c.fail_if_immutable(arg.expr) + to_lock, pos := c.fail_if_immutable(mut arg.expr) if !param.is_mut { tok := arg.share.str() c.error('`${node.name}` parameter ${i + 1} is not `${tok}`, `${tok}` is not needed`', @@ -1846,7 +1846,7 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type { node.pos) } if method.params[0].is_mut { - to_lock, pos := c.fail_if_immutable(node.left) + to_lock, pos := c.fail_if_immutable(mut node.left) if !node.left.is_lvalue() { c.error('cannot pass expression as `mut`', node.left.pos()) } @@ -1968,7 +1968,7 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type { arg.pos) } if arg.is_mut { - to_lock, pos := c.fail_if_immutable(arg.expr) + to_lock, pos := c.fail_if_immutable(mut arg.expr) if !param_is_mut { tok := arg.share.str() c.error('`${node.name}` parameter `${param.name}` is not `${tok}`, `${tok}` is not needed`', @@ -2426,7 +2426,7 @@ fn (mut c Checker) map_builtin_method_call(mut node ast.CallExpr, left_type ast. c.error('`.${method_name}()` does not have any arguments', node.args[0].pos) } if method_name[0] == `m` { - c.fail_if_immutable(node.left) + c.fail_if_immutable(mut node.left) } if node.left.is_auto_deref_var() || ret_type.has_flag(.shared_f) { ret_type = left_type.deref() @@ -2454,7 +2454,7 @@ fn (mut c Checker) map_builtin_method_call(mut node ast.CallExpr, left_type ast. } } 'delete' { - c.fail_if_immutable(node.left) + c.fail_if_immutable(mut node.left) if node.args.len != 1 { c.error('expected 1 argument, but got ${node.args.len}', node.pos) } @@ -2491,7 +2491,7 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as c.error('the `sort()` method can be called only on mutable receivers, but `${node.left}` is a call expression', node.pos) } - c.fail_if_immutable(node.left) + c.fail_if_immutable(mut node.left) // position of `a` and `b` doesn't matter, they're the same scope_register_a_b(mut node.scope, node.pos, elem_typ) @@ -2635,13 +2635,13 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as } node.return_type = array_info.elem_type if method_name == 'pop' { - c.fail_if_immutable(node.left) + c.fail_if_immutable(mut node.left) node.receiver_type = left_type.ref() } else { node.receiver_type = left_type } } else if method_name == 'delete' { - c.fail_if_immutable(node.left) + c.fail_if_immutable(mut node.left) unwrapped_left_sym := c.table.sym(c.unwrap_generic(left_type)) if method := c.table.find_method(unwrapped_left_sym, method_name) { node.receiver_type = method.receiver_type diff --git a/vlib/v/checker/if.v b/vlib/v/checker/if.v index 37617fd42a..4755ef4514 100644 --- a/vlib/v/checker/if.v +++ b/vlib/v/checker/if.v @@ -509,7 +509,7 @@ fn (mut c Checker) smartcast_if_conds(mut node ast.Expr, mut scope ast.Scope) { if is_variable { if (node.left is ast.Ident && node.left.is_mut) || (node.left is ast.SelectorExpr && node.left.is_mut) { - c.fail_if_immutable(node.left) + c.fail_if_immutable(mut node.left) } // TODO: Add check for sum types in a way that it doesn't break a lot of compiler code if mut node.left is ast.Ident diff --git a/vlib/v/checker/infix.v b/vlib/v/checker/infix.v index d7cff72393..13dcdb6057 100644 --- a/vlib/v/checker/infix.v +++ b/vlib/v/checker/infix.v @@ -505,7 +505,7 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { } // `array << elm` c.check_expr_opt_call(node.right, right_type) - node.auto_locked, _ = c.fail_if_immutable(node.left) + node.auto_locked, _ = c.fail_if_immutable(mut node.left) left_value_type := c.table.value_type(c.unwrap_generic(left_type)) left_value_sym := c.table.sym(c.unwrap_generic(left_value_type)) if left_value_sym.kind == .interface_ { @@ -661,7 +661,7 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { } if chan_info.is_mut { // TODO: The error message of the following could be more specific... - c.fail_if_immutable(node.right) + c.fail_if_immutable(mut node.right) } if elem_type.is_ptr() && !right_type.is_ptr() { c.error('cannot push non-reference `${right_sym.name}` on `${left_sym.name}`', diff --git a/vlib/v/checker/match.v b/vlib/v/checker/match.v index 4f21a92c10..48404b0d1c 100644 --- a/vlib/v/checker/match.v +++ b/vlib/v/checker/match.v @@ -24,7 +24,7 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type { node.cond_type = ast.mktyp(cond_type) if (node.cond is ast.Ident && node.cond.is_mut) || (node.cond is ast.SelectorExpr && node.cond.is_mut) { - c.fail_if_immutable(node.cond) + c.fail_if_immutable(mut node.cond) } c.ensure_type_exists(node.cond_type, node.pos) or { return ast.void_type } c.check_expr_opt_call(node.cond, cond_type) diff --git a/vlib/v/checker/postfix.v b/vlib/v/checker/postfix.v index 3fbe4a82ee..e4628f5478 100644 --- a/vlib/v/checker/postfix.v +++ b/vlib/v/checker/postfix.v @@ -37,7 +37,7 @@ fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) ast.Type { c.error('invalid operation: ${node.op.str()} (non-numeric type `${typ_str}`)', node.pos) } else { - node.auto_locked, _ = c.fail_if_immutable(node.expr) + node.auto_locked, _ = c.fail_if_immutable(mut node.expr) } node.typ = typ return typ