From 14e4c7d1ef9ef169d049cca703d8682d236a3a12 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 25 Oct 2026 14:00:35 -0700 Subject: [PATCH] Keep static-object rewrites when propertyIsEnumerable asks another class's prototype MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The analysis reads F.prototype as ⊤ beside the class prototype objects it tracks, so every class looked queried by any G.prototype.propertyIsEnumerable call. The query reaches a class's prototype only when G may be that class's function. Co-Authored-By: Claude Opus 5.5 --- .../src/frontend/shape-inference/static-objects.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/compiler/src/frontend/shape-inference/static-objects.ts b/packages/compiler/src/frontend/shape-inference/static-objects.ts index 5413663641..c7f36f4cf2 100644 --- a/packages/compiler/src/frontend/shape-inference/static-objects.ts +++ b/packages/compiler/src/frontend/shape-inference/static-objects.ts @@ -608,7 +608,16 @@ export function planStaticObjectRewrites( * as the object `propertyIsEnumerable` is asked about. */ const reflectsOn = (atoms: ReadonlySet, ctorPath: string): boolean => enumerabilityEscapes || - enumerabilityQueries.some((recv) => mayBeValue(recv, atoms, ctorPath)) || + enumerabilityQueries.some((recv) => { + // `F.prototype` is one of `atoms` (a class's prototype) only when F + // may be that class's function, which `atoms` holds too: the analysis + // reads a prototype as ⊤ beside the class prototype objects it tracks. + let e: ts.Expression = recv; + while (ts.isParenthesizedExpression(e)) e = e.expression; + if (ts.isPropertyAccessExpression(e) && e.name.text === "prototype") + return mayBeValue(e.expression, atoms, ctorPath); + return mayBeValue(recv, atoms, ctorPath); + }) || reflective.some((call) => call.arguments.nodes.some((arg) => mayBe(arg, atoms, ctorPath))); /** Whether a call that freezes, seals or redefines an object may reach one of `atoms`. */ const reshapes = (atoms: ReadonlySet, ctorPath: string): boolean =>