@scriptc/compiler 0.0.2 → 0.0.4
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 +145 -9
- package/dist/backend/cc.d.ts +7 -0
- package/dist/backend/cc.js +1 -0
- package/dist/backend/cc.js.map +1 -1
- package/dist/backend/emission/emit-exprs.js +35 -0
- package/dist/backend/emission/emit-exprs.js.map +1 -1
- package/dist/backend/emission/emit-shapes.js +1 -0
- package/dist/backend/emission/emit-shapes.js.map +1 -1
- package/dist/backend/emission/emitter.js +15 -3
- package/dist/backend/emission/emitter.js.map +1 -1
- package/dist/backend/llvm/emitter.js +65 -11
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/shapes.js +1 -0
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/coverage/surface-manifest.d.ts +22 -0
- package/dist/coverage/surface-manifest.js +295 -0
- package/dist/coverage/surface-manifest.js.map +1 -0
- package/dist/diagnostics/diagnostic.d.ts +16 -0
- package/dist/diagnostics/diagnostic.js +26 -2
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/frontend/lowering/lib-boundary.js +76 -6
- package/dist/frontend/lowering/lib-boundary.js.map +1 -1
- package/dist/frontend/lowering/lower-builtins.d.ts +37 -4
- package/dist/frontend/lowering/lower-builtins.js +240 -6
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.js +122 -32
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +34 -2
- package/dist/frontend/lowering/lower-classes.js +256 -33
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.js +25 -3
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +10 -0
- package/dist/frontend/lowering/lower-exprs.js +410 -9
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.d.ts +16 -1
- package/dist/frontend/lowering/lower-inspect.js +132 -5
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-island.js +24 -3
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.d.ts +6 -5
- package/dist/frontend/lowering/lower-modules.js +56 -18
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +56 -0
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +57 -1
- package/dist/frontend/lowering/lowerer.js +291 -10
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/surfaces.d.ts +9 -2
- package/dist/frontend/lowering/surfaces.js +44 -7
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/npm.js +2 -2
- package/dist/frontend/npm.js.map +1 -1
- package/dist/frontend/program.js +59 -8
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/resolve.js +120 -5
- package/dist/frontend/resolve.js.map +1 -1
- package/dist/frontend/shared.d.ts +8 -2
- package/dist/frontend/shared.js +22 -6
- package/dist/frontend/shared.js.map +1 -1
- package/dist/frontend/ts7/checker.js +1 -1
- package/dist/frontend/ts7/checker.js.map +1 -1
- package/dist/frontend/types.d.ts +25 -1
- package/dist/frontend/types.js +121 -7
- package/dist/frontend/types.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/ir/nodes.d.ts +43 -1
- package/dist/ir/nodes.js +41 -0
- package/dist/ir/nodes.js.map +1 -1
- package/dist/ir/validate.js +38 -6
- package/dist/ir/validate.js.map +1 -1
- package/package.json +6 -4
- package/surface-manifest.json +2117 -0
|
@@ -33,6 +33,10 @@ export type WidthLift = {
|
|
|
33
33
|
how: "width";
|
|
34
34
|
} | {
|
|
35
35
|
how: "arr";
|
|
36
|
+
} | {
|
|
37
|
+
how: "tupleArr";
|
|
38
|
+
} | {
|
|
39
|
+
how: "emptyArr";
|
|
36
40
|
} | {
|
|
37
41
|
how: "objWidth";
|
|
38
42
|
} | {
|
|
@@ -436,6 +440,12 @@ export declare class Lowerer {
|
|
|
436
440
|
/** Synthetic URLSearchParams.forEach loop functions, interned per
|
|
437
441
|
* callback arity/return — Map's pattern over the sp index walk. */
|
|
438
442
|
readonly spHofHelpers: Map<string, string>;
|
|
443
|
+
/** The primitive-constructor VALUES (`String`/`Number`/`Boolean` as
|
|
444
|
+
* bare identifiers — CLI option tables store and compare them): one
|
|
445
|
+
* synthesized coercion function per constructor per program, interned
|
|
446
|
+
* here by name so every reference is the SAME zero-capture closure and
|
|
447
|
+
* `opt.type === String` is JS identity (see primitiveCtorClosure). */
|
|
448
|
+
readonly primitiveCtorFns: Map<string, string>;
|
|
439
449
|
/** Optional-chain lowering state. While a chain body lowers, the guarded
|
|
440
450
|
* receiver NODE reads as a chainRecv (typed by the narrowed arm) instead
|
|
441
451
|
* of re-lowering, its checker type reads non-nullish (typeOf), and the
|
|
@@ -672,6 +682,17 @@ export declare class Lowerer {
|
|
|
672
682
|
* point for deferred collection diagnostics: resolving a reference to a
|
|
673
683
|
* broken declaration reports what collection deferred. */
|
|
674
684
|
resolveValueSymbol(ident: ts.Identifier): ts.Symbol | null;
|
|
685
|
+
/** The default-snapshot storage symbol a DEFAULT-import alias chain
|
|
686
|
+
* lands on, or null. A mutable entity-name default (`export default
|
|
687
|
+
* someLet`) registers its Node-semantics snapshot global under the
|
|
688
|
+
* exporter's default ALIAS symbol; the checker's getAliasedSymbol
|
|
689
|
+
* resolves through that symbol to the live let, so this walk follows
|
|
690
|
+
* the default hops syntactically — default import clauses, `{ default
|
|
691
|
+
* as x }` specifiers, `export { default } from` re-exports — and stops
|
|
692
|
+
* at the first default symbol carrying registered storage. Local
|
|
693
|
+
* `export { x as default }` specifiers (no module specifier) are LIVE
|
|
694
|
+
* bindings in Node and fall through to ordinary alias resolution. */
|
|
695
|
+
private defaultSnapshotSymbolOf;
|
|
675
696
|
/** A module's CJS export-table member symbol by NAME (the checker's
|
|
676
697
|
* module-symbol exports map — present in tsgo even where no expando
|
|
677
698
|
* property symbol exists at the attachment/use sites). */
|
|
@@ -734,6 +755,15 @@ export declare class Lowerer {
|
|
|
734
755
|
collectNpmImports(parts: FileParts[]): void;
|
|
735
756
|
collectJsonImports(parts: FileParts[]): void;
|
|
736
757
|
run(): LowerResult;
|
|
758
|
+
/** The unregistered-class type sweep (run()'s last step before the
|
|
759
|
+
* module assembles): every `{kind:"object"}` TYPE naming a class with
|
|
760
|
+
* no registered ClassInfo is rewritten IN PLACE to the f64 dummy.
|
|
761
|
+
* classval types are exempt (they emit the class-independent
|
|
762
|
+
* `ScrClassObj *` — inert-but-valid storage, the validator's own
|
|
763
|
+
* stance), and only type objects rewrite — node-level classNames
|
|
764
|
+
* (`new`, upcasts) cannot reach here (their lowerings fence without a
|
|
765
|
+
* registered class), so the validator still backstops those. */
|
|
766
|
+
sanitizeUnregisteredClassTypes(roots: unknown[]): void;
|
|
737
767
|
/** True when `t` (recursively) names a class instance type with no
|
|
738
768
|
* registered ClassInfo — the shape of a JS class whose collection fenced.
|
|
739
769
|
* Used by run()'s global pruning; shapes/unions recurse with a seen-set
|
|
@@ -904,6 +934,9 @@ export declare class Lowerer {
|
|
|
904
934
|
* copy loop, arrayWidthHelper)
|
|
905
935
|
* Null when the pair isn't in the relation — callers keep their fences. */
|
|
906
936
|
widthLiftPlan(src: IrType, dst: IrType): WidthLift | null;
|
|
937
|
+
/** True for the unit-only element types (`(null | undefined)[]`, the
|
|
938
|
+
* `readonly []` mapping): a union whose every arm is a unit. */
|
|
939
|
+
unitOnlyElem(t: IrType): boolean;
|
|
907
940
|
/** The build side of widthLiftPlan: the IrExpr converting `value` into
|
|
908
941
|
* `dst` under a plan the caller validated. Interns whatever helpers the
|
|
909
942
|
* lift needs (planned first, so the interns cannot fail — a failure here
|
|
@@ -932,6 +965,8 @@ export declare class Lowerer {
|
|
|
932
965
|
} | {
|
|
933
966
|
absent: true;
|
|
934
967
|
utag: number;
|
|
968
|
+
} | {
|
|
969
|
+
absentDyn: true;
|
|
935
970
|
}> | null;
|
|
936
971
|
recordWidthHelper(fromId: string, toId: string, loc: SrcLoc): string | null;
|
|
937
972
|
/** Interned `%arr.width.<n>(a)` — the per-element copy loop over
|
|
@@ -947,6 +982,16 @@ export declare class Lowerer {
|
|
|
947
982
|
tupleArrayWidthHelper(fromId: string, toT: IrType & {
|
|
948
983
|
kind: "array";
|
|
949
984
|
}, loc: SrcLoc): string | null;
|
|
985
|
+
/** Interned `%arr.empty.<n>(a)` — the EMPTY-array lift's build side: a
|
|
986
|
+
* unit-only-element array reshapes into any data-element array by
|
|
987
|
+
* answering a FRESH empty array, after a runtime non-empty trap (a
|
|
988
|
+
* genuinely inhabited `(null | undefined)[]` cannot reshape — the
|
|
989
|
+
* catchable-TypeError stance every checked extraction takes). */
|
|
990
|
+
emptyArrayLiftHelper(fromT: IrType & {
|
|
991
|
+
kind: "array";
|
|
992
|
+
}, toT: IrType & {
|
|
993
|
+
kind: "array";
|
|
994
|
+
}, loc: SrcLoc): string;
|
|
950
995
|
arrayWidthHelper(fromT: IrType & {
|
|
951
996
|
kind: "array";
|
|
952
997
|
}, toT: IrType & {
|
|
@@ -1145,6 +1190,17 @@ export declare class Lowerer {
|
|
|
1145
1190
|
* impossible value flow on). Null when the target isn't a non-unit arm
|
|
1146
1191
|
* of the union — those uses keep their erasure/fences. */
|
|
1147
1192
|
narrowedArmHelper(fromId: string, target: IrType, loc: SrcLoc): string | null;
|
|
1193
|
+
/** The DEFERRED-INIT field read (`stream!: T` assigned past the
|
|
1194
|
+
* constructor's top level — the slot is `T | undefined`): interned
|
|
1195
|
+
* `%deferred.read.<n>(u)` extracting the declared type. SCALAR arms
|
|
1196
|
+
* whose JS-undefined behavior a unit default reproduces read that
|
|
1197
|
+
* default — bool false (conditions are exact: undefined and false are
|
|
1198
|
+
* both falsy; only printing/strict-equality could tell) and f64 NaN
|
|
1199
|
+
* (arithmetic and conditions exact) — while string and REF arms keep
|
|
1200
|
+
* the checked-extraction TRAP: JS itself TypeErrors the first member
|
|
1201
|
+
* use of such an undefined, so the catchable TypeError at the read is
|
|
1202
|
+
* the same failure, named earlier (SEMANTICS.md). */
|
|
1203
|
+
deferredReadHelper(fromId: string, target: IrType, loc: SrcLoc): string | null;
|
|
1148
1204
|
/** True when a static value can become ONE island value: jsval itself,
|
|
1149
1205
|
* anything boundary-safe (the deep JSON marshal), a record whose fields
|
|
1150
1206
|
* all can (built as an island OBJECT literal, field by field), or an
|
|
@@ -1625,7 +1681,7 @@ export declare class Lowerer {
|
|
|
1625
1681
|
rejectComptimeCaptures(cb: ts.ArrowFunction | ts.FunctionExpression): void;
|
|
1626
1682
|
comptimeValueToIr(value: unknown, expected: IrType, path: string, blame: ts.Node): IrExpr;
|
|
1627
1683
|
isConsoleLog(call: ts.CallExpression): boolean;
|
|
1628
|
-
consoleCallMember(call: ts.CallExpression): "log" | "error" | "warn" | null;
|
|
1684
|
+
consoleCallMember(call: ts.CallExpression): "log" | "info" | "debug" | "error" | "warn" | null;
|
|
1629
1685
|
builtinImportOf(ident: ts.Identifier): {
|
|
1630
1686
|
module: string;
|
|
1631
1687
|
member: string;
|
|
@@ -20,7 +20,7 @@ import { provenanceActive } from "../provenance-registry.js";
|
|
|
20
20
|
import { ambientDtsPath, canonicalBuiltinModule, cjsExportAssignmentOf, cjsExportDiscardReason, fallbackDtsPath, isCjsExportTableLiteral, isJsSourceFile, isNodeEsmFile, isNodeTypesPath, locOf, overridesDtsPath, requireSpecOf, resolveImport, workspacePackageOfPath, } from "../program.js";
|
|
21
21
|
import { containsRecord, containsUnion, formatIrType, ISLAND_AMBIENT_TYPES, isUnitOnlyTsType, mapType, ShapeRegistry, typeKey, UnionRegistry, withUndefinedArm as withUndefinedArmCanonical, } from "../types.js";
|
|
22
22
|
import { boundaryIntoIslandMsg, boundaryOutOfIslandMsg, builtinConstLit, builtinModuleConstOf, builtinFenceHintOf, builtinModuleFnOf, stdlibMemberFence, isStdlibMember, isStdlibSymbol, isStdlibGlobal, stdlibGlobalMember, nodeTypesOnlySymbol } from "./surfaces.js";
|
|
23
|
-
import { splitFiles, collectProgram, collectNpmImports, collectJsonImports, moduleArtifacts, collectGlobals, declSymbolOf, lowerFileInit, lowerDefaultExport, buildMain, appendDynamicImportModules } from "./lower-modules.js";
|
|
23
|
+
import { splitFiles, collectProgram, collectNpmImports, collectJsonImports, moduleArtifacts, collectGlobals, declSymbolOf, defaultExportSymbolOf, lowerFileInit, lowerDefaultExport, buildMain, appendDynamicImportModules } from "./lower-modules.js";
|
|
24
24
|
import { registerBuiltinErrorClasses, registerBuiltinEmitterClass, registerBuiltinStreamClasses, builtinErrorInfoOf, builtinEmitterInfoOf, builtinStreamInfoOf, analyzeClassDecoration, classIteratorDrainCall, classIteratorNextCall, classIteratorOf, classIteratorOpenCall, classIteratorRestDrainCall, classMemberNameOf, classValueRef, collectClassShape, exactClassOfReceiver, collectClassShapeInner, ctorAbiEquals, findMethodOn, findStaticOn, findGenericMethodOn, findGenericStaticOn, genericClassInstanceType, isSubclassOf, inHierarchy, overrideBelow, staticShadowBelow, upcastTo, lowerClassMembers, lowerClassCtor, lowerClassExpression, lowerClassExpressionInfo, lowerClassMethodMember, lowerClassValueProperty, lowerStaticMethod, throwingSetterFn, fieldInitStmts, lowerStaticFieldInits, lowerStaticFieldRead, lowerDerivedCtorBody, superCallStmt, lowerSuperMethodCall, superThisRef, lowerSuperAccessorRead, lowerSuperAccessorWrite, inheritsBuiltinErrorCtor, inheritsBuiltinEmitterCtor, errorMessageArg, lowerNew, accessorCall } from "./lower-classes.js";
|
|
25
25
|
import { mixinCallClassInfoOf, mixinIntersectionInstanceType } from "./lower-mixins.js";
|
|
26
26
|
import { bindingNeverReassigned, bodyReadsArguments, isThisParameter, paramShape, paramShapes, checkDefaultParamBodyType, completeArgs, wrappedUndefined, undefinedArgFor, requireExactArityValue, bodyReturnType, declaredReturnType, collectSignature, collectSignatureInner, collectGenericSignature, genericFnOf, lowerGenericCall, lowerGenericFnValue, inferTypeParamBindings, lowerGenericInstance, lowerCall, lowerTimersMemberCall, lowerPromiseMethodCall, lowerFilterNarrowCall, isTopLevelFnSymbol, lowerNestedFunctionDecl, lambdaSignature, lowerLambda, lowerFunction } from "./lower-calls.js";
|
|
@@ -568,6 +568,12 @@ export class Lowerer {
|
|
|
568
568
|
/** Synthetic URLSearchParams.forEach loop functions, interned per
|
|
569
569
|
* callback arity/return — Map's pattern over the sp index walk. */
|
|
570
570
|
spHofHelpers = new Map();
|
|
571
|
+
/** The primitive-constructor VALUES (`String`/`Number`/`Boolean` as
|
|
572
|
+
* bare identifiers — CLI option tables store and compare them): one
|
|
573
|
+
* synthesized coercion function per constructor per program, interned
|
|
574
|
+
* here by name so every reference is the SAME zero-capture closure and
|
|
575
|
+
* `opt.type === String` is JS identity (see primitiveCtorClosure). */
|
|
576
|
+
primitiveCtorFns = new Map();
|
|
571
577
|
/** Optional-chain lowering state. While a chain body lowers, the guarded
|
|
572
578
|
* receiver NODE reads as a chainRecv (typed by the narrowed arm) instead
|
|
573
579
|
* of re-lowering, its checker type reads non-nullish (typeOf), and the
|
|
@@ -918,6 +924,16 @@ export class Lowerer {
|
|
|
918
924
|
this.flushDeferred(symbol);
|
|
919
925
|
return symbol;
|
|
920
926
|
}
|
|
927
|
+
// DEFAULT-SNAPSHOT storage lives on the EXPORTER'S default alias
|
|
928
|
+
// symbol (`export default someLet` — collectGlobals registers the
|
|
929
|
+
// Node-semantics snapshot there). getAliasedSymbol would resolve
|
|
930
|
+
// PAST it to the live let; walk the default-import hops and stop at
|
|
931
|
+
// the first default symbol carrying storage instead.
|
|
932
|
+
const snap = this.defaultSnapshotSymbolOf(symbol);
|
|
933
|
+
if (snap) {
|
|
934
|
+
this.flushDeferred(snap);
|
|
935
|
+
return snap;
|
|
936
|
+
}
|
|
921
937
|
symbol = this.checker.getAliasedSymbol(symbol);
|
|
922
938
|
}
|
|
923
939
|
// CommonJS export plumbing: a binding that resolved to a PROPERTY of a
|
|
@@ -933,6 +949,51 @@ export class Lowerer {
|
|
|
933
949
|
this.flushDeferred(symbol);
|
|
934
950
|
return symbol;
|
|
935
951
|
}
|
|
952
|
+
/** The default-snapshot storage symbol a DEFAULT-import alias chain
|
|
953
|
+
* lands on, or null. A mutable entity-name default (`export default
|
|
954
|
+
* someLet`) registers its Node-semantics snapshot global under the
|
|
955
|
+
* exporter's default ALIAS symbol; the checker's getAliasedSymbol
|
|
956
|
+
* resolves through that symbol to the live let, so this walk follows
|
|
957
|
+
* the default hops syntactically — default import clauses, `{ default
|
|
958
|
+
* as x }` specifiers, `export { default } from` re-exports — and stops
|
|
959
|
+
* at the first default symbol carrying registered storage. Local
|
|
960
|
+
* `export { x as default }` specifiers (no module specifier) are LIVE
|
|
961
|
+
* bindings in Node and fall through to ordinary alias resolution. */
|
|
962
|
+
defaultSnapshotSymbolOf(alias) {
|
|
963
|
+
let sym = alias;
|
|
964
|
+
for (let hop = 0; sym !== undefined && hop < 32; hop++) {
|
|
965
|
+
if (hop > 0 && sym.flags & ts.SymbolFlags.Alias && this.globalsBySymbol.has(sym))
|
|
966
|
+
return sym;
|
|
967
|
+
const d = this.checker
|
|
968
|
+
.declarationsOf(sym)
|
|
969
|
+
.find((x) => ts.isImportClause(x) || ts.isImportSpecifier(x) || ts.isExportSpecifier(x));
|
|
970
|
+
let spec;
|
|
971
|
+
let name;
|
|
972
|
+
if (d && ts.isImportClause(d) && ts.isImportDeclaration(d.parent)) {
|
|
973
|
+
spec = d.parent.moduleSpecifier;
|
|
974
|
+
name = "default";
|
|
975
|
+
}
|
|
976
|
+
else if (d && ts.isImportSpecifier(d)) {
|
|
977
|
+
const idecl = d.parent.parent.parent;
|
|
978
|
+
if (ts.isImportDeclaration(idecl))
|
|
979
|
+
spec = idecl.moduleSpecifier;
|
|
980
|
+
name = (d.propertyName ?? d.name).text;
|
|
981
|
+
}
|
|
982
|
+
else if (d && ts.isExportSpecifier(d)) {
|
|
983
|
+
const edecl = d.parent.parent;
|
|
984
|
+
if (ts.isExportDeclaration(edecl))
|
|
985
|
+
spec = edecl.moduleSpecifier;
|
|
986
|
+
name = (d.propertyName ?? d.name).text;
|
|
987
|
+
}
|
|
988
|
+
if (d === undefined || spec === undefined || !ts.isStringLiteral(spec) || name !== "default")
|
|
989
|
+
return null;
|
|
990
|
+
const dep = resolveImport(this.program, d.getSourceFile(), spec.text);
|
|
991
|
+
if (!dep)
|
|
992
|
+
return null;
|
|
993
|
+
sym = defaultExportSymbolOf(this, dep) ?? undefined;
|
|
994
|
+
}
|
|
995
|
+
return null;
|
|
996
|
+
}
|
|
936
997
|
/** A module's CJS export-table member symbol by NAME (the checker's
|
|
937
998
|
* module-symbol exports map — present in tsgo even where no expando
|
|
938
999
|
* property symbol exists at the attachment/use sites). */
|
|
@@ -1376,6 +1437,20 @@ export class Lowerer {
|
|
|
1376
1437
|
// the emitted program references, flushing deferred class diagnostics
|
|
1377
1438
|
// that a reached type makes relevant.
|
|
1378
1439
|
const artifacts = this.moduleArtifacts(functions);
|
|
1440
|
+
// Types still naming a class that never REGISTERED after retention's
|
|
1441
|
+
// flush (JS graphs whose class fences deferred to runtime — the
|
|
1442
|
+
// sentence-walker's path params, printer tables whose func-typed
|
|
1443
|
+
// fields spell the fenced class): the emitter would name a struct
|
|
1444
|
+
// that does not exist — the compile-C escape family. No instance of
|
|
1445
|
+
// such a class can ever exist (every construction site fenced), so
|
|
1446
|
+
// the slots are inert by construction: rewrite each to the f64 dummy
|
|
1447
|
+
// placeholder (boxNewC's uncollected-class stance, applied to unboxed
|
|
1448
|
+
// slots), uniformly across params/locals/globals/fields/body types so
|
|
1449
|
+
// every producer and consumer agrees. Programs with no unregistered
|
|
1450
|
+
// reference are untouched — byte-stability holds.
|
|
1451
|
+
if (this.diags.length === 0) {
|
|
1452
|
+
this.sanitizeUnregisteredClassTypes([functions, this.globalsList, artifacts.classes, artifacts.records, artifacts.unions]);
|
|
1453
|
+
}
|
|
1379
1454
|
const module = this.diags.length > 0
|
|
1380
1455
|
? null
|
|
1381
1456
|
: {
|
|
@@ -1400,6 +1475,45 @@ export class Lowerer {
|
|
|
1400
1475
|
...(this.npmLazyTraps ? { npmLazyTraps: this.npmLazyTraps } : {}),
|
|
1401
1476
|
};
|
|
1402
1477
|
}
|
|
1478
|
+
/** The unregistered-class type sweep (run()'s last step before the
|
|
1479
|
+
* module assembles): every `{kind:"object"}` TYPE naming a class with
|
|
1480
|
+
* no registered ClassInfo is rewritten IN PLACE to the f64 dummy.
|
|
1481
|
+
* classval types are exempt (they emit the class-independent
|
|
1482
|
+
* `ScrClassObj *` — inert-but-valid storage, the validator's own
|
|
1483
|
+
* stance), and only type objects rewrite — node-level classNames
|
|
1484
|
+
* (`new`, upcasts) cannot reach here (their lowerings fence without a
|
|
1485
|
+
* registered class), so the validator still backstops those. */
|
|
1486
|
+
sanitizeUnregisteredClassTypes(roots) {
|
|
1487
|
+
const isUnregisteredObjectType = (v) => typeof v === "object" && v !== null &&
|
|
1488
|
+
v.kind === "object" &&
|
|
1489
|
+
typeof v.className === "string" &&
|
|
1490
|
+
!this.classes.has(v.className);
|
|
1491
|
+
const sweep = (node) => {
|
|
1492
|
+
if (node === null || typeof node !== "object")
|
|
1493
|
+
return;
|
|
1494
|
+
if (Array.isArray(node)) {
|
|
1495
|
+
node.forEach((item, i) => {
|
|
1496
|
+
if (isUnregisteredObjectType(item))
|
|
1497
|
+
node[i] = F64;
|
|
1498
|
+
else
|
|
1499
|
+
sweep(item);
|
|
1500
|
+
});
|
|
1501
|
+
return;
|
|
1502
|
+
}
|
|
1503
|
+
const rec = node;
|
|
1504
|
+
for (const key of Object.keys(rec)) {
|
|
1505
|
+
if (key === "loc")
|
|
1506
|
+
continue;
|
|
1507
|
+
const v = rec[key];
|
|
1508
|
+
if (isUnregisteredObjectType(v))
|
|
1509
|
+
rec[key] = F64;
|
|
1510
|
+
else
|
|
1511
|
+
sweep(v);
|
|
1512
|
+
}
|
|
1513
|
+
};
|
|
1514
|
+
for (const root of roots)
|
|
1515
|
+
sweep(root);
|
|
1516
|
+
}
|
|
1403
1517
|
/** True when `t` (recursively) names a class instance type with no
|
|
1404
1518
|
* registered ClassInfo — the shape of a JS class whose collection fenced.
|
|
1405
1519
|
* Used by run()'s global pruning; shapes/unions recurse with a seen-set
|
|
@@ -2459,9 +2573,15 @@ export class Lowerer {
|
|
|
2459
2573
|
}
|
|
2460
2574
|
if (expected.kind === "array" && expr.type.kind === "array" && expected.elem.kind !== "jsval") {
|
|
2461
2575
|
const helper = this.arrayWidthHelper(expr.type, expected, expr.loc);
|
|
2462
|
-
if (
|
|
2576
|
+
if (helper)
|
|
2577
|
+
return { kind: "call", callee: helper, args: [expr], type: expected, loc: expr.loc };
|
|
2578
|
+
// The EMPTY-array lift (widthLiftPlan's emptyArr rule), top-level:
|
|
2579
|
+
// `cmd.aliases` typed `(null | undefined)[]` (an `aliases: []`
|
|
2580
|
+
// table) flowing into a `string[]` slot.
|
|
2581
|
+
const lift = this.widthLiftPlan(expr.type, expected);
|
|
2582
|
+
if (lift?.how !== "emptyArr")
|
|
2463
2583
|
return null;
|
|
2464
|
-
return
|
|
2584
|
+
return this.applyWidthLift(lift, expr, expected, expr.loc);
|
|
2465
2585
|
}
|
|
2466
2586
|
// A TUPLE flowing into an array slot (`const NAMES = [...] as const`
|
|
2467
2587
|
// assigned to a `readonly T[]` — the const-table pattern): TS erases
|
|
@@ -2547,10 +2667,39 @@ export class Lowerer {
|
|
|
2547
2667
|
return this.recordToClassPlan(src.shapeId, dst.className) !== null ? { how: "clsWidth" } : null;
|
|
2548
2668
|
}
|
|
2549
2669
|
if (dst.kind === "array" && src.kind === "array") {
|
|
2550
|
-
|
|
2670
|
+
if (this.widthLiftPlan(src.elem, dst.elem) !== null)
|
|
2671
|
+
return { how: "arr" };
|
|
2672
|
+
// The EMPTY-array lift: a unit-only element type (`readonly []`
|
|
2673
|
+
// mapped as the unit-element array, `(null | undefined)[]`) has no
|
|
2674
|
+
// per-element conversion into a data element — but the only value
|
|
2675
|
+
// such a slot honestly holds in the width family is EMPTY, so the
|
|
2676
|
+
// lift is a fresh empty array of the target type, guarded by a
|
|
2677
|
+
// runtime non-empty trap (the checked-extraction stance).
|
|
2678
|
+
if (this.unitOnlyElem(src.elem) && dst.elem.kind !== "jsval" && !this.unitOnlyElem(dst.elem)) {
|
|
2679
|
+
return { how: "emptyArr" };
|
|
2680
|
+
}
|
|
2681
|
+
return null;
|
|
2682
|
+
}
|
|
2683
|
+
// A TUPLE flowing into an array FIELD/ELEMENT (`aliases: ["ls"]` into
|
|
2684
|
+
// an `aliases: string[]` slot): per-position lifts, the top-level
|
|
2685
|
+
// tuple-into-array coercion applied recursively.
|
|
2686
|
+
if (dst.kind === "array" && src.kind === "record" && dst.elem.kind !== "jsval") {
|
|
2687
|
+
const from = this.shapes.get(src.shapeId);
|
|
2688
|
+
if (from?.tuple && from.fields.every((f) => this.widthLiftPlan(f.type, dst.elem) !== null)) {
|
|
2689
|
+
return { how: "tupleArr" };
|
|
2690
|
+
}
|
|
2691
|
+
return null;
|
|
2551
2692
|
}
|
|
2552
2693
|
return null;
|
|
2553
2694
|
}
|
|
2695
|
+
/** True for the unit-only element types (`(null | undefined)[]`, the
|
|
2696
|
+
* `readonly []` mapping): a union whose every arm is a unit. */
|
|
2697
|
+
unitOnlyElem(t) {
|
|
2698
|
+
if (t.kind !== "union")
|
|
2699
|
+
return false;
|
|
2700
|
+
const def = this.unions.get(t.unionId);
|
|
2701
|
+
return def !== undefined && def.arms.every((a) => isUnitType(a));
|
|
2702
|
+
}
|
|
2554
2703
|
/** The build side of widthLiftPlan: the IrExpr converting `value` into
|
|
2555
2704
|
* `dst` under a plan the caller validated. Interns whatever helpers the
|
|
2556
2705
|
* lift needs (planned first, so the interns cannot fail — a failure here
|
|
@@ -2597,6 +2746,20 @@ export class Lowerer {
|
|
|
2597
2746
|
throw new Error("lowerer bug: planned arr lift failed to intern");
|
|
2598
2747
|
return { kind: "call", callee: helper, args: [value], type: dst, loc };
|
|
2599
2748
|
}
|
|
2749
|
+
case "tupleArr": {
|
|
2750
|
+
if (dst.kind !== "array" || value.type.kind !== "record")
|
|
2751
|
+
throw new Error("lowerer bug: tupleArr lift shape");
|
|
2752
|
+
const helper = this.tupleArrayWidthHelper(value.type.shapeId, dst, loc);
|
|
2753
|
+
if (!helper)
|
|
2754
|
+
throw new Error("lowerer bug: planned tupleArr lift failed to intern");
|
|
2755
|
+
return { kind: "call", callee: helper, args: [value], type: dst, loc };
|
|
2756
|
+
}
|
|
2757
|
+
case "emptyArr": {
|
|
2758
|
+
if (dst.kind !== "array" || value.type.kind !== "array")
|
|
2759
|
+
throw new Error("lowerer bug: emptyArr lift shape");
|
|
2760
|
+
const helper = this.emptyArrayLiftHelper(value.type, dst, loc);
|
|
2761
|
+
return { kind: "call", callee: helper, args: [value], type: dst, loc };
|
|
2762
|
+
}
|
|
2600
2763
|
case "objWidth": {
|
|
2601
2764
|
if (dst.kind !== "record" || value.type.kind !== "object")
|
|
2602
2765
|
throw new Error("lowerer bug: objWidth lift shape");
|
|
@@ -2660,10 +2823,19 @@ export class Lowerer {
|
|
|
2660
2823
|
if (!ff) {
|
|
2661
2824
|
// A target field MISSING on the source: legal exactly when it is
|
|
2662
2825
|
// optional-flavored (an undefined-armed union) — the unset field
|
|
2663
|
-
// IS the undefined arm, the same rule literal completion applies
|
|
2664
|
-
//
|
|
2665
|
-
//
|
|
2666
|
-
|
|
2826
|
+
// IS the undefined arm, the same rule literal completion applies
|
|
2827
|
+
// — or 'unknown' (a dyn slot holds the DOM undefined, exactly
|
|
2828
|
+
// the absent-property read: the options-record call shape
|
|
2829
|
+
// against `{ plugins: unknown, ... }`). Never for tuples: a
|
|
2830
|
+
// completed position would change .length and JSON where Node
|
|
2831
|
+
// keeps the source arity.
|
|
2832
|
+
if (from.tuple)
|
|
2833
|
+
return null;
|
|
2834
|
+
if (tf.type.kind === "dyn") {
|
|
2835
|
+
plan.set(tf.name, { absentDyn: true });
|
|
2836
|
+
continue;
|
|
2837
|
+
}
|
|
2838
|
+
if (tf.type.kind !== "union")
|
|
2667
2839
|
return null;
|
|
2668
2840
|
const def = this.unions.get(tf.type.unionId);
|
|
2669
2841
|
const utag = def ? def.arms.findIndex((a) => a.kind === "undefinedT") : -1;
|
|
@@ -2717,6 +2889,11 @@ export class Lowerer {
|
|
|
2717
2889
|
kind: "recordLit",
|
|
2718
2890
|
fields: to.fields.map((f) => {
|
|
2719
2891
|
const lift = plan.get(f.name);
|
|
2892
|
+
if ("absentDyn" in lift) {
|
|
2893
|
+
// The unset 'unknown' field: the DOM undefined — exactly
|
|
2894
|
+
// the absent-property read's answer.
|
|
2895
|
+
return { name: f.name, value: dynUndefinedExpr(loc) };
|
|
2896
|
+
}
|
|
2720
2897
|
if ("absent" in lift) {
|
|
2721
2898
|
if (f.type.kind !== "union")
|
|
2722
2899
|
throw new Error("lowerer bug: absent lift against a non-union field");
|
|
@@ -2796,6 +2973,57 @@ export class Lowerer {
|
|
|
2796
2973
|
});
|
|
2797
2974
|
return name;
|
|
2798
2975
|
}
|
|
2976
|
+
/** Interned `%arr.empty.<n>(a)` — the EMPTY-array lift's build side: a
|
|
2977
|
+
* unit-only-element array reshapes into any data-element array by
|
|
2978
|
+
* answering a FRESH empty array, after a runtime non-empty trap (a
|
|
2979
|
+
* genuinely inhabited `(null | undefined)[]` cannot reshape — the
|
|
2980
|
+
* catchable-TypeError stance every checked extraction takes). */
|
|
2981
|
+
emptyArrayLiftHelper(fromT, toT, loc) {
|
|
2982
|
+
const key = `emptyarr:${typeKey(fromT.elem)}:${typeKey(toT.elem)}`;
|
|
2983
|
+
const existing = this.widthHelpers.get(key);
|
|
2984
|
+
if (existing)
|
|
2985
|
+
return existing;
|
|
2986
|
+
const name = `%arr.empty.${this.widthHelpers.size}`;
|
|
2987
|
+
this.widthHelpers.set(key, name);
|
|
2988
|
+
const a = { kind: "varRef", localId: "a.0", type: fromT, loc };
|
|
2989
|
+
this.liftedFns.push({
|
|
2990
|
+
name,
|
|
2991
|
+
params: [{ localId: "a.0", name: "a", type: fromT }],
|
|
2992
|
+
returnType: toT,
|
|
2993
|
+
locals: [{ id: "a.0", name: "a", type: fromT, mutable: true }],
|
|
2994
|
+
body: [
|
|
2995
|
+
{
|
|
2996
|
+
kind: "if",
|
|
2997
|
+
cond: {
|
|
2998
|
+
kind: "bin",
|
|
2999
|
+
op: "!==",
|
|
3000
|
+
left: { kind: "arrIntrinsic", method: "length", receiver: a, args: [], type: F64, loc },
|
|
3001
|
+
right: { kind: "numLit", value: 0, type: F64, loc },
|
|
3002
|
+
type: BOOL,
|
|
3003
|
+
loc,
|
|
3004
|
+
},
|
|
3005
|
+
then: [
|
|
3006
|
+
{
|
|
3007
|
+
kind: "throw",
|
|
3008
|
+
value: {
|
|
3009
|
+
kind: "libCall",
|
|
3010
|
+
fn: "error.new",
|
|
3011
|
+
args: [{ kind: "strLit", value: `expected ${this.fmt(toT)} (a non-empty ${this.fmt(fromT)} has no elements the target can hold)`, type: STRING, loc }],
|
|
3012
|
+
type: { kind: "object", className: "%TypeError" },
|
|
3013
|
+
loc,
|
|
3014
|
+
},
|
|
3015
|
+
loc,
|
|
3016
|
+
},
|
|
3017
|
+
],
|
|
3018
|
+
else_: [],
|
|
3019
|
+
loc,
|
|
3020
|
+
},
|
|
3021
|
+
{ kind: "return", value: { kind: "arrayLit", elems: [], type: toT, loc }, loc },
|
|
3022
|
+
],
|
|
3023
|
+
loc,
|
|
3024
|
+
});
|
|
3025
|
+
return name;
|
|
3026
|
+
}
|
|
2799
3027
|
arrayWidthHelper(fromT, toT, loc) {
|
|
2800
3028
|
const fromElem = fromT.elem;
|
|
2801
3029
|
const toElem = toT.elem;
|
|
@@ -3932,6 +4160,59 @@ export class Lowerer {
|
|
|
3932
4160
|
});
|
|
3933
4161
|
return name;
|
|
3934
4162
|
}
|
|
4163
|
+
/** The DEFERRED-INIT field read (`stream!: T` assigned past the
|
|
4164
|
+
* constructor's top level — the slot is `T | undefined`): interned
|
|
4165
|
+
* `%deferred.read.<n>(u)` extracting the declared type. SCALAR arms
|
|
4166
|
+
* whose JS-undefined behavior a unit default reproduces read that
|
|
4167
|
+
* default — bool false (conditions are exact: undefined and false are
|
|
4168
|
+
* both falsy; only printing/strict-equality could tell) and f64 NaN
|
|
4169
|
+
* (arithmetic and conditions exact) — while string and REF arms keep
|
|
4170
|
+
* the checked-extraction TRAP: JS itself TypeErrors the first member
|
|
4171
|
+
* use of such an undefined, so the catchable TypeError at the read is
|
|
4172
|
+
* the same failure, named earlier (SEMANTICS.md). */
|
|
4173
|
+
deferredReadHelper(fromId, target, loc) {
|
|
4174
|
+
if (target.kind !== "bool" && target.kind !== "f64") {
|
|
4175
|
+
return this.narrowedArmHelper(fromId, target, loc);
|
|
4176
|
+
}
|
|
4177
|
+
const from = this.unions.get(fromId);
|
|
4178
|
+
const tag = this.armTag(fromId, target);
|
|
4179
|
+
const utag = from ? from.arms.findIndex((a) => a.kind === "undefinedT") : -1;
|
|
4180
|
+
if (!from || tag < 0 || utag < 0)
|
|
4181
|
+
return null;
|
|
4182
|
+
const key = `deferred:${fromId}:${tag}`;
|
|
4183
|
+
const existing = this.narrowHelpers.get(key);
|
|
4184
|
+
if (existing)
|
|
4185
|
+
return existing;
|
|
4186
|
+
const name = `%deferred.read.${this.narrowHelpers.size}`;
|
|
4187
|
+
this.narrowHelpers.set(key, name);
|
|
4188
|
+
const fromT = { kind: "union", unionId: fromId };
|
|
4189
|
+
const u = { kind: "varRef", localId: "u.0", type: fromT, loc };
|
|
4190
|
+
const dflt = target.kind === "bool"
|
|
4191
|
+
? { kind: "boolLit", value: false, type: BOOL, loc }
|
|
4192
|
+
: { kind: "numLit", value: NaN, type: F64, loc };
|
|
4193
|
+
this.liftedFns.push({
|
|
4194
|
+
name,
|
|
4195
|
+
params: [{ localId: "u.0", name: "u", type: fromT }],
|
|
4196
|
+
returnType: target,
|
|
4197
|
+
locals: [{ id: "u.0", name: "u", type: fromT, mutable: true }],
|
|
4198
|
+
body: [
|
|
4199
|
+
{
|
|
4200
|
+
kind: "if",
|
|
4201
|
+
cond: { kind: "unionIsTag", unionId: fromId, tag: utag, negated: false, value: u, type: BOOL, loc },
|
|
4202
|
+
then: [{ kind: "return", value: dflt, loc }],
|
|
4203
|
+
else_: null,
|
|
4204
|
+
loc,
|
|
4205
|
+
},
|
|
4206
|
+
{
|
|
4207
|
+
kind: "return",
|
|
4208
|
+
value: { kind: "unionNarrow", unionId: fromId, tag, value: u, type: target, loc },
|
|
4209
|
+
loc,
|
|
4210
|
+
},
|
|
4211
|
+
],
|
|
4212
|
+
loc,
|
|
4213
|
+
});
|
|
4214
|
+
return name;
|
|
4215
|
+
}
|
|
3935
4216
|
/** True when a static value can become ONE island value: jsval itself,
|
|
3936
4217
|
* anything boundary-safe (the deep JSON marshal), a record whose fields
|
|
3937
4218
|
* all can (built as an island OBJECT literal, field by field), or an
|
|
@@ -4851,7 +5132,7 @@ export class Lowerer {
|
|
|
4851
5132
|
// unresolvable ones never collected, so they skip here too.
|
|
4852
5133
|
const baseName = ts.isMethodDeclaration(fnLike)
|
|
4853
5134
|
? classMemberNameOf(this, fnLike.name)
|
|
4854
|
-
: ts.isIdentifier(fnLike.name)
|
|
5135
|
+
: ts.isIdentifier(fnLike.name) || ts.isPrivateIdentifier(fnLike.name)
|
|
4855
5136
|
? fnLike.name.text
|
|
4856
5137
|
: null;
|
|
4857
5138
|
if (baseName === null)
|
|
@@ -5947,7 +6228,7 @@ export class Lowerer {
|
|
|
5947
6228
|
if (module !== null)
|
|
5948
6229
|
return { module, member: access.name.text };
|
|
5949
6230
|
// The RE-EXPORT FACADE's namespace spelling: `import * as assert from
|
|
5950
|
-
// "./facade.js"` over `export { ok } from "node:assert"` (
|
|
6231
|
+
// "./facade.js"` over `export { ok } from "node:assert"` (the formatter idiom's
|
|
5951
6232
|
// universal/assert). The member's symbol is the facade's
|
|
5952
6233
|
// ExportSpecifier, and builtinImportOf's alias chase answers the
|
|
5953
6234
|
// builtin's own module/member — the same tables as a direct import;
|