diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 8f0a1103c4..4a5fff8bdf 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -794,7 +794,21 @@ pub mut: name string kind IdentKind info IdentInfo - is_mut bool + is_mut bool // if mut *token* is before name. Use `is_mut()` to lookup mut variable +} + +pub fn (i &Ident) is_mut() bool { + match i.obj { + Var { + return i.obj.is_mut + } + ConstField { + return false + } + AsmRegister, GlobalField { + return true + } + } } pub fn (i &Ident) var_info() IdentVar { diff --git a/vlib/v/checker/assign.v b/vlib/v/checker/assign.v index e418d724a4..f95c0e09a3 100644 --- a/vlib/v/checker/assign.v +++ b/vlib/v/checker/assign.v @@ -559,15 +559,10 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { if right_node.right.obj is ast.Var { v := right_node.right.obj right_type0 = v.typ - if !v.is_mut && assigned_var.is_mut && !c.inside_unsafe { - c.error('`$right_node.right.name` is immutable, cannot have a mutable reference to it', - right_node.pos) - } - } else if right_node.right.obj is ast.ConstField { - if assigned_var.is_mut && !c.inside_unsafe { - c.error('`$right_node.right.name` is immutable, cannot have a mutable reference to it', - right_node.pos) - } + } + if !c.inside_unsafe && assigned_var.is_mut() && !right_node.right.is_mut() { + c.error('`$right_node.right.name` is immutable, cannot have a mutable reference to it', + right_node.pos) } } } diff --git a/vlib/v/checker/tests/modify_const_with_ref.out b/vlib/v/checker/tests/modify_const_with_ref.out deleted file mode 100644 index dc2b4335bc..0000000000 --- a/vlib/v/checker/tests/modify_const_with_ref.out +++ /dev/null @@ -1,14 +0,0 @@ -vlib/v/checker/tests/modify_const_with_ref.vv:11:11: error: `constant` is immutable, cannot have a mutable reference to it - 9 | mut unused_var := Foo{} - 10 | unused_var = Foo{} - 11 | mut c := &constant - | ^ - 12 | c.value = 200 - 13 | } -vlib/v/checker/tests/modify_const_with_ref.vv:9:6: error: unused variable: `unused_var` - 7 | - 8 | fn main() { - 9 | mut unused_var := Foo{} - | ~~~~~~~~~~ - 10 | unused_var = Foo{} - 11 | mut c := &constant \ No newline at end of file diff --git a/vlib/v/checker/tests/modify_const_with_ref.vv b/vlib/v/checker/tests/modify_const_with_ref.vv deleted file mode 100644 index 872460eba4..0000000000 --- a/vlib/v/checker/tests/modify_const_with_ref.vv +++ /dev/null @@ -1,13 +0,0 @@ -struct Foo { -mut: - value int -} - -const constant = Foo{ 100 } - -fn main() { - mut unused_var := Foo{} - unused_var = Foo{} - mut c := &constant - c.value = 200 -} diff --git a/vlib/v/checker/tests/mut_assign_ref.out b/vlib/v/checker/tests/mut_assign_ref.out new file mode 100644 index 0000000000..171bec7d5a --- /dev/null +++ b/vlib/v/checker/tests/mut_assign_ref.out @@ -0,0 +1,28 @@ +vlib/v/checker/tests/mut_assign_ref.vv:10:12: error: `f` is immutable, cannot have a mutable reference to it + 8 | fn main() { + 9 | f := Foo{} + 10 | mut pf := &f + | ^ + 11 | pf = &f + 12 | p := &f +vlib/v/checker/tests/mut_assign_ref.vv:11:7: error: `f` is immutable, cannot have a mutable reference to it + 9 | f := Foo{} + 10 | mut pf := &f + 11 | pf = &f + | ^ + 12 | p := &f + 13 | _ = p +vlib/v/checker/tests/mut_assign_ref.vv:15:11: error: `constant` is immutable, cannot have a mutable reference to it + 13 | _ = p + 14 | + 15 | mut c := &constant + | ^ + 16 | c.value = 200 + 17 | c = &constant +vlib/v/checker/tests/mut_assign_ref.vv:17:6: error: `constant` is immutable, cannot have a mutable reference to it + 15 | mut c := &constant + 16 | c.value = 200 + 17 | c = &constant + | ^ + 18 | ic := &constant // ok + 19 | _=ic diff --git a/vlib/v/checker/tests/mut_assign_ref.vv b/vlib/v/checker/tests/mut_assign_ref.vv new file mode 100644 index 0000000000..9fea31db3d --- /dev/null +++ b/vlib/v/checker/tests/mut_assign_ref.vv @@ -0,0 +1,24 @@ +struct Foo { +mut: + value int +} + +const constant = Foo{ 100 } + +fn main() { + f := Foo{} + mut pf := &f + pf = &f + p := &f + _ = p + + mut c := &constant + c.value = 200 + c = &constant + ic := &constant // ok + _=ic + + mut mf := f + pf = &mf // ok + _ = pf +} diff --git a/vlib/v/tests/interface_edge_cases/voidptr_casted_as_an_interface_test.v b/vlib/v/tests/interface_edge_cases/voidptr_casted_as_an_interface_test.v index 4a70f75c0b..3c30e043f7 100644 --- a/vlib/v/tests/interface_edge_cases/voidptr_casted_as_an_interface_test.v +++ b/vlib/v/tests/interface_edge_cases/voidptr_casted_as_an_interface_test.v @@ -19,7 +19,7 @@ fn test_voidptr_casted_as_an_interface_reference() { dump(pi) assert f(pi) == '&IAbc(0x0)' // - i := IAbc(Abc{}) + mut i := IAbc(Abc{}) pi = &i dump(pi) assert f(pi).contains('x: 123') diff --git a/vlib/v/tests/ref_array_init_test.v b/vlib/v/tests/ref_array_init_test.v index 917c452ec9..16b009887c 100644 --- a/vlib/v/tests/ref_array_init_test.v +++ b/vlib/v/tests/ref_array_init_test.v @@ -1,7 +1,11 @@ fn test_reference_array_init() { mut b := &[5, 6, 7] { - a := [1, 2, 3] + mut a := [1, 2, 3] + // TODO: this should probably produce a notice at least, + // (without unsafe{&a}), since it takes the address of something + // on the stack, that will very soon be out of scope, even + // though it is still in the same function: b = &a } println(b)