← board

//= is true division, not floor division

Repro

class A:
    def __init__(self, n):
        self.n = n
    def idiv(self, v):
        self.n //= v
        return self.n

print(A(25).idiv(3))     # CPython 8     pxx 8.333333333333334

%= in the same position is correct, so this is specific to //=.

Cause

The compound-assignment tail in the shared expression parser maps its token set with a case whose ELSE arm is tkSlash:

tkPlusEq:  ...tkPlus
tkMinusEq: ...tkMinus
tkStarEq:  ...tkStar
else       ...tkSlash

so anything that is not +=, -= or *= becomes TRUE division. / and // are different operators in Python — tkSlash vs tkDiv — and NilPy's own augmented path distinguishes them correctly (PyAugBinTok). Only this shared tail collapses them.

Fix shape

Give //= its own arm mapping to tkDiv, and make the ELSE an ERROR rather than a silent fallthrough to division — the current shape means any future compound token silently becomes /=, which is how this one got here.

Check what //= actually lexes to first: if it does not have a distinct token yet, that is the first half of the fix.

Gate

A .npy diffed against CPython: //= and /= on an int field and on a plain local; %=; each with int and float operands; and // / / as plain binops as controls.

Log

Resolved 2026-08-02

The ticket's "check what //= actually lexes to first" was the right first question, and the answer was the whole bug: the lexer already distinguishes them, and it is the same token as Pascal's /=.

So the shared tail's tkSlashEq -> tkSlash mapping is correct for Pascal and wrong for NilPy. Fixed by making that one arm frontend-aware; /= never reached this tail from NilPy at all, which is why only //= was affected.

The ELSE arm is now an internal error rather than a silent fallthrough to division, as the ticket suggested — that shape is how this bug arrived and would have repeated for the next compound token.

Verified on BOTH frontends, because the token is shared: NilPy's //=, /= and %= on fields and locals across ints, floats and negatives (floor division differs most visibly on negatives — -7 // 2 is -4, not -3), plus a Pascal program whose /= must still be real division.

gate.sh quick GREEN, self-host fixedpoint byte-identical.