@scriptc/compiler 0.0.10 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ambient/scriptc-node-fallback.d.ts +63 -15
- package/ambient/scriptc.d.ts +2 -2
- package/dist/backend/cc.d.ts +2 -2
- package/dist/backend/emission/emit-async.js +1 -1
- package/dist/backend/emission/emit-exprs.js +131 -54
- package/dist/backend/emission/emit-exprs.js.map +1 -1
- package/dist/backend/emission/emit-island.js +1 -1
- package/dist/backend/emission/emit-shapes.js +1 -1
- package/dist/backend/emission/emit-walkers.d.ts +14 -14
- package/dist/backend/emission/emit-walkers.js +44 -44
- package/dist/backend/emission/emit-walkers.js.map +1 -1
- package/dist/backend/emission/emitter.d.ts +3 -3
- package/dist/backend/emission/emitter.js +33 -9
- package/dist/backend/emission/emitter.js.map +1 -1
- package/dist/backend/emission/may-throw.js +1 -1
- package/dist/backend/llvm/dyn.d.ts +10 -10
- package/dist/backend/llvm/dyn.js +26 -26
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.js +156 -47
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/shapes.js +1 -1
- package/dist/backend/llvm/walkers.js +2 -2
- package/dist/backend/llvm/walkers.js.map +1 -1
- package/dist/coverage/surface-manifest.js +16 -2
- package/dist/coverage/surface-manifest.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +21 -8
- package/dist/diagnostics/diagnostic.js +48 -14
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/frontend/lowering/lib-boundary.js +5 -5
- package/dist/frontend/lowering/lib-boundary.js.map +1 -1
- package/dist/frontend/lowering/lower-assert.js +12 -12
- package/dist/frontend/lowering/lower-assert.js.map +1 -1
- package/dist/frontend/lowering/lower-builtins.d.ts +63 -7
- package/dist/frontend/lowering/lower-builtins.js +327 -35
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +4 -4
- package/dist/frontend/lowering/lower-calls.js +104 -70
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +7 -0
- package/dist/frontend/lowering/lower-classes.js +82 -6
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +9 -5
- package/dist/frontend/lowering/lower-containers.js +88 -26
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-emitter.d.ts +70 -3
- package/dist/frontend/lowering/lower-emitter.js +438 -31
- package/dist/frontend/lowering/lower-emitter.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +87 -12
- package/dist/frontend/lowering/lower-exprs.js +630 -125
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.js +5 -5
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-island.js +12 -3
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.d.ts +8 -5
- package/dist/frontend/lowering/lower-modules.js +157 -63
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-namespaces.d.ts +24 -0
- package/dist/frontend/lowering/lower-namespaces.js +158 -16
- package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
- package/dist/frontend/lowering/lower-server.js +11 -11
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.d.ts +1 -1
- package/dist/frontend/lowering/lower-stmts.js +271 -36
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.js +171 -20
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +27 -10
- package/dist/frontend/lowering/lowerer.js +156 -54
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/surfaces.d.ts +44 -0
- package/dist/frontend/lowering/surfaces.js +236 -5
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/npm.d.ts +12 -0
- package/dist/frontend/npm.js +30 -0
- package/dist/frontend/npm.js.map +1 -1
- package/dist/frontend/program.d.ts +25 -0
- package/dist/frontend/program.js +145 -136
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/shared.d.ts +1 -1
- package/dist/frontend/shared.js +8 -8
- package/dist/frontend/shared.js.map +1 -1
- package/dist/frontend/types.d.ts +2 -2
- package/dist/frontend/types.js +15 -15
- package/dist/frontend/types.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +169 -5
- package/dist/index.js.map +1 -1
- package/dist/ir/nodes.d.ts +174 -106
- package/dist/ir/nodes.js +69 -24
- package/dist/ir/nodes.js.map +1 -1
- package/dist/ir/validate.js +55 -36
- package/dist/ir/validate.js.map +1 -1
- package/dist/library/fence-eval.js +12 -2
- package/dist/library/fence-eval.js.map +1 -1
- package/dist/library/int-infer.d.ts +119 -0
- package/dist/library/int-infer.js +1314 -0
- package/dist/library/int-infer.js.map +1 -0
- package/dist/library/int-infer.test.d.ts +1 -0
- package/dist/library/int-infer.test.js +279 -0
- package/dist/library/int-infer.test.js.map +1 -0
- package/dist/library/profile.d.ts +34 -5
- package/dist/library/profile.js +77 -13
- package/dist/library/profile.js.map +1 -1
- package/dist/library/sidecar-validate.js +1 -1
- package/dist/library/sidecar-validate.js.map +1 -1
- package/dist/library/sidecar.d.ts +24 -1
- package/dist/library/sidecar.js +163 -16
- package/dist/library/sidecar.js.map +1 -1
- package/package.json +2 -2
- package/surface-manifest.json +210 -12
|
@@ -4,19 +4,19 @@
|
|
|
4
4
|
* the module artifacts (globals, embedded npm tables) the IR module carries. */
|
|
5
5
|
import * as ts from "../ts7/adapter.js";
|
|
6
6
|
import { dirname as dirnamePath, resolve as resolvePath } from "node:path";
|
|
7
|
-
import { NpmGraphBuilder, packageNameOfPath, probeNodeImportRefusal } from "../npm.js";
|
|
7
|
+
import { NpmGraphBuilder, packageNameOfPath, probeNodeImportRefusal, probeNodeRequireRefusal } from "../npm.js";
|
|
8
8
|
import { isNpmStaticPackage } from "../npm-static.js";
|
|
9
9
|
import { isJsSourceFileName, isRelativeSpecifier } from "../shared.js";
|
|
10
|
-
import { cjsExportAssignmentOf, cjsExportDiscardReason, isCjsJsFile, isJsSourceFile, isRequireStatement, locOf, orderedImportsOf, resolveImport, resolveNpmImport } from "../program.js";
|
|
10
|
+
import { canonicalBuiltinModule, cjsExportAssignmentOf, cjsExportDiscardReason, isCjsJsFile, isJsSourceFile, isRequireStatement, locOf, makeCycleAdmission, orderedImportsOf, resolveImport, resolveNpmImport } from "../program.js";
|
|
11
11
|
import { invalidJsonModuleDiag, npmEmbedFailedDiag, requiresDynamicImportDiag } from "../../diagnostics/diagnostic.js";
|
|
12
12
|
import { BOOL, DYN, JSVAL, RUNTIME_ERROR_CLASSES, STRING, VOID, arrayOf, canConvertToDyn, isUnitType } from "../../ir/nodes.js";
|
|
13
13
|
import { ENTRY_NAME, PoisonError, boundIdentifiersOf, dynFallbackType, dynUndefinedExpr, importCallHandleType, newFnCtx, uncheckedOverloadHandleCall } from "./lowerer.js";
|
|
14
|
-
import { builtinMemberRequireDecl, builtinNamespaceDestructureModuleOf, isPromisifyCall } from "./lower-builtins.js";
|
|
14
|
+
import { builtinMemberRequireDecl, builtinNamespaceDestructureModuleOf, createRequireBindingDecl, createRequireNamespaceDecl, createRequireSpecOf, isPromisifyCall } from "./lower-builtins.js";
|
|
15
15
|
import { bindingContextualGenericFnNodeOf, bindingGenericFnAliasInfoOf, bindingGenericFnInfoOf, bindingGenericFnNodeOf, deadUnmappableBinding, implicitLocalFnInfoOf, implicitLocalFnNodeOf, nullishGenericBindingUnitOf } from "./lower-calls.js";
|
|
16
16
|
import { isVarDeclared, provenanceElidedConstDecl } from "./lower-stmts.js";
|
|
17
17
|
import { streamClassAliasDecl } from "./lower-stream.js";
|
|
18
18
|
import { stdlibGlobalAliasDecl } from "./surfaces.js";
|
|
19
|
-
import {
|
|
19
|
+
import { collectNamespaceStmt, nsPathPrefix, trapDeclRootOf } from "./lower-namespaces.js";
|
|
20
20
|
import { collectExpandoMembers } from "./lower-expando.js";
|
|
21
21
|
import { isUnitOnlyTsType, unitOnlyUnion } from "../types.js";
|
|
22
22
|
import { decoratorNodesOf, genericIfaceBindingKeepsClass, guaranteedDecorationThrow } from "./lower-classes.js";
|
|
@@ -101,10 +101,13 @@ function dynamicProgramImportsOf(program, sf) {
|
|
|
101
101
|
* still evaluates exactly when Node evaluates it: the import() site's
|
|
102
102
|
* namespace builder calls the guarded init on the engine microtask.
|
|
103
103
|
* Fixpoint: an added module's own import() sites are scanned too. Static
|
|
104
|
-
* cycles inside the added subgraph
|
|
105
|
-
* (preflight only walked the entry's static graph,
|
|
106
|
-
* these)
|
|
107
|
-
*
|
|
104
|
+
* cycles inside the added subgraph ride preflight's own admission engine
|
|
105
|
+
* (makeCycleAdmission — preflight only walked the entry's static graph,
|
|
106
|
+
* so it never judged these): benign back edges are Node cache hits the
|
|
107
|
+
* run-once init guards reproduce, and inadmissible ones get preflight's
|
|
108
|
+
* SC1016 with the same narrowed reason via `onCycle`. Idempotent —
|
|
109
|
+
* re-running on an already-extended order adds nothing (both lowering
|
|
110
|
+
* passes share one array). */
|
|
108
111
|
export function appendDynamicImportModules(program, order, onCycle) {
|
|
109
112
|
if (order.length === 0)
|
|
110
113
|
return; // no preflight order — sites keep their fences
|
|
@@ -113,20 +116,31 @@ export function appendDynamicImportModules(program, order, onCycle) {
|
|
|
113
116
|
state.set(sf, "done");
|
|
114
117
|
const added = [];
|
|
115
118
|
const stack = [];
|
|
119
|
+
const staticEdgesOf = (sf) => orderedImportsOf(program, sf).flatMap(({ stmt, dep }) => dep !== null && dep !== sf
|
|
120
|
+
? [{ dep, stmt: stmt }]
|
|
121
|
+
: []);
|
|
122
|
+
const cycleAdmissionReason = makeCycleAdmission(program, staticEdgesOf);
|
|
116
123
|
const visit = (sf) => {
|
|
117
|
-
|
|
118
|
-
if (s === "done")
|
|
124
|
+
if (state.get(sf) !== undefined)
|
|
119
125
|
return;
|
|
120
|
-
if (s === "visiting") {
|
|
121
|
-
const cycleStart = stack.indexOf(sf.fileName);
|
|
122
|
-
onCycle([...stack.slice(cycleStart), sf.fileName].join(" → "));
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
126
|
state.set(sf, "visiting");
|
|
126
127
|
stack.push(sf.fileName);
|
|
127
|
-
for (const
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
for (const e of staticEdgesOf(sf)) {
|
|
129
|
+
const s = state.get(e.dep);
|
|
130
|
+
if (s === "done")
|
|
131
|
+
continue;
|
|
132
|
+
if (s === "visiting") {
|
|
133
|
+
// A back edge: Node answers it from the cache. Same admission
|
|
134
|
+
// question as preflight's static walk, same fence when refused.
|
|
135
|
+
const reason = cycleAdmissionReason(sf, e);
|
|
136
|
+
if (reason !== null) {
|
|
137
|
+
const cycleStart = stack.indexOf(e.dep.fileName);
|
|
138
|
+
onCycle([...stack.slice(cycleStart), e.dep.fileName].join(" → "), reason);
|
|
139
|
+
}
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
visit(e.dep);
|
|
143
|
+
}
|
|
130
144
|
stack.pop();
|
|
131
145
|
state.set(sf, "done");
|
|
132
146
|
added.push(sf);
|
|
@@ -356,6 +370,8 @@ export function collectNpmImports(L, parts) {
|
|
|
356
370
|
if (builder) {
|
|
357
371
|
for (const fp of parts)
|
|
358
372
|
collectDynamicImports(L, builder, fp.sf);
|
|
373
|
+
for (const fp of parts)
|
|
374
|
+
collectCreateRequires(L, builder, fp.sf);
|
|
359
375
|
const graph = builder.finish();
|
|
360
376
|
if (graph.modules.length > 0) {
|
|
361
377
|
L.npmEmbedded = { modules: graph.modules, edges: graph.edges };
|
|
@@ -410,6 +426,47 @@ function collectDynamicImports(L, builder, sf) {
|
|
|
410
426
|
};
|
|
411
427
|
visit(sf);
|
|
412
428
|
}
|
|
429
|
+
/** The createRequire half of the npm chokepoint (--dynamic only): every
|
|
430
|
+
* `require("bare-literal")` through a createRequire binding — whatever
|
|
431
|
+
* body it sits in — resolves under Node's "require" condition and
|
|
432
|
+
* embeds AT COLLECTION time, so the per-site lowering later just looks
|
|
433
|
+
* its entry up (lowerCreateRequireCall). Builtins, relative documents,
|
|
434
|
+
* "#" specifiers, --npm-static opt-ins, and Node-refused bare names
|
|
435
|
+
* are the lowering's own arms — only resolvable installed packages
|
|
436
|
+
* register here; resolution failures are diagnostics at the call
|
|
437
|
+
* expression, exactly like static npm imports at their statements. */
|
|
438
|
+
function collectCreateRequires(L, builder, sf) {
|
|
439
|
+
const visit = (node) => {
|
|
440
|
+
if (ts.isCallExpression(node)) {
|
|
441
|
+
const cr = createRequireSpecOf(L, node);
|
|
442
|
+
const spec = cr?.spec ?? null;
|
|
443
|
+
if (cr !== null &&
|
|
444
|
+
spec !== null &&
|
|
445
|
+
canonicalBuiltinModule(spec) === null &&
|
|
446
|
+
!isRelativeSpecifier(spec) &&
|
|
447
|
+
!spec.startsWith("/") &&
|
|
448
|
+
!spec.startsWith("#") &&
|
|
449
|
+
probeNodeRequireRefusal(cr.baseFile.fileName, spec) === null) {
|
|
450
|
+
const pkgName = spec.startsWith("@")
|
|
451
|
+
? spec.split("/").slice(0, 2).join("/")
|
|
452
|
+
: spec.split("/")[0];
|
|
453
|
+
const mapKey = `${cr.baseFile.fileName}\u0000${spec}`;
|
|
454
|
+
if (!L.createRequireImports.has(mapKey) && !isNpmStaticPackage(pkgName)) {
|
|
455
|
+
const before = builder.errors.length;
|
|
456
|
+
const entryKey = builder.addRequire(cr.baseFile.fileName, spec);
|
|
457
|
+
for (const err of builder.errors.slice(before)) {
|
|
458
|
+
L.pushDiag(npmEmbedFailedDiag(err.message, locOf(node)));
|
|
459
|
+
}
|
|
460
|
+
L.createRequireImports.set(mapKey, entryKey === null
|
|
461
|
+
? ""
|
|
462
|
+
: { entryKey, format: builder.moduleFormatOf(entryKey) ?? "cjs" });
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
ts.forEachChild(node, visit);
|
|
467
|
+
};
|
|
468
|
+
visit(sf);
|
|
469
|
+
}
|
|
413
470
|
/** JSON module default imports (`import pkg from "../package.json"`):
|
|
414
471
|
* the document is DATA known at build time, so the binding bakes into a
|
|
415
472
|
* record global — the checker's structural type for the module (thanks
|
|
@@ -639,7 +696,7 @@ function cjsScalarLiteral(e) {
|
|
|
639
696
|
/** True when a JS file-scope declaration's initializer provably LOWERS to
|
|
640
697
|
* a checked-dynamic (or unit) value, so a DYN module global can hold it:
|
|
641
698
|
* no initializer, a unit literal, or a checker-`any` call/member/
|
|
642
|
-
* identifier read (any-typed operations lower through the
|
|
699
|
+
* identifier read (any-typed operations lower through the checked-dynamic tree in JS).
|
|
643
700
|
* `new` expressions stay OUT even when checker-any (`new Anon.Sub()` over
|
|
644
701
|
* an expando class member constructs a TYPED instance — corpus 2032), as
|
|
645
702
|
* does everything else (object/array literals have their own rules;
|
|
@@ -661,7 +718,7 @@ function jsDynHoldableInitializer(L, init) {
|
|
|
661
718
|
// A CALL whose inferred type has no static mapping and whose residue
|
|
662
719
|
// falls to the checked-dynamic kind (`const exec = common.mustCall(() =>
|
|
663
720
|
// ... exec ...)` — the wrapper's rest-args type is not checker-`any`,
|
|
664
|
-
// but the VALUE lowers through the
|
|
721
|
+
// but the VALUE lowers through the checked-dynamic tree the same way): registering the
|
|
665
722
|
// dyn global BEFORE the initializer lowers is what lets the callback
|
|
666
723
|
// capture the binding itself — the Node-suite self-referential-const
|
|
667
724
|
// idiom. Non-dyn residues (pure single-signature function types, typed
|
|
@@ -802,7 +859,7 @@ export function collectGlobals(L, sf, topStmts) {
|
|
|
802
859
|
const t = L.mapTypeOf(strict) ?? dynFallbackType(L, nameNode, strict);
|
|
803
860
|
if (!t || t.kind === "void")
|
|
804
861
|
L.badType(typeNode, strict);
|
|
805
|
-
// `module.exports.Strings = Strings` naming a
|
|
862
|
+
// `module.exports.Strings = Strings` naming a dyn-HOLDING
|
|
806
863
|
// const (the JS file-scope object-literal identity story): the
|
|
807
864
|
// export ALIASES the const's own dyn global — one storage, one
|
|
808
865
|
// owner, identity by construction (a record-typed second slot
|
|
@@ -826,7 +883,7 @@ export function collectGlobals(L, sf, topStmts) {
|
|
|
826
883
|
L.globalsByDeclNode.set(d, vG);
|
|
827
884
|
return;
|
|
828
885
|
}
|
|
829
|
-
// A mutable (`let`)
|
|
886
|
+
// A mutable (`let`) dyn source: separate DYN storage IS
|
|
830
887
|
// Node's copy-of-the-reference at this statement (later
|
|
831
888
|
// reassignments of the let stay invisible through the
|
|
832
889
|
// export). The id must not collide with the let's own
|
|
@@ -1025,37 +1082,65 @@ export function collectGlobals(L, sf, topStmts) {
|
|
|
1025
1082
|
// and put its fences on the build.
|
|
1026
1083
|
if (provenanceElidedConstDecl(L, decl))
|
|
1027
1084
|
continue;
|
|
1028
|
-
//
|
|
1029
|
-
//
|
|
1030
|
-
//
|
|
1031
|
-
//
|
|
1032
|
-
//
|
|
1033
|
-
//
|
|
1034
|
-
//
|
|
1035
|
-
//
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1085
|
+
// The trap/nullish/dead classification probes below resolve
|
|
1086
|
+
// symbols INSIDE the initializer, and resolution can fence (the
|
|
1087
|
+
// cross-block merged-namespace SC1090, resolveValueSymbol →
|
|
1088
|
+
// fenceCrossBlockNsRef): a fence mid-probe means the probe cannot
|
|
1089
|
+
// classify the declaration, not that collection dies — the
|
|
1090
|
+
// diagnostic is recorded, the binding falls through to ordinary
|
|
1091
|
+
// registration, and the statement lowering re-fences at its own
|
|
1092
|
+
// site (pushDiag dedupes), exactly the per-probe recovery the
|
|
1093
|
+
// alias/generic-fn registrations below already use.
|
|
1094
|
+
const classifyDiagsBefore = L.diags.length;
|
|
1095
|
+
const classified = (() => {
|
|
1096
|
+
try {
|
|
1097
|
+
// A TRAP declaration at file scope — the initializer's chain roots
|
|
1098
|
+
// at an ambient-undefined name (`declare const t: Type<string>;
|
|
1099
|
+
// export const out = t.pipe(...)`): Node throws the root's
|
|
1100
|
+
// ReferenceError evaluating the initializer, so no value ever
|
|
1101
|
+
// exists and no reference can ever run. No global registers; the
|
|
1102
|
+
// binding enters trapBindings (registered HERE, before any body
|
|
1103
|
+
// lowers, so hoisted-function references resolve the trap), and
|
|
1104
|
+
// the statement lowering emits the throw at its position.
|
|
1105
|
+
// Written bindings keep ordinary storage (trapDeclRootOf).
|
|
1106
|
+
if (trapDeclRootOf(L, decl) !== null) {
|
|
1107
|
+
for (const nameNode of boundIdentifiersOf(decl.name)) {
|
|
1108
|
+
const sym = L.checker.getSymbolAtLocation(nameNode);
|
|
1109
|
+
if (sym)
|
|
1110
|
+
L.trapBindings.add(sym);
|
|
1111
|
+
}
|
|
1112
|
+
return true;
|
|
1113
|
+
}
|
|
1114
|
+
// A NULLISH generic binding at file scope (`export const Mixin:
|
|
1115
|
+
// MixinHelperFunc = null as any`): no storage — reads know the
|
|
1116
|
+
// value (lower-exprs/lower-calls claim them); the statement
|
|
1117
|
+
// lowering emits nothing by the same test.
|
|
1118
|
+
if (ts.isIdentifier(decl.name) &&
|
|
1119
|
+
nullishGenericBindingUnitOf(L, L.checker.getSymbolAtLocation(decl.name) ?? null) !== null) {
|
|
1120
|
+
return true;
|
|
1121
|
+
}
|
|
1122
|
+
// A DEAD unmappable binding at file scope (`var xs2: typeof
|
|
1123
|
+
// Array;` — never read anywhere): no global, no statement, no
|
|
1124
|
+
// type fence for a value the program never consumes.
|
|
1125
|
+
if (ts.isIdentifier(decl.name) &&
|
|
1126
|
+
deadUnmappableBinding(L, L.checker.getSymbolAtLocation(decl.name) ?? null, decl)) {
|
|
1127
|
+
return true;
|
|
1128
|
+
}
|
|
1041
1129
|
}
|
|
1130
|
+
catch (e) {
|
|
1131
|
+
if (!(e instanceof PoisonError))
|
|
1132
|
+
throw e;
|
|
1133
|
+
// A probe fenced mid-classification: JS files defer the
|
|
1134
|
+
// recorded diagnostics to runtime fences like every other
|
|
1135
|
+
// collection failure; TS keeps the eager report (the
|
|
1136
|
+
// statement lowering re-fences at its own site — pushDiag
|
|
1137
|
+
// dedupes).
|
|
1138
|
+
deferJsCollectionDiags(L, sf, classifyDiagsBefore);
|
|
1139
|
+
}
|
|
1140
|
+
return false;
|
|
1141
|
+
})();
|
|
1142
|
+
if (classified)
|
|
1042
1143
|
continue;
|
|
1043
|
-
}
|
|
1044
|
-
// A NULLISH generic binding at file scope (`export const Mixin:
|
|
1045
|
-
// MixinHelperFunc = null as any`): no storage — reads know the
|
|
1046
|
-
// value (lower-exprs/lower-calls claim them); the statement
|
|
1047
|
-
// lowering emits nothing by the same test.
|
|
1048
|
-
if (ts.isIdentifier(decl.name) &&
|
|
1049
|
-
nullishGenericBindingUnitOf(L, L.checker.getSymbolAtLocation(decl.name) ?? null) !== null) {
|
|
1050
|
-
continue;
|
|
1051
|
-
}
|
|
1052
|
-
// A DEAD unmappable binding at file scope (`var xs2: typeof
|
|
1053
|
-
// Array;` — never read anywhere): no global, no statement, no
|
|
1054
|
-
// type fence for a value the program never consumes.
|
|
1055
|
-
if (ts.isIdentifier(decl.name) &&
|
|
1056
|
-
deadUnmappableBinding(L, L.checker.getSymbolAtLocation(decl.name) ?? null, decl)) {
|
|
1057
|
-
continue;
|
|
1058
|
-
}
|
|
1059
1144
|
// `const f = <T>(x: T) => x` at file scope: a generic function
|
|
1060
1145
|
// value binding — no global exists (the binding is never read;
|
|
1061
1146
|
// calls and pinned references monomorphize against the
|
|
@@ -1163,6 +1248,15 @@ export function collectGlobals(L, sf, topStmts) {
|
|
|
1163
1248
|
// same test.
|
|
1164
1249
|
if (builtinMemberRequireDecl(decl.name, decl.initializer))
|
|
1165
1250
|
continue;
|
|
1251
|
+
// `const require = createRequire(import.meta.url)` at file scope:
|
|
1252
|
+
// compile-time plumbing — no global storage; the statement
|
|
1253
|
+
// lowering skips it by the same test.
|
|
1254
|
+
if (isConst && createRequireBindingDecl(L, decl.name, decl.initializer))
|
|
1255
|
+
continue;
|
|
1256
|
+
// `const fs = require("node:fs")` through that binding at file
|
|
1257
|
+
// scope — a namespace import in const clothing, same story.
|
|
1258
|
+
if (isConst && createRequireNamespaceDecl(L, decl.name, decl.initializer))
|
|
1259
|
+
continue;
|
|
1166
1260
|
// `const { createSign } = crypto` over a builtin NAMESPACE binding
|
|
1167
1261
|
// at file scope: alias plumbing like the destructured-require form
|
|
1168
1262
|
// — no storage (the statement lowering skips by the same test).
|
|
@@ -1194,7 +1288,7 @@ export function collectGlobals(L, sf, topStmts) {
|
|
|
1194
1288
|
try {
|
|
1195
1289
|
// A JS file-scope evolving ARRAY (`const mustCallChecks = [];`
|
|
1196
1290
|
// — test/common's exit-accounting ledger): the strict type
|
|
1197
|
-
// (any[]) has no mapping, but the VALUE is the
|
|
1291
|
+
// (any[]) has no mapping, but the VALUE is the dyn array the
|
|
1198
1292
|
// literal builds (lowerArrayLiteral's JS fallback) — register
|
|
1199
1293
|
// a checked-dynamic global so separately-declared function
|
|
1200
1294
|
// bodies (runCallChecks, _mustCallInner) reach the SAME
|
|
@@ -1217,11 +1311,11 @@ export function collectGlobals(L, sf, topStmts) {
|
|
|
1217
1311
|
// the literal's contract — the SAME object flows into untyped
|
|
1218
1312
|
// callees, gets stamped by them, and is compared back against
|
|
1219
1313
|
// the binding (assert.strictEqual(found, input)). A static
|
|
1220
|
-
// record global would re-box at every
|
|
1221
|
-
// that identity, so the binding holds the
|
|
1314
|
+
// record global would re-box at every dyn crossing and lose
|
|
1315
|
+
// that identity, so the binding holds the dyn object itself.
|
|
1222
1316
|
// Gated to literals that are PURE DATA WRITTEN INLINE — every
|
|
1223
1317
|
// property a non-computed PropertyAssignment whose value is
|
|
1224
|
-
// dyn-representable (unmappable member types are the
|
|
1318
|
+
// dyn-representable (unmappable member types are the checked-dynamic tree
|
|
1225
1319
|
// fallback's own case) — so shorthand aggregates (test/common's
|
|
1226
1320
|
// export object: alias plumbing importers resolve THROUGH),
|
|
1227
1321
|
// spreads, accessors, and literals holding unconvertible typed
|
|
@@ -1245,7 +1339,7 @@ export function collectGlobals(L, sf, topStmts) {
|
|
|
1245
1339
|
continue;
|
|
1246
1340
|
}
|
|
1247
1341
|
// A JS file-scope ANY-RESIDUE binding whose VALUE provably
|
|
1248
|
-
// lives in the
|
|
1342
|
+
// lives in the checked-dynamic tree: no initializer (`let catchWarning;` —
|
|
1249
1343
|
// test/common's warning ledger), a unit initializer (`let
|
|
1250
1344
|
// localhostIPv4 = null;` — the lazy-cache idiom), or an
|
|
1251
1345
|
// initializer whose own checker type is `any` (`const handler
|
|
@@ -1255,7 +1349,7 @@ export function collectGlobals(L, sf, topStmts) {
|
|
|
1255
1349
|
// storage instead of fencing per reference. Typed-but-
|
|
1256
1350
|
// unmappable initializers (`new Set(...)` — a real Set the
|
|
1257
1351
|
// decl keeps as an %init local) stay OUT: forcing those into
|
|
1258
|
-
// the
|
|
1352
|
+
// the checked-dynamic tree would trade their working typed representation for
|
|
1259
1353
|
// fences.
|
|
1260
1354
|
if (isJsSourceFile(sf) && !L.mapTypeOf(L.typeOf(nameNode)) &&
|
|
1261
1355
|
ts.isIdentifier(decl.name) && nameNode === decl.name &&
|
|
@@ -1266,7 +1360,7 @@ export function collectGlobals(L, sf, topStmts) {
|
|
|
1266
1360
|
const g = { id: `%g.${tag}${nsPrefix}${nameNode.text}`, name: nameNode.text, type: DYN, mutable: isLet };
|
|
1267
1361
|
L.globalsBySymbol.set(symbol, g);
|
|
1268
1362
|
L.globalsList.push(g);
|
|
1269
|
-
// Mutable dyn globals hold the
|
|
1363
|
+
// Mutable dyn globals hold the dyn undefined from module
|
|
1270
1364
|
// entry (the main path's rule below): a closure called
|
|
1271
1365
|
// above the declaration reads undefined instead of
|
|
1272
1366
|
// faulting on NULL.
|
|
@@ -1370,7 +1464,7 @@ export function collectGlobals(L, sf, topStmts) {
|
|
|
1370
1464
|
// infers a record (`const wrapped = function () { return
|
|
1371
1465
|
// expectedResult; }`): the closure VALUE lowers with a dyn
|
|
1372
1466
|
// return (declaredReturnType's record twin — JS object
|
|
1373
|
-
// literals are
|
|
1467
|
+
// literals are dyn values, and a record return would copy
|
|
1374
1468
|
// identity away), so the binding's slot must agree or an
|
|
1375
1469
|
// adapter would re-copy at the assignment.
|
|
1376
1470
|
if (isJsSourceFile(sf) &&
|
|
@@ -1407,7 +1501,7 @@ export function collectGlobals(L, sf, topStmts) {
|
|
|
1407
1501
|
L.globalsList.push(g);
|
|
1408
1502
|
// Mutable checked-dynamic LET globals ride the same entry
|
|
1409
1503
|
// init: a closure called above the declaration statement
|
|
1410
|
-
// reads the
|
|
1504
|
+
// reads the dyn undefined instead of faulting on NULL — the
|
|
1411
1505
|
// dyn face of let's documented pre-declaration window (Node
|
|
1412
1506
|
// throws the TDZ ReferenceError there).
|
|
1413
1507
|
if (isVarDeclared(decl) || (g.type.kind === "dyn" && g.mutable)) {
|
|
@@ -1457,7 +1551,7 @@ function handleArrayPreservingCall(L, e) {
|
|
|
1457
1551
|
* must hold the interned undefined arm BEFORE the body runs (a function
|
|
1458
1552
|
* called above the declaration statement may read it — lowerFileInit
|
|
1459
1553
|
* emits the assigns right after the run-once guard). Checked-dynamic
|
|
1460
|
-
* slots hold the
|
|
1554
|
+
* slots hold the dyn undefined the same way (a NULL dyn is a trap, not
|
|
1461
1555
|
* a value). Other types need nothing: tsc's flow analysis rejects their
|
|
1462
1556
|
* direct early reads, and closure reads share let's documented
|
|
1463
1557
|
* zero/NULL divergence window. */
|
|
@@ -1465,7 +1559,7 @@ function noteVarGlobalEntryInit(L, sf, g) {
|
|
|
1465
1559
|
// 'any' globals need the entry init exactly like undefined-armed
|
|
1466
1560
|
// unions: tsc never guards `any` reads, so `var x: any;` is readable
|
|
1467
1561
|
// before any assignment and its slot must hold its world's undefined
|
|
1468
|
-
// — the ENGINE's for jsval (--dynamic), the
|
|
1562
|
+
// — the ENGINE's for jsval (--dynamic), the checked-dynamic tree's for dyn (static) —
|
|
1469
1563
|
// rather than a C-level NULL (an op or validated exit on NULL is
|
|
1470
1564
|
// memory-unsafe, not a TypeError).
|
|
1471
1565
|
if (g.type.kind !== "union" && g.type.kind !== "jsval" && g.type.kind !== "dyn")
|
|
@@ -1667,7 +1761,7 @@ export function lowerFileInit(L, sf, stmts, name) {
|
|
|
1667
1761
|
// Module-scope `var` hoisting: undefined-armed var globals hold the
|
|
1668
1762
|
// interned undefined from module entry (before any body statement —
|
|
1669
1763
|
// a function called above the declaration reads `undefined`, exactly
|
|
1670
|
-
// Node); checked-dynamic var globals hold the
|
|
1764
|
+
// Node); checked-dynamic var globals hold the dyn undefined the same
|
|
1671
1765
|
// way. After the guard: a cache-hit revisit must not reset them.
|
|
1672
1766
|
for (const g of L.varGlobalEntryInits.get(sf) ?? []) {
|
|
1673
1767
|
const wrapped = g.type.kind === "dyn" ? dynUndefinedExpr(loc0) : L.unassignedSlotInit(g.type, loc0);
|