Skip to content

Commit 4d9e5e8

Browse files
authored
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](https://github.com/nim-lang/Nim/blob/1ef9a656d25f71dec6066e68ce6e9a518d5e9f16/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.
1 parent 1ef9a65 commit 4d9e5e8

File tree

5 files changed

+35
-4
lines changed

5 files changed

+35
-4
lines changed

compiler/semexprs.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1787,7 +1787,7 @@ proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
17871787
result = newTreeI(nkCall, n.info, setterId, a[0], n[1])
17881788
result.flags.incl nfDotSetter
17891789
let orig = newTreeI(nkCall, n.info, setterId, aOrig[0], nOrig[1])
1790-
result = semOverloadedCallAnalyseEffects(c, result, orig, {})
1790+
result = semOverloadedCallAnalyseEffects(c, result, orig, {efNoUndeclared})
17911791

17921792
if result != nil:
17931793
result = afterCallActions(c, result, nOrig, {})

tests/specialops/terrmsgs.nim

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ block:
2626
block:
2727
template `.=`(a: Foo, b: untyped, c: untyped) = b = c
2828
b.x = 123 #[tt.Error
29-
^ undeclared field: 'x=' for type terrmsgs.Bar [type declared in terrmsgs.nim(15, 8)]]#
30-
# yeah it says x= but does it matter in practice
29+
^ undeclared field: 'x' for type terrmsgs.Bar [type declared in terrmsgs.nim(15, 8)]]#
3130
block:
3231
template `()`(a: Foo, b: untyped, c: untyped) = echo "something"
3332

tests/specialops/tmismatch.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ template `.=`*(flags: Flags, key: Flag, val: bool) =
1414
var flags: Flags
1515

1616
flags.A = 123 #[tt.Error
17-
^ undeclared field: 'A=' for type tmismatch.Flags [type declared in tmismatch.nim(9, 5)]]#
17+
^ undeclared field: 'A' for type tmismatch.Flags [type declared in tmismatch.nim(9, 5)]]#

tests/specialops/tsetterfallback1.nim

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# issue #4711
2+
3+
type
4+
Vec4 = object
5+
x,y,z,w : float32
6+
7+
Vec3 = object
8+
x,y,z : float32
9+
10+
proc `+=`(v0: var Vec3; v1: Vec3) =
11+
v0.x += v1.x
12+
v0.y += v1.y
13+
v0.z += v1.z
14+
15+
proc xyz(v: var Vec4): var Vec3 =
16+
cast[ptr Vec3](v.x.addr)[]
17+
18+
let tmp = Vec3(x: 1, y:2, z:3)
19+
var dst = Vec4(x: 4, y:4, z:4, w:4)
20+
21+
xyz(dst) = tmp # works
22+
dst.xyz() = tmp # works
23+
dst.xyz += tmp # works
24+
dst.xyz = tmp # attempting to call undeclared routine `xyz=`

tests/specialops/tsetterfallback2.nim

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# https://forum.nim-lang.org/t/12785
2+
3+
proc x(pt: var array[2, float]): var float = pt[0]
4+
5+
var pt = [0.0, 0.0]
6+
pt.x += 1.0 # <-- fine
7+
x(pt) = 1.0 # <-- fine
8+
pt.x = 1.0 # <-- does not compile

0 commit comments

Comments
 (0)