Repro, with the control that separates the two readings
class V:
def __init__(self, x): self.x = x
def __mul__(self, s): return V(self.x * s)
__rmul__ = __mul__ # pascal26: undefined variable (__mul__)
v = V(3) * 4
print(v.x) # CPython: 12
./compiler/pascal26 probe.py out -> error: undefined variable (__mul__).
Delete only the alias line and the identical class compiles and prints 12.
That control is what establishes this is a NAME-BINDING bug in the class body and
not a missing dunder — without it the obvious reading is "no operator
overloading", which would send an implementer at the wrong subsystem entirely.
feature-nilpy-arithmetic-dunders-full-protocol is done/ and is not this: the
dunders resolve fine when called. What does not work is referring to one by name.
Why it ranks above its one-line size
name = earlier_name in a class body is ordinary Python — it is how __rmul__,
__radd__ and every other reflected operator is conventionally written, and how
update = __init__-style aliases are spelled throughout real code. It is not an
edge case reachable only by mistake, so it is squarely a compiler gap and
the lekkerzeilen source should not move for it (see the umbrella's cheat
rule, which permits changing that source and is deliberately not used here).
Blast radius is the argument: one line, seven modules, because it sits in the vector-math module everything imports.
Log
- 2026-09-09 — resolved; this names the commit that carried the resolve, which is not always the one that carried the change — commit bbd27a5c3.