From 504d34a0a89cd3c7bf1b13008f42f76dc825bd9c Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 4 Jun 2025 03:48:50 +0300 Subject: [PATCH] checker: fix mutable const bug (fix #14916) --- vlib/v/checker/assign.v | 2 +- vlib/v/checker/containers.v | 10 ++++++++++ vlib/v/checker/tests/ban_const_ref_mutation.out | 7 +++++++ vlib/v/checker/tests/ban_const_ref_mutation.vv | 6 ++---- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/vlib/v/checker/assign.v b/vlib/v/checker/assign.v index ee04483558..d11f5955d0 100644 --- a/vlib/v/checker/assign.v +++ b/vlib/v/checker/assign.v @@ -4,7 +4,7 @@ module checker import v.ast -// TODO: 600 line function +// TODO: 980 line function fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { prev_inside_assign := c.inside_assign c.inside_assign = true diff --git a/vlib/v/checker/containers.v b/vlib/v/checker/containers.v index 33fc34fd60..3ce44a5cb9 100644 --- a/vlib/v/checker/containers.v +++ b/vlib/v/checker/containers.v @@ -795,6 +795,16 @@ fn (mut c Checker) check_append(mut node ast.InfixExpr, left_type ast.Type, righ if !left_value_type.has_flag(.option) && right_type.has_flag(.option) { c.error('unwrapped Option cannot be used in an infix expression', node.pos) } + + right := node.right + if right is ast.PrefixExpr && right.op == .amp { + mut expr2 := right.right + if mut expr2 is ast.Ident { + if !node.left.is_blank_ident() && expr2.obj is ast.ConstField { + c.error('cannot have mutable reference to const `${expr2.name}`', expr2.pos) + } + } + } if left_value_sym.kind == .interface { if right_final_sym.kind != .array { // []Animal << Cat diff --git a/vlib/v/checker/tests/ban_const_ref_mutation.out b/vlib/v/checker/tests/ban_const_ref_mutation.out index e69de29bb2..f162269ac0 100644 --- a/vlib/v/checker/tests/ban_const_ref_mutation.out +++ b/vlib/v/checker/tests/ban_const_ref_mutation.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/ban_const_ref_mutation.vv:11:14: error: cannot have mutable reference to const `foobar_const` + 9 | println('foobar_const.foo: ${foobar_const.foo}') // foobar_const.foo: 123 + 10 | mut foobars := []&Foobar{} + 11 | foobars << &foobar_const + | ~~~~~~~~~~~~ + 12 | foobars[0].foo = 456 + 13 | println('foobar_const.foo: ${foobar_const.foo}') // foobar_const.foo: 456 diff --git a/vlib/v/checker/tests/ban_const_ref_mutation.vv b/vlib/v/checker/tests/ban_const_ref_mutation.vv index d0209c8cb0..e71d0757cd 100644 --- a/vlib/v/checker/tests/ban_const_ref_mutation.vv +++ b/vlib/v/checker/tests/ban_const_ref_mutation.vv @@ -1,4 +1,3 @@ -/* struct Foobar { mut: foo int @@ -7,10 +6,9 @@ mut: const foobar_const = Foobar{123} fn main() { - println("foobar_const.foo: ${foobar_const.foo}") // foobar_const.foo: 123 + println('foobar_const.foo: ${foobar_const.foo}') // foobar_const.foo: 123 mut foobars := []&Foobar{} foobars << &foobar_const foobars[0].foo = 456 - println("foobar_const.foo: ${foobar_const.foo}") // foobar_const.foo: 456 + println('foobar_const.foo: ${foobar_const.foo}') // foobar_const.foo: 456 } -*/