← board

Measured 2026-09-13 (frankH), at ee5b6adc7 and under stable_pinned

Two defs, one file, nothing else in it:

def c_rsplit(label: str):
    return label.rsplit(" ", 1)      # ['C', 'minor']   correct

def c_split(label):
    return label.split(",")          # raw memory; CPython ['a', 'b', 'c']

PXXDBG=n.ret on that file, both compilers:

def n.ret run
c_rsplit(label: str) tk=22 then tk=6 rec=50 correct
c_split(label) tk=23 garbage

Same under stable_linux_amd64/default/stable_pinned, which predates this week's work — so this is older than the fixes it was found beside.

Where it is, and why the obvious widening is refused

PyInferReturnType's method-call arm (compiler/pyparser.inc, the PyRetMethodType block). Three sub-arms in an else if chain:

  1. the receiver resolves to a user class → PyRetMethodType answers;
  2. the receiver is a local the scan cannot type → tyVariant (added 2026-09-13 for the ARGUMENT-decides family; see test_nilpy_a_returned_method_call_takes_its_type_from_the_argument.npy);
  3. a str method on a receiver bound in this def → PyStrMethodInfo's row, but only when that row is a SCALAR.

split/rsplit/partition/splitlines are tabulated as tyClass, and arm 3 pairs cur := smRetTk with PyInferLastCi := -1 — right for a scalar, and for a class it produces "a class result with no class", which is worse. The source says so in its own words and names the regression it caused (7ddcb9650). So the arm declines, cur keeps whatever PyInferExprType took from the argument list, and "," makes it a string.

Do not just extend arm 3 to the class rows — that is the change that was reverted. Two candidate directions, unmeasured:

The annotated row must stay tk=6 rec=50 either way, and it reaches that by a different route (PyInferExprType can type an annotated label), so it is the control.

Also worth a look while in here

c_rsplit prints two n.ret lines with DIFFERENT kinds — tk=22 from one pass and tk=6 rec=50 from the other. The routine's own comments call two passes disagreeing "a silent ABI mismatch". It works today; nobody has established why.

How it was found, and the warning in it

Reduced from lekkerzeilen. It was first measured as WORKING in a seven-def probe and is broken when it is the only thing in the file — the contaminant was inside the probe, in the right population, and honest. "Would this row still pass if it were the ONLY thing in the run?" answers NO here, which is the question that caught it.

Log