mirror of
https://github.com/vlang/v.git
synced 2025-09-18 11:56:57 -04:00
checker: fix checking of expression as mut receiver, when calling methods of arrays/maps (#20410)
This commit is contained in:
parent
a321ef694b
commit
3d8425dafd
@ -2066,10 +2066,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(mut node.left)
|
to_lock, pos := c.check_for_mut_receiver(mut node.left)
|
||||||
if !node.left.is_lvalue() {
|
|
||||||
c.error('cannot pass expression as `mut`', node.left.pos())
|
|
||||||
}
|
|
||||||
// node.is_mut = true
|
// node.is_mut = true
|
||||||
if to_lock != '' && rec_share != .shared_t {
|
if to_lock != '' && rec_share != .shared_t {
|
||||||
c.error('${to_lock} is `shared` and must be `lock`ed to be passed as `mut`',
|
c.error('${to_lock} is `shared` and must be `lock`ed to be passed as `mut`',
|
||||||
@ -2684,7 +2681,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(mut node.left)
|
c.check_for_mut_receiver(mut node.left)
|
||||||
}
|
}
|
||||||
if node.left.is_auto_deref_var() || left_type.has_flag(.shared_f) {
|
if node.left.is_auto_deref_var() || left_type.has_flag(.shared_f) {
|
||||||
ret_type = node.left_type.deref()
|
ret_type = node.left_type.deref()
|
||||||
@ -2712,7 +2709,7 @@ fn (mut c Checker) map_builtin_method_call(mut node ast.CallExpr, left_type_ ast
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
'delete' {
|
'delete' {
|
||||||
c.fail_if_immutable(mut node.left)
|
c.check_for_mut_receiver(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)
|
||||||
}
|
}
|
||||||
@ -2789,7 +2786,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(mut node.left)
|
c.check_for_mut_receiver(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)
|
||||||
@ -2943,13 +2940,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(mut node.left)
|
c.check_for_mut_receiver(mut node.left)
|
||||||
node.receiver_type = node.left_type.ref()
|
node.receiver_type = node.left_type.ref()
|
||||||
} else {
|
} else {
|
||||||
node.receiver_type = node.left_type
|
node.receiver_type = node.left_type
|
||||||
}
|
}
|
||||||
} else if method_name == 'delete' {
|
} else if method_name == 'delete' {
|
||||||
c.fail_if_immutable(mut node.left)
|
c.check_for_mut_receiver(mut node.left)
|
||||||
unwrapped_left_sym := c.table.sym(unwrapped_left_type)
|
unwrapped_left_sym := c.table.sym(unwrapped_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
|
||||||
@ -2959,6 +2956,14 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as
|
|||||||
return node.return_type
|
return node.return_type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut c Checker) check_for_mut_receiver(mut expr ast.Expr) (string, token.Pos) {
|
||||||
|
to_lock, pos := c.fail_if_immutable(mut expr)
|
||||||
|
if !expr.is_lvalue() {
|
||||||
|
c.error('cannot pass expression as `mut`', expr.pos())
|
||||||
|
}
|
||||||
|
return to_lock, pos
|
||||||
|
}
|
||||||
|
|
||||||
fn scope_register_it(mut s ast.Scope, pos token.Pos, typ ast.Type) {
|
fn scope_register_it(mut s ast.Scope, pos token.Pos, typ ast.Type) {
|
||||||
scope_register_var_name(mut s, pos, typ, 'it')
|
scope_register_var_name(mut s, pos, typ, 'it')
|
||||||
}
|
}
|
||||||
|
@ -4,3 +4,9 @@ vlib/v/checker/tests/fn_return_array_sort_err.vv:6:14: error: the `sort()` metho
|
|||||||
6 | ret_array().sort()
|
6 | ret_array().sort()
|
||||||
| ~~~~~~
|
| ~~~~~~
|
||||||
7 | }
|
7 | }
|
||||||
|
vlib/v/checker/tests/fn_return_array_sort_err.vv:6:2: error: cannot pass expression as `mut`
|
||||||
|
4 |
|
||||||
|
5 | fn main() {
|
||||||
|
6 | ret_array().sort()
|
||||||
|
| ~~~~~~~~~~~
|
||||||
|
7 | }
|
||||||
|
@ -1,5 +1,20 @@
|
|||||||
vlib/v/checker/tests/mut_receiver_lit.vv:10:1: error: cannot pass expression as `mut`
|
vlib/v/checker/tests/mut_receiver_lit.vv:12:2: error: cannot pass expression as `mut`
|
||||||
8 | }
|
10 |
|
||||||
9 |
|
11 | fn non_mut_receiver() {
|
||||||
10 | Box{}.set(0)
|
12 | Box{}.set(0)
|
||||||
| ~~~~~
|
| ~~~~~
|
||||||
|
13 | }
|
||||||
|
14 |
|
||||||
|
vlib/v/checker/tests/mut_receiver_lit.vv:18:11: error: cannot pass expression as `mut`
|
||||||
|
16 | fn array_chained_method_calls() {
|
||||||
|
17 | path := 'hello/file.txt'
|
||||||
|
18 | _ = path.split('.').pop()
|
||||||
|
| ~~~~~~~~~~
|
||||||
|
19 | }
|
||||||
|
20 |
|
||||||
|
vlib/v/checker/tests/mut_receiver_lit.vv:24:4: error: cannot pass expression as `mut`
|
||||||
|
22 | fn map_chained_method_calls() {
|
||||||
|
23 | mut m := map[int]int{}
|
||||||
|
24 | m.clone().delete(0)
|
||||||
|
| ~~~~~~~
|
||||||
|
25 | }
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// error in non-mut as receover
|
||||||
struct Box {
|
struct Box {
|
||||||
mut:
|
mut:
|
||||||
value int
|
value int
|
||||||
@ -7,4 +8,18 @@ fn (mut box Box) set(value int) {
|
|||||||
box.value = value
|
box.value = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn non_mut_receiver() {
|
||||||
Box{}.set(0)
|
Box{}.set(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// error in array chained method calls
|
||||||
|
fn array_chained_method_calls() {
|
||||||
|
path := 'hello/file.txt'
|
||||||
|
_ = path.split('.').pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// error in map chained method calls
|
||||||
|
fn map_chained_method_calls() {
|
||||||
|
mut m := map[int]int{}
|
||||||
|
m.clone().delete(0)
|
||||||
|
}
|
||||||
|
@ -2,6 +2,6 @@
|
|||||||
// Phenomenon: cgen brackets are asymmetric in chained method calls.
|
// Phenomenon: cgen brackets are asymmetric in chained method calls.
|
||||||
fn test_main() {
|
fn test_main() {
|
||||||
mut path := 'hello/file.txt'
|
mut path := 'hello/file.txt'
|
||||||
extension := path.split('.').pop()
|
extension := path.split('.').last()
|
||||||
assert extension == 'txt'
|
assert extension == 'txt'
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user