Symptom
After a different-shape element is stored into a P[] (through as any), a read loop that does s += r.x + r.y yields NaN where node string-concatenates.
Minimal reproducer
class P { x: number; y: number; constructor(x: number, y: number) { this.x = x; this.y = y; } }
class Q { x: string; y: string; constructor(x: string, y: string) { this.x = x; this.y = y; } }
function run(): number {
const a: P[] = [];
for (let i = 0; i < 10; i++) a.push(new P(i, i + 1));
(a as any)[4] = new Q("z", "w");
let s = 0;
for (let i = 0; i < a.length; i++) { const r = a[i]; s += r.x + r.y; }
return s;
}
console.log(run());
node 26.5.1: 16zw1113151719 (sum concatenates through the Q at index 4). Perry: NaN.
What is established
Symptom
After a different-shape element is stored into a
P[](throughas any), a read loop that doess += r.x + r.yyieldsNaNwhere node string-concatenates.Minimal reproducer
node 26.5.1:
16zw1113151719(sum concatenates through the Q at index 4). Perry:NaN.What is established
main@ 423bb44 (v0.5.1448) and on the repsel: a proven element fetch is still a runtime call — specialize a[i] inside the element-shape guarded clone #7771 branch (A/B'd both arms).+lowering claiming a numeric proof forr.xoff the declared element type and coercing (js_number_coerce("z")→ NaN) where spec+should have dispatched to string concat. Declared types are hints, not layout facts (CLAUDE.md, Known Limitations) — the annotation is lied to viaas any, but node semantics still apply.