Skip to content

Compile object-literal shorthand of class declarations - #1557

Open
cramforce wants to merge 1 commit into
mainfrom
opt/class-value-shorthand
Open

cramforce wants to merge 1 commit into
mainfrom
opt/class-value-shorthand

Conversation

@cramforce

Copy link
Copy Markdown
Contributor

{ A, B } where B is a class declaration failed. The shorthand property path resolved locals, globals and functions but not class names, so a class extending EventEmitter (and, in JavaScript, a plain class declaration) reported "the reference to 'B' (a binding form with no lowering)", or in JavaScript a deferred SC2002 shape mismatch at run time. This broke module.exports = { Channel, Plain } and similar exports.

The shorthand now lowers a class name exactly like the identifier B (the class-name branch of lowerIdentifierExpr is factored into classNameValue and shared), so the property holds the class value: construction through it, name, identity with the binding, and instanceof.

A statically decided instanceof with computed operands (new o.B() instanceof B, p instanceof lib.Plain) was refused with SC1090 because folding dropped the operands' evaluation. It now evaluates both operands, left then right, and then answers the folded result. The inheritance.ts diagnostics fixture no longer expects that refusal.

Evidence:

  • Corpus 6585–6587 (CommonJS and TypeScript shorthand of plain, EventEmitter-derived and expression classes; a module exporting classes through shorthand) match Node in the plain and sanitized lanes.
  • Focused corpus (class, cjs, instanceof, shorthand, object, inherit) in both lanes, the diagnostics suite and the npm suites show only failures that also occur on the base commit in the sandbox.
  • Zero-cost gate against 139542b: PASS, 3450 programs identical (bench, self-hosted compiler, all corpus programs).

Overlap: #1544 (opt/ee-class-value-crash) also edits relational.ts, in different hunks of lowerInstanceOf (untyped EventEmitter constructor values).

🤖 Generated with Claude Code

`{ A, B }` where `B` is a class declaration failed: the shorthand path
resolved locals, globals and functions but not class names, so a class
extending EventEmitter (and, in JavaScript, a plain class declaration)
reported "the reference to 'B' (a binding form with no lowering)" or a
deferred SC2002 shape mismatch, breaking `module.exports = { A, B }`.
The shorthand now lowers a class name exactly like the identifier
(shared classNameValue), so the property holds the class value.

A statically decided instanceof with computed operands
(`new o.B() instanceof B`, `p instanceof lib.Plain`) was refused because
folding dropped the operands' evaluation; it now evaluates both
operands, left then right, and answers the folded result.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
scriptc Ready Ready Preview, v0 Oct 20, 2026 9:28pm UTC

Comment on lines +3169 to +3172
// A class declaration's name (`{ Name }`): the class value, exactly
// like the long form `{ Name: Name }`.
const classValue = classNameValue(lowerer, resolved, propName, loc);
if (classValue) return classValue;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading a class through shorthand before its declaration runs returns the class value instead of throwing the required ReferenceError.

Fix on Vercel

answer: IrExpr,
): IrExpr {
const stmts: IrStmt[] = [];
if (left.kind !== "varRef") stmts.push({ kind: "exprStmt", expr: left, loc: left.loc });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When a folded instanceof has an uninitialized binding on the left and a computed constructor on the right, skipping the varRef suppresses the ReferenceError and evaluates the constructor instead.

Fix on Vercel

@cramforce
cramforce requested a review from ctate October 20, 2026 23:03

This branch was successfully deployed

1 active deployment
Preview — 69d93430 Deployed Oct 20, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant