Repro
class C { a = 5; inc(): number { return this.a + 1; } }
function viaParam(c: C, n: number): number { let l = 0; for (let i = 0; i < n; i++) l = c.inc(); return l; }
delete (C.prototype as any).inc;
try { console.log(viaParam(new C(), 1)); } catch (e) { console.log("threw:", (e as Error).constructor.name); }
node: threw: TypeError — perry (main 19082697e7, also every branch since): prints 6.
Mechanism
The direct-method guards (js_method_direct_shape_guard, the inline form in lower_call/method_override.rs, and the typed-feedback contract) invalidate on prototype overrides through PERRY_CLASS_PROTOTYPE_FAST_GUARDS_INVALIDATED[_BY_METHOD], but a delete of the prototype method does not flip the latch, so the guard still passes and the compiled body runs.
The same script's monkey-patch case (C.prototype.inc = function… mid-program) IS honored, so the miss is specific to deletion. Found while validating the probe-first method dispatch change (differential vs node, identical on both switch arms — i.e. pre-existing, not introduced there).
https://claude.ai/code/session_01F1dt1jfzK2cheMZyus6y6p
Repro
node:
threw: TypeError— perry (main19082697e7, also every branch since): prints6.Mechanism
The direct-method guards (
js_method_direct_shape_guard, the inline form inlower_call/method_override.rs, and the typed-feedback contract) invalidate on prototype overrides throughPERRY_CLASS_PROTOTYPE_FAST_GUARDS_INVALIDATED[_BY_METHOD], but adeleteof the prototype method does not flip the latch, so the guard still passes and the compiled body runs.The same script's monkey-patch case (
C.prototype.inc = function…mid-program) IS honored, so the miss is specific to deletion. Found while validating the probe-first method dispatch change (differential vs node, identical on both switch arms — i.e. pre-existing, not introduced there).https://claude.ai/code/session_01F1dt1jfzK2cheMZyus6y6p