A tuple-unpacking assignment does not box a callable value
- Type: bug — Track N. Found: 2026-08-27 by agent-A, probing sibling positions while closing [[bug-nilpy-a-lambda-returned-directly-is-not-callable]].
- Pre-existing: identical on HEAD and at pinned v380, so it is not that fix's doing.
Repro
a, b = lambda x: x + 1, lambda x: x + 2
print(a(1), b(1))
| CPython | 2 3 |
| pxx | compiles, then TypeError: object is not callable |
Cause, by analogy rather than by measurement
Not verified — measure before writing a cause into this ticket; two recent N tickets named the wrong mechanism.
The single-target paths call PyBoxCallableValue on the right-hand side
(pyparser.inc, the two assignment sites and the return arm): both lambda
lowerings hand back a heap OBJECT pointer, and a pointer-typed local never
reaches ParsePostfix's dynamic-call path, which keys on tyVariant. The
unpacking path builds its own per-target stores and plausibly never asks. That
is the same shape as
bug-nilpy-immediately-invoked-lambda-is-not-callable (the paren-callee
position) and the return arm itself — this would be the fourth position to
need the box, which is the argument for asking where the boxing decision
lives rather than adding a fourth call
(devdocs/dev/normalise-dont-special-case.md).
Why it ranks here
Loud (a TypeError at the call, not a wrong value) and the workaround is two
lines, so it sits below the wrong-value bugs. But a, b = f, g over callables
is ordinary Python, and the failure appears at the CALL, away from the
assignment that caused it.
Gate
make compiler/pascal26 fixedpoint + tools/gate.sh quick, the repro matching
CPython, and a witness row in test-core covering the unpack of two lambdas, of
two def names, and a mixed a, b = fn, 1. .expected generated by CPython.