fix field setter fallback that never worked (#24871)

refs https://forum.nim-lang.org/t/12785, refs #4711

The code was already there that when `propertyWriteAccess` returns `nil`
(i.e. cannot find a setter), `semAsgn` turns the [LHS into a call and
semchecks
it](1ef9a656d2/compiler/semexprs.nim (L1941-L1948)),
meaning if a setter cannot be found a getter will be assigned to
instead. However `propertyWriteAccess` never returned nil, because
`semOverloadedCallAnalyseEffects` was not called with `efNoUndeclared`
and so produced an error directly. So `efNoUndeclared` is passed to this
call so this code works as intended.

This fixes the issue described in #4711 which was closed because
subscripts do not have the same behavior implemented. However we can
implement this for subscripts as well (I have an implementation ready),
it just changes the error message from the failed overloads of `[]=` to
the failed overloads of `[]` for the LHS, which might be misleading but
is consistent with the error messages for any other assignment. I can do
this in this PR or another one.

(cherry picked from commit 4d9e5e8b6d)
This commit is contained in:
metagn
2025-04-13 20:21:33 +03:00
committed by narimiran
parent 94497c790b
commit 0c8cefcbef
5 changed files with 35 additions and 4 deletions

View File

@@ -1787,7 +1787,7 @@ proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
result = newTreeI(nkCall, n.info, setterId, a[0], n[1])
result.flags.incl nfDotSetter
let orig = newTreeI(nkCall, n.info, setterId, aOrig[0], nOrig[1])
result = semOverloadedCallAnalyseEffects(c, result, orig, {})
result = semOverloadedCallAnalyseEffects(c, result, orig, {efNoUndeclared})
if result != nil:
result = afterCallActions(c, result, nOrig, {})

View File

@@ -26,8 +26,7 @@ block:
block:
template `.=`(a: Foo, b: untyped, c: untyped) = b = c
b.x = 123 #[tt.Error
^ undeclared field: 'x=' for type terrmsgs.Bar [type declared in terrmsgs.nim(15, 8)]]#
# yeah it says x= but does it matter in practice
^ undeclared field: 'x' for type terrmsgs.Bar [type declared in terrmsgs.nim(15, 8)]]#
block:
template `()`(a: Foo, b: untyped, c: untyped) = echo "something"

View File

@@ -14,4 +14,4 @@ template `.=`*(flags: Flags, key: Flag, val: bool) =
var flags: Flags
flags.A = 123 #[tt.Error
^ undeclared field: 'A=' for type tmismatch.Flags [type declared in tmismatch.nim(9, 5)]]#
^ undeclared field: 'A' for type tmismatch.Flags [type declared in tmismatch.nim(9, 5)]]#

View File

@@ -0,0 +1,24 @@
# issue #4711
type
Vec4 = object
x,y,z,w : float32
Vec3 = object
x,y,z : float32
proc `+=`(v0: var Vec3; v1: Vec3) =
v0.x += v1.x
v0.y += v1.y
v0.z += v1.z
proc xyz(v: var Vec4): var Vec3 =
cast[ptr Vec3](v.x.addr)[]
let tmp = Vec3(x: 1, y:2, z:3)
var dst = Vec4(x: 4, y:4, z:4, w:4)
xyz(dst) = tmp # works
dst.xyz() = tmp # works
dst.xyz += tmp # works
dst.xyz = tmp # attempting to call undeclared routine `xyz=`

View File

@@ -0,0 +1,8 @@
# https://forum.nim-lang.org/t/12785
proc x(pt: var array[2, float]): var float = pt[0]
var pt = [0.0, 0.0]
pt.x += 1.0 # <-- fine
x(pt) = 1.0 # <-- fine
pt.x = 1.0 # <-- does not compile