← board

nilpy: d[k] += 1 is not an lvalue

Repro

d = {"a": 1}
d["a"] += 1        # error: assignment target is not an lvalue

xs = [1, 2]
xs[0] += 5         # error: assignment target is not an lvalue

Plain subscript assignment is fine — d["a"] = 1 and xs[0] = 5 both work — and so is x += 1 on a simple name. Only the augmented form with a subscript target fails.

Why it matters

counts[k] += 1 is the single most common counting idiom in Python, and xs[i] += v is the most common accumulate. A Counter is far less useful without it: the whole point of a missing key reading as 0 is that c[k] += 1 needs no seeding.

Shape

Desugar target[key] op= value to a read-modify-write of the same subscript, evaluating the target and key expressions ONCE (Python evaluates them once; a naive textual expansion would evaluate a call in the key twice). All the augmented operators, not just +=.

Note on the diagnostic

The error is reported one line PAST the offending statement (a 3-line file reports line 4). Line attribution in these diagnostics is unreliable in general — see the note in [[bug-nilpy-stdlib-name-binds-pascal-unit]], where an error inside a used unit is reported against the main file with a fictional line number.

Gate

make test-nilpy green with a .npy case covering dict, list and Counter targets and every augmented operator, diffed against CPython, + --tier quick + self-host byte-identical.

CLOSED — found already fixed

Re-checked directly against current HEAD: d["a"] += 1, xs[0] += 5, a Counter target, and -=/*= on both dict and list subscripts all work and match CPython. Whatever landed the general subscript-assignment lowering work since this was filed (2026-07-26) evidently covered the augmented form too — no specific commit identified, and none was worth archaeology-hunting for since the behavior is simply correct now.

No test existed to guard this shape, so one was added rather than closing on faith alone: test/test_nilpy_augmented_subscript_assign.npy. Gate: make test-nilpy green, self-host fixedpoint, testmgr --tier quick.

Ticket closed.

Log