diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 07518bfb8b..bc7c442a5b 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -2066,10 +2066,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(mut node.left) - if !node.left.is_lvalue() { - c.error('cannot pass expression as `mut`', node.left.pos()) - } + to_lock, pos := c.check_for_mut_receiver(mut node.left) // node.is_mut = true if to_lock != '' && rec_share != .shared_t { 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) } 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) { 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' { - c.fail_if_immutable(mut node.left) + c.check_for_mut_receiver(mut node.left) if node.args.len != 1 { 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', 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 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 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() } else { node.receiver_type = node.left_type } } 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) if method := c.table.find_method(unwrapped_left_sym, method_name) { 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 } +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) { scope_register_var_name(mut s, pos, typ, 'it') } diff --git a/vlib/v/checker/tests/fn_return_array_sort_err.out b/vlib/v/checker/tests/fn_return_array_sort_err.out index d15d93706d..53aaace036 100644 --- a/vlib/v/checker/tests/fn_return_array_sort_err.out +++ b/vlib/v/checker/tests/fn_return_array_sort_err.out @@ -4,3 +4,9 @@ vlib/v/checker/tests/fn_return_array_sort_err.vv:6:14: error: the `sort()` metho 6 | ret_array().sort() | ~~~~~~ 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 | } diff --git a/vlib/v/checker/tests/mut_receiver_lit.out b/vlib/v/checker/tests/mut_receiver_lit.out index e0cd49066d..17f5006893 100644 --- a/vlib/v/checker/tests/mut_receiver_lit.out +++ b/vlib/v/checker/tests/mut_receiver_lit.out @@ -1,5 +1,20 @@ -vlib/v/checker/tests/mut_receiver_lit.vv:10:1: error: cannot pass expression as `mut` - 8 | } - 9 | - 10 | Box{}.set(0) - | ~~~~~ +vlib/v/checker/tests/mut_receiver_lit.vv:12:2: error: cannot pass expression as `mut` + 10 | + 11 | fn non_mut_receiver() { + 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 | } diff --git a/vlib/v/checker/tests/mut_receiver_lit.vv b/vlib/v/checker/tests/mut_receiver_lit.vv index e015e715f2..f8fe0ef9b3 100644 --- a/vlib/v/checker/tests/mut_receiver_lit.vv +++ b/vlib/v/checker/tests/mut_receiver_lit.vv @@ -1,3 +1,4 @@ +// error in non-mut as receover struct Box { mut: value int @@ -7,4 +8,18 @@ fn (mut box Box) set(value int) { box.value = value } -Box{}.set(0) +fn non_mut_receiver() { + 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) +} diff --git a/vlib/v/tests/method_call_chain_test.v b/vlib/v/tests/method_call_chained_test.v similarity index 81% rename from vlib/v/tests/method_call_chain_test.v rename to vlib/v/tests/method_call_chained_test.v index c9cef8d4be..698322936c 100644 --- a/vlib/v/tests/method_call_chain_test.v +++ b/vlib/v/tests/method_call_chained_test.v @@ -2,6 +2,6 @@ // Phenomenon: cgen brackets are asymmetric in chained method calls. fn test_main() { mut path := 'hello/file.txt' - extension := path.split('.').pop() + extension := path.split('.').last() assert extension == 'txt' }