← board

NilPy: a 1-character string literal was a char, and segfaulted as an argument

Found 2026-07-20 while testing [[bug-a-nilpy-subclass-overlays-parent-layout]] — the inheritance repro crashed only because its objects were named "d".

Repro

class A:
    def __init__(self, n: str) -> None:
        self.n = n

a = A("d")     # SIGSEGV;  A("dd") works
print(a.n)

Cause

The shared factor types any 1-character literal as tyChar (correct for Pascal, where 'd' IS a char). Python has no char type, so this made every string-expecting context depend on a char->string coercion — and the method/constructor argument paths have none. The character CODE (0x64 for "d") was passed where the callee dereferenced a string pointer. A plain def argument survived because the frozen-string parameter path normalizes an AN_INT_LIT/tyChar argument into a string literal; the class paths do not.

Fix

da66e43d — a 1-character literal stays AN_STR_LIT under PyExprMode; the Pascal dialect's char literal is untouched. ord() then needed a string operand path (the ordinal intrinsic would take the string's pointer for its code): a string argument routes to pylib's new pyord_s as a normal AN_CALL, so the argument still goes through the regular frozen-string conversion.

Regression test

test/test_nilpy_one_char_string.npy, wired into make test-nilpy; output diffed against CPython running the same file.