mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
checker: change 'fail_if_immutable(expr_ ast.Expr)' to 'fail_if_immutable(mut expr ast.Expr)' (#18811)
This commit is contained in:
parent
b3a6b73306
commit
17b576227f
@ -227,7 +227,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Make sure the variable is mutable
|
// 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) {
|
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())
|
c.error('cannot assign an Option value to a non-option variable', right.pos())
|
||||||
|
@ -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
|
// returns name and position of variable that needs write lock
|
||||||
// also sets `is_changed` to true (TODO update the name to reflect this?)
|
// 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 to_lock := '' // name of variable that needs lock
|
||||||
mut pos := token.Pos{} // and its position
|
mut pos := token.Pos{} // and its position
|
||||||
mut explicit_lock_needed := false
|
mut explicit_lock_needed := false
|
||||||
mut expr := unsafe { expr_ }
|
|
||||||
match mut expr {
|
match mut expr {
|
||||||
ast.CastExpr {
|
ast.CastExpr {
|
||||||
// TODO
|
// TODO
|
||||||
return '', expr.pos
|
return '', expr.pos
|
||||||
}
|
}
|
||||||
ast.ComptimeSelector {
|
ast.ComptimeSelector {
|
||||||
|
mut expr_left := expr.left
|
||||||
if mut expr.left is ast.Ident {
|
if mut expr.left is ast.Ident {
|
||||||
if mut expr.left.obj is ast.Var {
|
if mut expr.left.obj is ast.Var {
|
||||||
if expr.left.obj.ct_type_var != .generic_param {
|
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',
|
c.error('you have to create a handle and `lock` it to modify `shared` ${kind} element',
|
||||||
expr.left.pos().extend(expr.pos))
|
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 {
|
ast.ParExpr {
|
||||||
to_lock, pos = c.fail_if_immutable(expr.expr)
|
to_lock, pos = c.fail_if_immutable(mut expr.expr)
|
||||||
}
|
}
|
||||||
ast.PrefixExpr {
|
ast.PrefixExpr {
|
||||||
if expr.op == .mul && expr.right is ast.Ident {
|
if expr.op == .mul && expr.right is ast.Ident {
|
||||||
// Do not fail if dereference is immutable:
|
// Do not fail if dereference is immutable:
|
||||||
// `*x = foo()` doesn't modify `x`
|
// `*x = foo()` doesn't modify `x`
|
||||||
} else {
|
} else {
|
||||||
to_lock, pos = c.fail_if_immutable(expr.right)
|
to_lock, pos = c.fail_if_immutable(mut expr.right)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.PostfixExpr {
|
ast.PostfixExpr {
|
||||||
to_lock, pos = c.fail_if_immutable(expr.expr)
|
to_lock, pos = c.fail_if_immutable(mut expr.expr)
|
||||||
}
|
}
|
||||||
ast.SelectorExpr {
|
ast.SelectorExpr {
|
||||||
if expr.expr_type == 0 {
|
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',
|
c.error('field `${expr.field_name}` of struct `${type_str}` is immutable',
|
||||||
expr.pos)
|
expr.pos)
|
||||||
}
|
}
|
||||||
to_lock, pos = c.fail_if_immutable(expr.expr)
|
to_lock, pos = c.fail_if_immutable(mut expr.expr)
|
||||||
}
|
}
|
||||||
if to_lock != '' {
|
if to_lock != '' {
|
||||||
// No automatic lock for struct access
|
// 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)
|
expr.pos)
|
||||||
return '', expr.pos
|
return '', expr.pos
|
||||||
}
|
}
|
||||||
c.fail_if_immutable(expr.expr)
|
c.fail_if_immutable(mut expr.expr)
|
||||||
}
|
}
|
||||||
.sum_type {
|
.sum_type {
|
||||||
sumtype_info := typ_sym.info as ast.SumType
|
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)
|
expr.pos)
|
||||||
return '', expr.pos
|
return '', expr.pos
|
||||||
}
|
}
|
||||||
c.fail_if_immutable(expr.expr)
|
c.fail_if_immutable(mut expr.expr)
|
||||||
}
|
}
|
||||||
.array, .string {
|
.array, .string {
|
||||||
// should only happen in `builtin` and unsafe blocks
|
// 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 {
|
.aggregate, .placeholder {
|
||||||
c.fail_if_immutable(expr.expr)
|
c.fail_if_immutable(mut expr.expr)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
c.error('unexpected symbol `${typ_sym.kind}`', expr.pos)
|
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 {
|
ast.CallExpr {
|
||||||
// TODO: should only work for builtin method
|
// TODO: should only work for builtin method
|
||||||
if expr.name == 'slice' {
|
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 != '' {
|
if to_lock != '' {
|
||||||
// No automatic lock for array slicing (yet(?))
|
// No automatic lock for array slicing (yet(?))
|
||||||
explicit_lock_needed = true
|
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 {
|
for mut io in ios {
|
||||||
typ := c.expr(mut io.expr)
|
typ := c.expr(mut io.expr)
|
||||||
if output {
|
if output {
|
||||||
c.fail_if_immutable(io.expr)
|
c.fail_if_immutable(mut io.expr)
|
||||||
}
|
}
|
||||||
if io.alias != '' {
|
if io.alias != '' {
|
||||||
aliases << io.alias
|
aliases << io.alias
|
||||||
|
@ -1101,7 +1101,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
|
|||||||
call_arg.pos)
|
call_arg.pos)
|
||||||
}
|
}
|
||||||
if call_arg.is_mut {
|
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_lvalue() {
|
||||||
if call_arg.expr is ast.StructInit {
|
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}`',
|
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)
|
arg.pos)
|
||||||
}
|
}
|
||||||
if arg.is_mut {
|
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 {
|
if !param.is_mut {
|
||||||
tok := arg.share.str()
|
tok := arg.share.str()
|
||||||
c.error('`${node.name}` parameter ${i + 1} is not `${tok}`, `${tok}` is not needed`',
|
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)
|
node.pos)
|
||||||
}
|
}
|
||||||
if method.params[0].is_mut {
|
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() {
|
if !node.left.is_lvalue() {
|
||||||
c.error('cannot pass expression as `mut`', node.left.pos())
|
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)
|
arg.pos)
|
||||||
}
|
}
|
||||||
if arg.is_mut {
|
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 {
|
if !param_is_mut {
|
||||||
tok := arg.share.str()
|
tok := arg.share.str()
|
||||||
c.error('`${node.name}` parameter `${param.name}` is not `${tok}`, `${tok}` is not needed`',
|
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)
|
c.error('`.${method_name}()` does not have any arguments', node.args[0].pos)
|
||||||
}
|
}
|
||||||
if method_name[0] == `m` {
|
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) {
|
if node.left.is_auto_deref_var() || ret_type.has_flag(.shared_f) {
|
||||||
ret_type = left_type.deref()
|
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' {
|
'delete' {
|
||||||
c.fail_if_immutable(node.left)
|
c.fail_if_immutable(mut node.left)
|
||||||
if node.args.len != 1 {
|
if node.args.len != 1 {
|
||||||
c.error('expected 1 argument, but got ${node.args.len}', node.pos)
|
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',
|
c.error('the `sort()` method can be called only on mutable receivers, but `${node.left}` is a call expression',
|
||||||
node.pos)
|
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
|
// position of `a` and `b` doesn't matter, they're the same
|
||||||
scope_register_a_b(mut node.scope, node.pos, elem_typ)
|
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
|
node.return_type = array_info.elem_type
|
||||||
if method_name == 'pop' {
|
if method_name == 'pop' {
|
||||||
c.fail_if_immutable(node.left)
|
c.fail_if_immutable(mut node.left)
|
||||||
node.receiver_type = left_type.ref()
|
node.receiver_type = left_type.ref()
|
||||||
} else {
|
} else {
|
||||||
node.receiver_type = left_type
|
node.receiver_type = left_type
|
||||||
}
|
}
|
||||||
} else if method_name == 'delete' {
|
} 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))
|
unwrapped_left_sym := c.table.sym(c.unwrap_generic(left_type))
|
||||||
if method := c.table.find_method(unwrapped_left_sym, method_name) {
|
if method := c.table.find_method(unwrapped_left_sym, method_name) {
|
||||||
node.receiver_type = method.receiver_type
|
node.receiver_type = method.receiver_type
|
||||||
|
@ -509,7 +509,7 @@ fn (mut c Checker) smartcast_if_conds(mut node ast.Expr, mut scope ast.Scope) {
|
|||||||
if is_variable {
|
if is_variable {
|
||||||
if (node.left is ast.Ident && node.left.is_mut)
|
if (node.left is ast.Ident && node.left.is_mut)
|
||||||
|| (node.left is ast.SelectorExpr && 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
|
// 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
|
if mut node.left is ast.Ident
|
||||||
|
@ -505,7 +505,7 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
|||||||
}
|
}
|
||||||
// `array << elm`
|
// `array << elm`
|
||||||
c.check_expr_opt_call(node.right, right_type)
|
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_type := c.table.value_type(c.unwrap_generic(left_type))
|
||||||
left_value_sym := c.table.sym(c.unwrap_generic(left_value_type))
|
left_value_sym := c.table.sym(c.unwrap_generic(left_value_type))
|
||||||
if left_value_sym.kind == .interface_ {
|
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 {
|
if chan_info.is_mut {
|
||||||
// TODO: The error message of the following could be more specific...
|
// 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() {
|
if elem_type.is_ptr() && !right_type.is_ptr() {
|
||||||
c.error('cannot push non-reference `${right_sym.name}` on `${left_sym.name}`',
|
c.error('cannot push non-reference `${right_sym.name}` on `${left_sym.name}`',
|
||||||
|
@ -24,7 +24,7 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
|
|||||||
node.cond_type = ast.mktyp(cond_type)
|
node.cond_type = ast.mktyp(cond_type)
|
||||||
if (node.cond is ast.Ident && node.cond.is_mut)
|
if (node.cond is ast.Ident && node.cond.is_mut)
|
||||||
|| (node.cond is ast.SelectorExpr && 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.ensure_type_exists(node.cond_type, node.pos) or { return ast.void_type }
|
||||||
c.check_expr_opt_call(node.cond, cond_type)
|
c.check_expr_opt_call(node.cond, cond_type)
|
||||||
|
@ -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}`)',
|
c.error('invalid operation: ${node.op.str()} (non-numeric type `${typ_str}`)',
|
||||||
node.pos)
|
node.pos)
|
||||||
} else {
|
} else {
|
||||||
node.auto_locked, _ = c.fail_if_immutable(node.expr)
|
node.auto_locked, _ = c.fail_if_immutable(mut node.expr)
|
||||||
}
|
}
|
||||||
node.typ = typ
|
node.typ = typ
|
||||||
return typ
|
return typ
|
||||||
|
Loading…
Reference in New Issue
Block a user