diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 94d526831..e19c4785d 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -9872,27 +9872,21 @@ export class Lowerer { * instance type. Collection and body lowering own a refusal of that * class: the poison reaches the declaration or statement that asked, as * before. A speculative whole-program analysis owns none, so there the - * class is unmappable for the query and its diagnostics are dropped; - * lowering the class's own declaration collects it again and reports - * them if the program reaches it. */ + * refusal stays reported (the build fails with it, as it did where such + * an analysis already caught the poison) and the class is unmappable for + * the query instead of the poison escaping the compiler. */ collectLocalClassForType(decl: ts.ClassLikeDeclaration): boolean { if (this.speculativeTypeQueryDepth === 0 || this.fnStack.length > 0) { this.lowerClassExpressionInfo(decl); return true; } - const sink: ScrDiagnostic[] = []; - const previousSink = this.diagSink; - this.diagSink = sink; try { this.lowerClassExpressionInfo(decl); + return true; } catch (e) { if (e instanceof PoisonError) return false; throw e; - } finally { - this.diagSink = previousSink; } - for (const d of sink) this.pushDiag(d); - return true; } lowerClassExpression(expr: ts.ClassLikeDeclaration): IrExpr { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6102-local-class-type-query.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6102-local-class-type-query.js.json deleted file mode 100644 index 86c6ba9e8..000000000 --- a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6102-local-class-type-query.js.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "order": [ - "/tests/corpus/6102-local-class-type-query.js" - ], - "diags": [] -} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/local-class-type-query-js.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/local-class-type-query-js.js.json new file mode 100644 index 000000000..6bf774cd8 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/local-class-type-query-js.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/diagnostics/local-class-type-query-js.js" + ], + "diags": [] +} diff --git a/tests/corpus/6102-local-class-type-query.js b/tests/corpus/6102-local-class-type-query.js deleted file mode 100644 index 92fe35725..000000000 --- a/tests/corpus/6102-local-class-type-query.js +++ /dev/null @@ -1,42 +0,0 @@ -// A whole-program analysis that queries types before reachability is known -// (the computed-key write census here) can name a function-local class whose -// collection is refused. That query has no owner for the refusal: the class -// stays unmapped for it, and the refusal belongs to the class's own -// declaration, which this program never executes (it used to crash the -// compiler with an uncaught PoisonError). -function main(run) { - if (!run) return "skipped"; - const Project = class { - constructor() { - this.name = "p"; - } - close() { - if (this.missingFilesMap) { - this.missingFilesMap.clear(); - this.missingFilesMap = void 0; - } - } - add(k) { - (this.missingFilesMap || (this.missingFilesMap = new Map())).set(k, 1); - } - }; - const holder = { p: new Project() }; - const key = String(run); - holder.p[key] = "q"; - return holder.p.name; -} - -class Counter { - constructor() { - this.counts = {}; - } - bump(key) { - this.counts[key] = (this.counts[key] || 0) + 1; - return this.counts[key]; - } -} - -const counter = new Counter(); -const word = process.argv.length > 99 ? "unused" : "word"; -counter.bump(word); -console.log(main(0), counter.bump(word)); diff --git a/tests/diagnostics/local-class-type-query-js.js b/tests/diagnostics/local-class-type-query-js.js new file mode 100644 index 000000000..2da619133 --- /dev/null +++ b/tests/diagnostics/local-class-type-query-js.js @@ -0,0 +1,26 @@ +// A whole-program analysis that queries types before reachability is known +// (the computed-key write census here, through `holder.p`) names a +// function-local class whose collection is refused. The refusal is reported, +// once, at the class; it used to crash the compiler with an uncaught +// PoisonError. +function main() { + const Project = class _Project { + constructor() { + this.name = "p"; + } + close() { + if (this.missingFilesMap) { + this.missingFilesMap.clear(); + this.missingFilesMap = void 0; + } + } + add(k) { + (this.missingFilesMap || (this.missingFilesMap = new Map())).set(k, 1); + } + }; + const holder = { p: new Project() }; + const key = process.argv.length > 5 ? String(process.argv.length) : "name"; + holder.p[key] = "q"; + console.log(holder.p.name); +} +main(); diff --git a/tests/harness/__snapshots__/local-class-type-query-js.js.txt b/tests/harness/__snapshots__/local-class-type-query-js.js.txt new file mode 100644 index 000000000..60422a5dc --- /dev/null +++ b/tests/harness/__snapshots__/local-class-type-query-js.js.txt @@ -0,0 +1,6 @@ +local-class-type-query-js.js:14:9 - error SC1090: fields assigned outside the constructor's top level ('this.missingFilesMap' would be undefined until the first assignment runs — assign it unconditionally at the top of the constructor) is not supported yet + + 13 | this.missingFilesMap.clear(); + 14 | this.missingFilesMap = void 0; + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 15 | } \ No newline at end of file diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index e211a263b..b91073f87 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -2210,7 +2210,6 @@ "605-closures-forward-capture-tdz.ts": 3277, "6100-record-get-or-create.ts": 3771, "6101-record-get-or-create-unchecked/main.ts": 2107, - "6102-local-class-type-query.js": 2600, "6103-typeof-builtin-bindings.cjs": 2202, "6104-typeof-builtin-bindings.mjs": 2031, "6105-cjs-top-level-this/main.js": 1371, @@ -5247,7 +5246,6 @@ "605-closures-forward-capture-tdz.ts": 4638, "6100-record-get-or-create.ts": 3173, "6101-record-get-or-create-unchecked/main.ts": 3228, - "6102-local-class-type-query.js": 1967, "6103-typeof-builtin-bindings.cjs": 1796, "6104-typeof-builtin-bindings.mjs": 1715, "6105-cjs-top-level-this/main.js": 3213, diff --git a/tests/harness/npm.test.ts b/tests/harness/npm.test.ts index c4e70294e..a6cdee2b5 100644 --- a/tests/harness/npm.test.ts +++ b/tests/harness/npm.test.ts @@ -73,7 +73,7 @@ const KNOWN: Record = { "node24-env": { run: "SC1090" }, "node24-esm-metadata": { run: "SC1090" }, "node24-event-emitter": { run: "SC2020" }, - "node24-file-url-conversion": { run: "SC2020" }, + "node24-file-url-conversion": { build: "SC1090" }, "node24-fs-descriptors": { run: "SC1090" }, "node24-mime": { run: "SC2020" }, "node24-mime-errors": { run: "SC1090" }, @@ -104,7 +104,7 @@ const KNOWN: Record = { "package-imports": { build: "SC2013" }, "promise-bridge": { build: "SC1090" }, "self-name": { build: "SC2013" }, - "stream-shims": { run: "SC1090" }, + "stream-shims": { build: "SC1090" }, "util-shims": { run: "SC2020" }, "web-streams": { build: "SC2013" }, "workspace-copied": { build: "SC2013" },