@scriptc/compiler 0.0.8 → 0.0.10
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 +13 -0
- package/dist/backend/cc.js +14 -0
- package/dist/backend/cc.js.map +1 -1
- package/dist/backend/emission/emit-exprs.js +244 -17
- package/dist/backend/emission/emit-exprs.js.map +1 -1
- package/dist/backend/emission/emit-types.d.ts +3 -0
- package/dist/backend/emission/emit-types.js +12 -0
- package/dist/backend/emission/emit-types.js.map +1 -1
- package/dist/backend/emission/emit-walkers.d.ts +7 -5
- package/dist/backend/emission/emit-walkers.js +52 -12
- package/dist/backend/emission/emit-walkers.js.map +1 -1
- package/dist/backend/emission/emitter.d.ts +1 -1
- package/dist/backend/emission/emitter.js +30 -9
- package/dist/backend/emission/emitter.js.map +1 -1
- package/dist/backend/llvm/dyn.d.ts +1 -0
- package/dist/backend/llvm/dyn.js +83 -1
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.js +357 -20
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +73 -14
- package/dist/diagnostics/diagnostic.js +112 -31
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/diagnostics/render.js +8 -0
- package/dist/diagnostics/render.js.map +1 -1
- package/dist/frontend/lowering/lib-boundary.js +11 -1
- package/dist/frontend/lowering/lib-boundary.js.map +1 -1
- package/dist/frontend/lowering/lower-assert.js +16 -0
- package/dist/frontend/lowering/lower-assert.js.map +1 -1
- package/dist/frontend/lowering/lower-builtins.d.ts +24 -0
- package/dist/frontend/lowering/lower-builtins.js +256 -3
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +71 -11
- package/dist/frontend/lowering/lower-calls.js +942 -18
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.js +27 -1
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +21 -2
- package/dist/frontend/lowering/lower-containers.js +386 -53
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-dgram.js +92 -17
- package/dist/frontend/lowering/lower-dgram.js.map +1 -1
- package/dist/frontend/lowering/lower-emitter.js +54 -0
- package/dist/frontend/lowering/lower-emitter.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.js +231 -17
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.js +33 -2
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-namespaces.d.ts +25 -11
- package/dist/frontend/lowering/lower-namespaces.js +50 -15
- package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
- package/dist/frontend/lowering/lower-server.js +211 -4
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.d.ts +1 -5
- package/dist/frontend/lowering/lower-stmts.js +660 -19
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.js +92 -5
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +102 -15
- package/dist/frontend/lowering/lowerer.js +378 -30
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/surfaces.js +20 -3
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/npm-static-rewrite.d.ts +7 -2
- package/dist/frontend/npm-static-rewrite.js +566 -138
- package/dist/frontend/npm-static-rewrite.js.map +1 -1
- package/dist/frontend/npm-static.js +11 -2
- package/dist/frontend/npm-static.js.map +1 -1
- package/dist/frontend/program.js +5 -5
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/shared.d.ts +6 -1
- package/dist/frontend/shared.js +46 -1
- package/dist/frontend/shared.js.map +1 -1
- package/dist/frontend/types.d.ts +13 -0
- package/dist/frontend/types.js +88 -9
- package/dist/frontend/types.js.map +1 -1
- package/dist/index.js +169 -32
- package/dist/index.js.map +1 -1
- package/dist/ir/nodes.d.ts +230 -12
- package/dist/ir/nodes.js +85 -6
- package/dist/ir/nodes.js.map +1 -1
- package/dist/ir/validate.js +109 -9
- package/dist/ir/validate.js.map +1 -1
- package/dist/library/fence-eval.d.ts +77 -0
- package/dist/library/fence-eval.js +385 -0
- package/dist/library/fence-eval.js.map +1 -0
- package/dist/library/profile.d.ts +11 -1
- package/dist/library/profile.js +102 -18
- package/dist/library/profile.js.map +1 -1
- package/package.json +2 -2
- package/surface-manifest.json +10 -3
|
@@ -26,7 +26,7 @@ import { mixinCallClassInfoOf, mixinIntersectionInstanceType } from "./lower-mix
|
|
|
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";
|
|
27
27
|
import { lowerArrayMethodCall, lowerBufferStaticCall, lowerBytesMethodCall, lowerBytesNew, lowerMapMethodCall, lowerMapForEachCall, buildMapForEachFn, lowerRecordOvfCaptureHelper, lowerEnvToPairsHelper, lowerSetMethodCall, lowerSetForEachCall, buildSetForEachFn, lowerRegexMethodCall, lowerStringMethodCall } from "./lower-containers.js";
|
|
28
28
|
import { lowerStreamModuleCall } from "./lower-stream.js";
|
|
29
|
-
import { builtinImportOf, lowerBuiltinModuleCall, lowerChildArgsArg, lowerSpawnSyncCall, lowerSpawnCall, lowerExecSyncCall, recordToEnvPairs, lowerJsonMethodCall, fencedBuiltinImportOf, lowerCryptoComposedCall, lowerUrlMethodCall, lowerSearchParamsMethodCall, lowerStatsMethodCall, lowerChildMethodCall, lowerAtomicsCall, lowerBuiltinExtraProperty, promisifiedExecFileDecl, lowerExecFileAsyncCall, execFileAsyncHelper, lowerStringDecoderMethodCall, strdecHelper, lowerReadlineMethodCall, lowerDcChannelMethodCall, lowerDcChannelProperty, lowerAlsMethodCall, lowerDcTracingChannelMethodCall, lowerDcTracingChannelProperty, lowerJsonProperty, lowerErrorCodeProperty, lowerProcessProperty, isProcessEnv, envValueType, lowerProcessEnvGet, lowerProcessMethodCall, lowerProcessOptionalMethodCall, lowerTimeoutMethodCall, envSnapshotHelper, isConsoleLog, consoleCallMember, lowerNumberStaticCall, lowerNumberStaticProperty, lowerDateCall, lowerTextCodecCall, lowerFsConstantsProperty, lowerHttp2ConstantsProperty, http2ConstantBindingOf, http2ConstantsDestructureDecl, lowerProcessStreamProperty, lowerStringStaticCall, lowerStringLastIndexOfCall, lowerPromiseStaticCall } from "./lower-builtins.js";
|
|
29
|
+
import { builtinImportOf, lowerBuiltinModuleCall, lowerFsToUnixTimestampCall, lowerFsLadderCall, lowerChildArgsArg, lowerSpawnSyncCall, lowerSpawnCall, lowerExecSyncCall, recordToEnvPairs, lowerJsonMethodCall, fencedBuiltinImportOf, lowerCryptoComposedCall, lowerUrlMethodCall, lowerSearchParamsMethodCall, lowerStatsMethodCall, lowerChildMethodCall, lowerAtomicsCall, lowerBuiltinExtraProperty, promisifiedExecFileDecl, lowerExecFileAsyncCall, execFileAsyncHelper, lowerStringDecoderMethodCall, strdecHelper, lowerReadlineMethodCall, lowerDcChannelMethodCall, lowerDcChannelProperty, lowerAlsMethodCall, lowerDcTracingChannelMethodCall, lowerDcTracingChannelProperty, lowerJsonProperty, lowerErrorCodeProperty, lowerProcessProperty, isProcessEnv, envValueType, lowerProcessEnvGet, lowerProcessMethodCall, lowerProcessOptionalMethodCall, lowerTimeoutMethodCall, envSnapshotHelper, isConsoleLog, consoleCallMember, lowerNumberStaticCall, lowerNumberStaticProperty, lowerDateCall, lowerTextCodecCall, lowerFsConstantsProperty, lowerHttp2ConstantsProperty, http2ConstantBindingOf, http2ConstantsDestructureDecl, lowerProcessStreamProperty, lowerStringStaticCall, lowerStringLastIndexOfCall, lowerPromiseStaticCall } from "./lower-builtins.js";
|
|
30
30
|
import { isIslandExpr, islandFuncValueFence, islandRegexpOf, jsvalIn, requireDynamicApi, islandGlobalFnOf, lowerDynamicImportCall, lowerFetchCall, lowerIslandMethodCall, lowerMathProperty, npmPackageOf, npmMemberFence, npmPackageOfSymbol } from "./lower-island.js";
|
|
31
31
|
import { lowerHttpHeadersElement, lowerNetModuleCall, lowerServerMethodCall, lowerServerProperty } from "./lower-server.js";
|
|
32
32
|
import { lowerDgramDnsModuleCall, lowerDgramMethodCall } from "./lower-dgram.js";
|
|
@@ -280,6 +280,45 @@ export function dynUndefinedExpr(loc) {
|
|
|
280
280
|
loc,
|
|
281
281
|
};
|
|
282
282
|
}
|
|
283
|
+
/** An always-throwing Node-parity error expression (the error.nodeThrow
|
|
284
|
+
* libCall — the lowered form of arms Node rejects unconditionally:
|
|
285
|
+
* ERR_INVALID_THIS receivers, ERR_MISSING_ARGS arity ladders, the
|
|
286
|
+
* symbol-to-string TypeError). kind 0 Error / 1 TypeError / 2 RangeError;
|
|
287
|
+
* an empty code means no code slot. `type` is the replaced expression's
|
|
288
|
+
* own (never materialized — the global.undefRead pattern). */
|
|
289
|
+
export function nodeThrowExpr(kind, code, message, type, loc) {
|
|
290
|
+
return {
|
|
291
|
+
kind: "libCall",
|
|
292
|
+
fn: "error.nodeThrow",
|
|
293
|
+
args: [
|
|
294
|
+
{ kind: "numLit", value: kind, type: F64, loc },
|
|
295
|
+
{ kind: "strLit", value: code, type: STRING, loc },
|
|
296
|
+
{ kind: "strLit", value: message, type: STRING, loc },
|
|
297
|
+
],
|
|
298
|
+
type,
|
|
299
|
+
loc,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
/** The post-validation fence STRING a validation-ladder Chk libCall
|
|
303
|
+
* throws after its Node-order checks pass: the same SC2020 text the
|
|
304
|
+
* per-statement runtime fence would have thrown (message + "[code at
|
|
305
|
+
* file:line]"), rendered eagerly so the runtime can throw it verbatim
|
|
306
|
+
* (scr_throw_lowering_fence). The diagnostic joins the runtime-fence
|
|
307
|
+
* ledger exactly like a deferred statement fence — nothing silently
|
|
308
|
+
* drops off the coverage report. */
|
|
309
|
+
export function ladderFenceExpr(L, surface, node, hint) {
|
|
310
|
+
const loc = locOf(node);
|
|
311
|
+
const d = noLoweringDiag(surface, loc, hint);
|
|
312
|
+
L.runtimeFences.push(d);
|
|
313
|
+
const sf = node.getSourceFile();
|
|
314
|
+
const pos = ts.getLineAndCharacterOfPosition(sf, loc.start);
|
|
315
|
+
return {
|
|
316
|
+
kind: "strLit",
|
|
317
|
+
value: `${d.message} [${d.code} at ${loc.file}:${pos.line + 1}]`,
|
|
318
|
+
type: STRING,
|
|
319
|
+
loc,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
283
322
|
/** The checked-dynamic declaration fallback for unmappable binding types
|
|
284
323
|
* (see irTypeOf), two gates over one story:
|
|
285
324
|
*
|
|
@@ -458,6 +497,29 @@ export class Lowerer {
|
|
|
458
497
|
/** Per-symbol result of the never-reassigned file scan
|
|
459
498
|
* (bindingNeverReassigned — object-literal generic-method receivers). */
|
|
460
499
|
neverReassignedCache = new Map();
|
|
500
|
+
/** TRAP bindings: declarations whose initializer provably throws before
|
|
501
|
+
* producing a value (its chain roots at an ambient-undefined name —
|
|
502
|
+
* ambientUndefVarRootOf). Module init unwinds at the declaration, so no
|
|
503
|
+
* reference to the binding can ever execute; the statement lowers to the
|
|
504
|
+
* root's throw, no storage exists, and references lower to the same
|
|
505
|
+
* trap shape (never reached — sound whatever the type). */
|
|
506
|
+
trapBindings = new Set();
|
|
507
|
+
/** NULLISH bindings of unmappable (generic-signature) types: `const i:
|
|
508
|
+
* I<A & B> = null as any` — the binding provably holds null/undefined
|
|
509
|
+
* forever (every write's RHS is nullish too), so no storage exists and
|
|
510
|
+
* each READ knows the value. Member reads and method calls through one
|
|
511
|
+
* lower to Node's exact TypeError ("Cannot read properties of null
|
|
512
|
+
* (reading 'fn')"); nullish-to-nullish flows lower to nothing. The map
|
|
513
|
+
* answers which unit the binding holds (the TypeError names it). Null
|
|
514
|
+
* entries cache probed non-qualifiers. */
|
|
515
|
+
nullishBindings = new Map();
|
|
516
|
+
/** DEAD bindings of unmappable types: never READ anywhere in the
|
|
517
|
+
* program, declared with no initializer or a value-only one (a function
|
|
518
|
+
* literal), every write's RHS side-effect-free. Node materializes the
|
|
519
|
+
* value and drops it — zero observable effect — so the declaration and
|
|
520
|
+
* its writes lower to nothing, and no type fence fires for a value the
|
|
521
|
+
* program never consumes. */
|
|
522
|
+
deadBindings = new Set();
|
|
461
523
|
/** IMPLICIT-ANY function-value bindings (npm-static JS — `const knownBy
|
|
462
524
|
* = (cmd) => ...`), by their VariableDeclaration: the registered info,
|
|
463
525
|
* or null for probed non-qualifiers (implicitLocalFnNodeOf). */
|
|
@@ -902,7 +964,11 @@ export class Lowerer {
|
|
|
902
964
|
const recvDecl = recvDecls.find(ts.isImportClause) ?? recvDecls[0];
|
|
903
965
|
if (recvDecl && ts.isVariableDeclaration(recvDecl) && recvDecl.initializer) {
|
|
904
966
|
const spec = requireSpecOf(recvDecl.initializer);
|
|
905
|
-
const dep = spec
|
|
967
|
+
const dep = spec === null
|
|
968
|
+
? null
|
|
969
|
+
: isRelativeSpecifier(spec)
|
|
970
|
+
? resolveImport(this.program, recvDecl.getSourceFile(), spec)
|
|
971
|
+
: npmStaticDepSf7(this.program, recvDecl.getSourceFile(), spec);
|
|
906
972
|
if (dep)
|
|
907
973
|
symbol = this.cjsModuleExportSymbol(dep, ident.text);
|
|
908
974
|
}
|
|
@@ -1099,12 +1165,14 @@ export class Lowerer {
|
|
|
1099
1165
|
}
|
|
1100
1166
|
/** True when `expr` is an identifier bound by a top-level
|
|
1101
1167
|
* `const x = require("./local")` of a RELATIVE module — the CommonJS
|
|
1102
|
-
* namespace binding — or
|
|
1103
|
-
*
|
|
1104
|
-
* same
|
|
1105
|
-
*
|
|
1106
|
-
*
|
|
1107
|
-
*
|
|
1168
|
+
* namespace binding — or of a bare specifier naming an opted-in
|
|
1169
|
+
* --npm-static package (its CJS entry is a program module, so the
|
|
1170
|
+
* binding is the same namespace over the same export table), or by a
|
|
1171
|
+
* DEFAULT import of a CommonJS JS module (`import d from "./lib.cjs"`:
|
|
1172
|
+
* Node binds d to module.exports, the same value require answers).
|
|
1173
|
+
* Member accesses on it resolve through the export table (property
|
|
1174
|
+
* symbols → resolveValueSymbol); the bare value keeps the
|
|
1175
|
+
* namespace-object fence, like ESM namespace imports of builtins. */
|
|
1108
1176
|
cjsLocalModuleBindingOf(expr) {
|
|
1109
1177
|
if (!ts.isIdentifier(expr))
|
|
1110
1178
|
return false;
|
|
@@ -1122,8 +1190,12 @@ export class Lowerer {
|
|
|
1122
1190
|
return false;
|
|
1123
1191
|
}
|
|
1124
1192
|
const spec = requireSpecOf(decl.initializer);
|
|
1125
|
-
if (spec === null
|
|
1193
|
+
if (spec === null)
|
|
1194
|
+
return false;
|
|
1195
|
+
if (!isRelativeSpecifier(spec) &&
|
|
1196
|
+
npmStaticDepSf7(this.program, decl.getSourceFile(), spec) === null) {
|
|
1126
1197
|
return false;
|
|
1198
|
+
}
|
|
1127
1199
|
}
|
|
1128
1200
|
// SINGLE-VALUE exporters (`module.exports = Countdown` / `= double` /
|
|
1129
1201
|
// `= 42`): the requirer's binding IS the exported value, not a
|
|
@@ -1222,13 +1294,22 @@ export class Lowerer {
|
|
|
1222
1294
|
/** The lowering of a CommonJS `require("./local")` occurrence: a call of
|
|
1223
1295
|
* the required module's run-once %init at exactly this statement's
|
|
1224
1296
|
* position — Node's inline evaluation, with the guard supplying the
|
|
1225
|
-
* cache-hit behavior for every require after the first.
|
|
1226
|
-
*
|
|
1227
|
-
*
|
|
1297
|
+
* cache-hit behavior for every require after the first. Bare specifiers
|
|
1298
|
+
* naming an opted-in --npm-static package resolve to that package's
|
|
1299
|
+
* program entry (the same edge preflight admitted — bundle dists require
|
|
1300
|
+
* their external dependencies by name). Null for everything else
|
|
1301
|
+
* (builtins load nothing; the rest kept its preflight fence). */
|
|
1228
1302
|
requireInitStmt(spec, node) {
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1303
|
+
// Relative requires resolve within the program; a BARE require can be
|
|
1304
|
+
// a program-module edge too when it names an opted-in --npm-static
|
|
1305
|
+
// package (one package requiring another — the resolution answered
|
|
1306
|
+
// its shipped JS, the file is in the module order, and the reads
|
|
1307
|
+
// alias its globals). Without the guarded %init call at this position
|
|
1308
|
+
// those globals stay uninitialized: the dep's module body would never
|
|
1309
|
+
// run.
|
|
1310
|
+
const dep = isRelativeSpecifier(spec)
|
|
1311
|
+
? resolveImport(this.program, node.getSourceFile(), spec)
|
|
1312
|
+
: npmStaticDepSf7(this.program, node.getSourceFile(), spec);
|
|
1232
1313
|
if (!dep || dep.fileName.endsWith(".json"))
|
|
1233
1314
|
return null;
|
|
1234
1315
|
const initName = this.initNameOf.get(dep);
|
|
@@ -1830,8 +1911,8 @@ export class Lowerer {
|
|
|
1830
1911
|
throw new PoisonError();
|
|
1831
1912
|
}
|
|
1832
1913
|
// Would-be records with INDEX SIGNATURES (`Record<string, T>`,
|
|
1833
|
-
// `{ [k: string]: T }`) get
|
|
1834
|
-
//
|
|
1914
|
+
// `{ [k: string]: T }`) get the index-signature fence (SC2006) naming
|
|
1915
|
+
// the supported key/value domain instead of the generic
|
|
1835
1916
|
// supported-types recitation.
|
|
1836
1917
|
if (widened.flags & (ts.TypeFlags.Object | ts.TypeFlags.Intersection) &&
|
|
1837
1918
|
this.checker.getCallSignatures(widened).length === 0 &&
|
|
@@ -1950,9 +2031,27 @@ export class Lowerer {
|
|
|
1950
2031
|
}
|
|
1951
2032
|
}
|
|
1952
2033
|
// STANDARD-LIBRARY nominal types with no lowering at all: the SC2020
|
|
1953
|
-
// story, naming the type
|
|
2034
|
+
// story, naming the type — and for the families with a WHY, the same
|
|
2035
|
+
// pointed reason the identifier/constructor chokepoints teach.
|
|
1954
2036
|
if (stdlibNominal) {
|
|
1955
|
-
|
|
2037
|
+
const intlHint = "Intl formatter values have no representation — the COMPOSED en-US forms lower: " +
|
|
2038
|
+
'new Intl.NumberFormat("en-US").format(x) and x.toLocaleString("en-US") with default options; ' +
|
|
2039
|
+
"the rest is ICU locale data the binary does not carry";
|
|
2040
|
+
const typeHints = {
|
|
2041
|
+
ArrayBuffer: "no free-standing ArrayBuffer value exists — typed arrays own their storage " +
|
|
2042
|
+
"(new Uint8Array(n) allocates; new Uint8Array(new ArrayBuffer(n)) erases the buffer into the view)",
|
|
2043
|
+
SharedArrayBuffer: "no shared-memory threads exist in a compiled program — Uint8Array is the byte storage",
|
|
2044
|
+
NumberFormat: intlHint,
|
|
2045
|
+
DateTimeFormat: intlHint,
|
|
2046
|
+
DurationFormat: intlHint,
|
|
2047
|
+
PluralRules: intlHint,
|
|
2048
|
+
Collator: intlHint,
|
|
2049
|
+
ListFormat: intlHint,
|
|
2050
|
+
RelativeTimeFormat: intlHint,
|
|
2051
|
+
Segmenter: intlHint,
|
|
2052
|
+
DisplayNames: intlHint,
|
|
2053
|
+
};
|
|
2054
|
+
this.pushDiag(noLoweringDiag(this.checker.typeToString(type), locOf(node), typeHints[stdlibOwnSym?.name ?? ""]));
|
|
1956
2055
|
throw new PoisonError();
|
|
1957
2056
|
}
|
|
1958
2057
|
// USER record shapes blocked by ONE member (SC2009's record arm):
|
|
@@ -2147,8 +2246,10 @@ export class Lowerer {
|
|
|
2147
2246
|
}
|
|
2148
2247
|
/** Exact-shape enforcement (SC2002). Records are monomorphic structs, so
|
|
2149
2248
|
* everywhere a value flows into a typed slot (call arg, initializer,
|
|
2150
|
-
* assignment, field, return) the shapes must MATCH —
|
|
2151
|
-
*
|
|
2249
|
+
* assignment, field, return) the shapes must MATCH — or width-coerce:
|
|
2250
|
+
* coerceToExpected already ran widthCoerce (the copy-reshape family),
|
|
2251
|
+
* so what reaches here is the RESIDUE its rules decline, and the
|
|
2252
|
+
* diagnostic names the first blocking rule (describeRecordWidthBlocker).
|
|
2152
2253
|
* Non-record mismatches are not reachable through tsc-clean programs; the
|
|
2153
2254
|
* validator ICEs on them as the usual backstop. */
|
|
2154
2255
|
requireExactShape(node, actual, expected) {
|
|
@@ -2207,7 +2308,13 @@ export class Lowerer {
|
|
|
2207
2308
|
throw new PoisonError();
|
|
2208
2309
|
}
|
|
2209
2310
|
if (containsRecord(actual) || containsRecord(expected)) {
|
|
2210
|
-
|
|
2311
|
+
// A record→record pair gets the pointed story: WHICH width rule
|
|
2312
|
+
// declined (a field that doesn't lift, a required field with no
|
|
2313
|
+
// source, an index signature that could hold the completed key).
|
|
2314
|
+
const detail = actual.kind === "record" && expected.kind === "record"
|
|
2315
|
+
? (this.describeRecordWidthBlocker(actual.shapeId, expected.shapeId) ?? undefined)
|
|
2316
|
+
: undefined;
|
|
2317
|
+
this.pushDiag(recordShapeMismatchDiag(this.fmt(expected), this.fmt(actual), locOf(node), detail));
|
|
2211
2318
|
throw new PoisonError();
|
|
2212
2319
|
}
|
|
2213
2320
|
// Everything else — a plain-kind mismatch like a string flowing into a
|
|
@@ -2297,6 +2404,21 @@ export class Lowerer {
|
|
|
2297
2404
|
return expr;
|
|
2298
2405
|
}
|
|
2299
2406
|
if (expr.type.kind === "jsval" && expected.kind !== "jsval") {
|
|
2407
|
+
// The jsval→DOM crossing (the world unification's engine-handle
|
|
2408
|
+
// kind): an 'any'-typed engine value flowing into an 'unknown'/
|
|
2409
|
+
// 'object'/JS-residue slot wraps BY REFERENCE as the DOM's island
|
|
2410
|
+
// kind — engine scalars normalize to native DOM kinds at wrap time,
|
|
2411
|
+
// typeof/truthiness/String()/=== route to the engine, un-armed DOM
|
|
2412
|
+
// walks fence loudly, and the value unwraps back identity-preserved
|
|
2413
|
+
// (scr_jsval_from_dyn). Monotone under evolution/widening: a value
|
|
2414
|
+
// wraps once at its first dyn edge and stays valid through every
|
|
2415
|
+
// subsequent dyn slot; narrowing never changes representation.
|
|
2416
|
+
// This wrap RETIRES the silent-wrong-answer fence-closure box for
|
|
2417
|
+
// jsval members of DOM object literals (lowerDynObjectLiteral's
|
|
2418
|
+
// coercion lands here first).
|
|
2419
|
+
if (expected.kind === "dyn") {
|
|
2420
|
+
return { kind: "dynFromJsval", value: expr, type: DYN, loc: expr.loc };
|
|
2421
|
+
}
|
|
2300
2422
|
// The exit set: everything round-trippable, plus bare undefined-armed
|
|
2301
2423
|
// unions of JSON-safe data arms (the engine's undefined takes the
|
|
2302
2424
|
// undefined arm before the JSON detour) — canExitIslandToType.
|
|
@@ -2705,10 +2827,23 @@ export class Lowerer {
|
|
|
2705
2827
|
* recursively — NESTED width)
|
|
2706
2828
|
* arr — array into array whose element pair lifts (per-element
|
|
2707
2829
|
* copy loop, arrayWidthHelper)
|
|
2830
|
+
* dynIn — a typed value into an 'unknown' (dyn) slot — the same
|
|
2831
|
+
* static→DOM deep copy coerceToExpected applies top-level
|
|
2832
|
+
* upcast — a derived class instance into a base-typed slot (the
|
|
2833
|
+
* prefix-layout pointer reinterpret, no copy)
|
|
2834
|
+
* funcAdapt — a function into a slot whose signature differs only by
|
|
2835
|
+
* CLEAN mechanical conversions (cleanFuncAdaptable); the
|
|
2836
|
+
* stranded (trap-only) dispositions stay out of the plan
|
|
2708
2837
|
* Null when the pair isn't in the relation — callers keep their fences. */
|
|
2709
2838
|
widthLiftPlan(src, dst) {
|
|
2710
2839
|
if (typeEquals(src, dst))
|
|
2711
2840
|
return { how: "copy" };
|
|
2841
|
+
// An 'unknown' (dyn) DESTINATION slot: the static→DOM conversion —
|
|
2842
|
+
// dynFrom, a DEEP COPY (`{ v: 5 }` into `{ v: unknown }`, `number[]`
|
|
2843
|
+
// into `unknown[]` — tsc's top type over the width family's copies).
|
|
2844
|
+
if (dst.kind === "dyn" && src.kind !== "dyn" && this.dynConvertible(src)) {
|
|
2845
|
+
return { how: "dynIn" };
|
|
2846
|
+
}
|
|
2712
2847
|
if (dst.kind === "union") {
|
|
2713
2848
|
if (src.kind === "union") {
|
|
2714
2849
|
return this.unionRetagMappable(src.unionId, dst.unionId) ? { how: "retag" } : null;
|
|
@@ -2747,6 +2882,23 @@ export class Lowerer {
|
|
|
2747
2882
|
if (src.kind === "union" && !isUnitType(dst) && dst.kind !== "void" && this.armTag(src.unionId, dst) >= 0) {
|
|
2748
2883
|
return { how: "narrow" };
|
|
2749
2884
|
}
|
|
2885
|
+
// A DERIVED instance into a BASE-typed slot (`{ p: Q }` copying into
|
|
2886
|
+
// `{ p: P }`): the same implicit upcast coerceToExpected performs at
|
|
2887
|
+
// top level — prefix layout, a pointer reinterpret, no copy.
|
|
2888
|
+
if (dst.kind === "object" &&
|
|
2889
|
+
src.kind === "object" &&
|
|
2890
|
+
this.isSubclassOf(src.className, dst.className)) {
|
|
2891
|
+
return { how: "upcast" };
|
|
2892
|
+
}
|
|
2893
|
+
// A FUNCTION into a slot whose signature differs only by CLEAN
|
|
2894
|
+
// mechanical conversions (fewer params — JS ignores extras — and
|
|
2895
|
+
// coercibleValue pieces): the general function-value adapter, plan-
|
|
2896
|
+
// gated to the clean subset. The stranded (trap-only) dispositions
|
|
2897
|
+
// funcCoerceAdapter also builds stay TOP-LEVEL only: a width plan
|
|
2898
|
+
// never promises a bridge that can only throw.
|
|
2899
|
+
if (dst.kind === "func" && src.kind === "func" && this.cleanFuncAdaptable(src, dst)) {
|
|
2900
|
+
return { how: "funcAdapt" };
|
|
2901
|
+
}
|
|
2750
2902
|
if (dst.kind === "record" && src.kind === "record") {
|
|
2751
2903
|
return this.recordWidthPlan(src.shapeId, dst.shapeId) !== null ? { how: "width" } : null;
|
|
2752
2904
|
}
|
|
@@ -2874,6 +3026,24 @@ export class Lowerer {
|
|
|
2874
3026
|
throw new Error("lowerer bug: planned narrow lift failed to intern");
|
|
2875
3027
|
return { kind: "call", callee: helper, args: [value], type: dst, loc };
|
|
2876
3028
|
}
|
|
3029
|
+
case "dynIn": {
|
|
3030
|
+
if (dst.kind !== "dyn")
|
|
3031
|
+
throw new Error("lowerer bug: dynIn lift against a non-dyn slot");
|
|
3032
|
+
return { kind: "dynFrom", value, type: DYN, loc };
|
|
3033
|
+
}
|
|
3034
|
+
case "upcast": {
|
|
3035
|
+
if (dst.kind !== "object" || value.type.kind !== "object")
|
|
3036
|
+
throw new Error("lowerer bug: upcast lift shape");
|
|
3037
|
+
return this.upcastTo(value, dst.className);
|
|
3038
|
+
}
|
|
3039
|
+
case "funcAdapt": {
|
|
3040
|
+
if (dst.kind !== "func" || value.type.kind !== "func")
|
|
3041
|
+
throw new Error("lowerer bug: funcAdapt lift shape");
|
|
3042
|
+
const adapter = this.funcCoerceAdapter(value.type, dst, loc);
|
|
3043
|
+
if (!adapter)
|
|
3044
|
+
throw new Error("lowerer bug: planned funcAdapt lift failed to intern");
|
|
3045
|
+
return { kind: "call", callee: adapter, args: [value], type: dst, loc };
|
|
3046
|
+
}
|
|
2877
3047
|
default: {
|
|
2878
3048
|
const _exhaustive = lift;
|
|
2879
3049
|
void _exhaustive;
|
|
@@ -2891,9 +3061,11 @@ export class Lowerer {
|
|
|
2891
3061
|
* optional-flavored field completes to its undefined arm (the
|
|
2892
3062
|
* literal-completion rule). TUPLES width-coerce too, arity-exact (TS
|
|
2893
3063
|
* permits no other tuple width): per-position lifts, never completion.
|
|
2894
|
-
* Index-signature
|
|
2895
|
-
*
|
|
2896
|
-
*
|
|
3064
|
+
* Index-signature SOURCES narrow here like any wider record — declared
|
|
3065
|
+
* fields copy, the overflow drops with the width (missing target
|
|
3066
|
+
* fields decline: the overflow could hold them). Index-signature
|
|
3067
|
+
* TARGETS keep the overflow CAPTURE helper (widthCoerce's other arm).
|
|
3068
|
+
* Null when the shapes don't relate that way. */
|
|
2897
3069
|
/** The pure planning half of recordWidthHelper — every target field's
|
|
2898
3070
|
* lift, or null when the pair isn't width-coercible. Callers that must
|
|
2899
3071
|
* validate a WHOLE plan before interning anything (the retag helper's
|
|
@@ -2901,7 +3073,13 @@ export class Lowerer {
|
|
|
2901
3073
|
recordWidthPlan(fromId, toId) {
|
|
2902
3074
|
const from = this.shapes.get(fromId);
|
|
2903
3075
|
const to = this.shapes.get(toId);
|
|
2904
|
-
|
|
3076
|
+
// INDEX-SIGNATURE sources narrow like any wider record — the target
|
|
3077
|
+
// fields copy off the declared struct slots and the overflow drops
|
|
3078
|
+
// with the rest of the width (divergence 36's stance; the absent-
|
|
3079
|
+
// completion rule below is the one extra fence). Index-signature
|
|
3080
|
+
// TARGETS keep the overflow CAPTURE helper (widthCoerce's other arm):
|
|
3081
|
+
// a fresh hybrid needs keyed writes, not a field-list literal.
|
|
3082
|
+
if (!from || !to || to.indexValue)
|
|
2905
3083
|
return null;
|
|
2906
3084
|
// Tuple↔record pairs never relate; tuple↔tuple only arity-exact.
|
|
2907
3085
|
if (!!from.tuple !== !!to.tuple)
|
|
@@ -2926,8 +3104,12 @@ export class Lowerer {
|
|
|
2926
3104
|
// the absent-property read: the options-record call shape
|
|
2927
3105
|
// against `{ plugins: unknown, ... }`). Never for tuples: a
|
|
2928
3106
|
// completed position would change .length and JSON where Node
|
|
2929
|
-
// keeps the source arity.
|
|
2930
|
-
|
|
3107
|
+
// keeps the source arity. Never for INDEX-SIGNATURE sources:
|
|
3108
|
+
// the overflow may hold this very key at runtime (tsc lets the
|
|
3109
|
+
// signature satisfy optional target members), so completing to
|
|
3110
|
+
// undefined would drop a value Node keeps — the pair stays
|
|
3111
|
+
// fenced.
|
|
3112
|
+
if (from.tuple || from.indexValue)
|
|
2931
3113
|
return null;
|
|
2932
3114
|
if (tf.type.kind === "dyn") {
|
|
2933
3115
|
plan.set(tf.name, { absentDyn: true });
|
|
@@ -2953,6 +3135,92 @@ export class Lowerer {
|
|
|
2953
3135
|
this.widthPlanning.delete(key);
|
|
2954
3136
|
}
|
|
2955
3137
|
}
|
|
3138
|
+
/** Post-hoc classifier for SC2002's record→record residue: WHY the
|
|
3139
|
+
* width family (recordWidthPlan and the overflow capture — widthCoerce's
|
|
3140
|
+
* two record arms) declined this pair — the FIRST blocking rule, named.
|
|
3141
|
+
* Pure description on the failure path (the site already carries the
|
|
3142
|
+
* rejection): mirrors the planners' gates, never changes what coerces,
|
|
3143
|
+
* and answers null when no pointed story applies (the generic message
|
|
3144
|
+
* stands). */
|
|
3145
|
+
describeRecordWidthBlocker(fromId, toId) {
|
|
3146
|
+
const from = this.shapes.get(fromId);
|
|
3147
|
+
const to = this.shapes.get(toId);
|
|
3148
|
+
if (!from || !to)
|
|
3149
|
+
return null;
|
|
3150
|
+
if (to.indexValue) {
|
|
3151
|
+
// The overflow CAPTURE's gates (lowerRecordOvfCaptureHelper).
|
|
3152
|
+
if (from.tuple || to.tuple)
|
|
3153
|
+
return "a tuple cannot reshape into an index-signature record";
|
|
3154
|
+
const tIv = to.indexValue;
|
|
3155
|
+
const slotOk = (t) => typeEquals(t, tIv) ||
|
|
3156
|
+
(tIv.kind === "dyn" && (t.kind === "dyn" || this.dynConvertible(t))) ||
|
|
3157
|
+
this.widthLiftPlan(t, tIv) !== null;
|
|
3158
|
+
const consumed = new Set();
|
|
3159
|
+
for (const tf of to.fields) {
|
|
3160
|
+
const sf = from.fields.find((f) => f.name === tf.name);
|
|
3161
|
+
if (sf) {
|
|
3162
|
+
if (this.widthLiftPlan(sf.type, tf.type) !== null) {
|
|
3163
|
+
consumed.add(tf.name);
|
|
3164
|
+
continue;
|
|
3165
|
+
}
|
|
3166
|
+
return `field '${tf.name}': '${this.fmt(sf.type)}' does not lift into '${this.fmt(tf.type)}'`;
|
|
3167
|
+
}
|
|
3168
|
+
if (tf.type.kind !== "union" || this.armTag(tf.type.unionId, UNDEFINED_T) < 0) {
|
|
3169
|
+
return `the expected field '${tf.name}' is required and the source has no field to copy into it`;
|
|
3170
|
+
}
|
|
3171
|
+
if (tIv.kind === "dyn" ? !this.dynConvertible(tf.type) : !typeEquals(tf.type, tIv)) {
|
|
3172
|
+
return `the expected field '${tf.name}' ('${this.fmt(tf.type)}') cannot take a runtime key collision from the '${this.fmt(tIv)}' signature slot`;
|
|
3173
|
+
}
|
|
3174
|
+
}
|
|
3175
|
+
for (const ff of from.fields) {
|
|
3176
|
+
if (consumed.has(ff.name))
|
|
3177
|
+
continue;
|
|
3178
|
+
if (!slotOk(ff.type)) {
|
|
3179
|
+
return `the source field '${ff.name}' ('${this.fmt(ff.type)}') cannot enter the expected '[key: string]: ${this.fmt(tIv)}' slot`;
|
|
3180
|
+
}
|
|
3181
|
+
}
|
|
3182
|
+
if (from.indexValue && !slotOk(from.indexValue)) {
|
|
3183
|
+
return `the source's '[key: string]: ${this.fmt(from.indexValue)}' slot cannot enter the expected '[key: string]: ${this.fmt(tIv)}' slot`;
|
|
3184
|
+
}
|
|
3185
|
+
// The dispatch-writes gate: runtime-keyed writes can collide with a
|
|
3186
|
+
// declared field whose type is not the slot's.
|
|
3187
|
+
const dispatchWrites = from.indexValue !== undefined ||
|
|
3188
|
+
from.fields.some((ff) => !consumed.has(ff.name) && to.fields.some((f) => f.name === ff.name));
|
|
3189
|
+
if (dispatchWrites) {
|
|
3190
|
+
const bad = to.fields.find((f) => tIv.kind === "dyn" ? !this.dynConvertible(f.type) : !typeEquals(f.type, tIv));
|
|
3191
|
+
if (bad) {
|
|
3192
|
+
return `runtime-keyed writes can collide with the expected field '${bad.name}' ('${this.fmt(bad.type)}'), which cannot take a '${this.fmt(tIv)}' slot value`;
|
|
3193
|
+
}
|
|
3194
|
+
}
|
|
3195
|
+
return null;
|
|
3196
|
+
}
|
|
3197
|
+
// The field-copy plan's gates (recordWidthPlan).
|
|
3198
|
+
if (!!from.tuple !== !!to.tuple)
|
|
3199
|
+
return null;
|
|
3200
|
+
if (from.tuple && from.fields.length !== to.fields.length) {
|
|
3201
|
+
return `tuple arities differ (${from.fields.length} vs ${to.fields.length}; TS permits no tuple width)`;
|
|
3202
|
+
}
|
|
3203
|
+
for (const tf of to.fields) {
|
|
3204
|
+
const ff = from.fields.find((f) => f.name === tf.name);
|
|
3205
|
+
if (!ff) {
|
|
3206
|
+
if (from.tuple)
|
|
3207
|
+
return null;
|
|
3208
|
+
if (from.indexValue) {
|
|
3209
|
+
return `'${tf.name}' is not a declared field of the source, and the source's index signature could hold it at runtime (a completed undefined would drop that value)`;
|
|
3210
|
+
}
|
|
3211
|
+
if (tf.type.kind === "dyn")
|
|
3212
|
+
continue;
|
|
3213
|
+
if (tf.type.kind !== "union" || this.armTag(tf.type.unionId, UNDEFINED_T) < 0) {
|
|
3214
|
+
return `the expected field '${tf.name}' is missing on the source and is not optional`;
|
|
3215
|
+
}
|
|
3216
|
+
continue;
|
|
3217
|
+
}
|
|
3218
|
+
if (this.widthLiftPlan(ff.type, tf.type) === null) {
|
|
3219
|
+
return `field '${tf.name}': '${this.fmt(ff.type)}' does not lift into '${this.fmt(tf.type)}'`;
|
|
3220
|
+
}
|
|
3221
|
+
}
|
|
3222
|
+
return null;
|
|
3223
|
+
}
|
|
2956
3224
|
recordWidthHelper(fromId, toId, loc) {
|
|
2957
3225
|
const from = this.shapes.get(fromId);
|
|
2958
3226
|
const to = this.shapes.get(toId);
|
|
@@ -3611,6 +3879,28 @@ export class Lowerer {
|
|
|
3611
3879
|
}
|
|
3612
3880
|
return false;
|
|
3613
3881
|
}
|
|
3882
|
+
/** True when a `src` function value enters a `dst` slot through
|
|
3883
|
+
* funcCoerceAdapter with NO stranded (trap-only) piece: no rest packs,
|
|
3884
|
+
* no surplus source params, every slot parameter converts into the
|
|
3885
|
+
* wrapped function's own type, and the result converts back (a void
|
|
3886
|
+
* slot drops it; a void result answers the exact JS undefined for
|
|
3887
|
+
* dyn/jsval slots). The width family's func gate — widthLiftPlan
|
|
3888
|
+
* bridges only signatures whose every call succeeds by construction. */
|
|
3889
|
+
cleanFuncAdaptable(src, dst) {
|
|
3890
|
+
if (src.rest === true || dst.rest === true)
|
|
3891
|
+
return false;
|
|
3892
|
+
if (src.params.length > dst.params.length)
|
|
3893
|
+
return false;
|
|
3894
|
+
for (let i = 0; i < src.params.length; i++) {
|
|
3895
|
+
if (!this.coercibleValue(dst.params[i], src.params[i]))
|
|
3896
|
+
return false;
|
|
3897
|
+
}
|
|
3898
|
+
if (dst.ret.kind === "void")
|
|
3899
|
+
return src.ret.kind !== "jsval";
|
|
3900
|
+
if (this.coercibleValue(src.ret, dst.ret))
|
|
3901
|
+
return true;
|
|
3902
|
+
return src.ret.kind === "void" && (dst.ret.kind === "dyn" || dst.ret.kind === "jsval");
|
|
3903
|
+
}
|
|
3614
3904
|
/** Interned `%fn.adapt.<n>(f)` — the GENERAL function-value adapter: a
|
|
3615
3905
|
* `fromT` function value flowing into a `toT` slot whose pieces differ
|
|
3616
3906
|
* only by coercibleValue conversions. The slot's callers pass toT's
|
|
@@ -4929,6 +5219,11 @@ export class Lowerer {
|
|
|
4929
5219
|
if (value.kind === "unitLit") {
|
|
4930
5220
|
return { kind: "dynFrom", value, type: DYN, loc: value.loc };
|
|
4931
5221
|
}
|
|
5222
|
+
// An ISLAND ('any') value: the by-reference jsval→DOM wrap — the same
|
|
5223
|
+
// edge coerceToExpected converts (dyn slots accept engine values).
|
|
5224
|
+
if (value.type.kind === "jsval") {
|
|
5225
|
+
return { kind: "dynFromJsval", value, type: DYN, loc: value.loc };
|
|
5226
|
+
}
|
|
4932
5227
|
if (!this.dynConvertible(value.type)) {
|
|
4933
5228
|
this.unsupported("SC1100", node, `storing '${this.fmt(value.type)}' values under an 'unknown'-valued index signature (only numbers, strings, booleans, and JSON-safe records/arrays/unions convert)`);
|
|
4934
5229
|
}
|
|
@@ -5884,7 +6179,7 @@ export class Lowerer {
|
|
|
5884
6179
|
lowerDestructuringAssignParts(target, rhs, loc) {
|
|
5885
6180
|
return lowerDestructuringAssignParts(this, target, rhs, loc);
|
|
5886
6181
|
}
|
|
5887
|
-
lowerBindingPattern(pattern, srcRef, srcType, isLet, out) {
|
|
6182
|
+
lowerBindingPattern(pattern, srcRef, srcType, isLet, out, dynSpell) {
|
|
5888
6183
|
// An ISLAND source (`const { readFileSync } = await import("fs")` —
|
|
5889
6184
|
// a namespace handle, or any 'any'-typed object): each bound name is
|
|
5890
6185
|
// an engine property read, mirroring the island property-read rule —
|
|
@@ -5948,7 +6243,7 @@ export class Lowerer {
|
|
|
5948
6243
|
}
|
|
5949
6244
|
return;
|
|
5950
6245
|
}
|
|
5951
|
-
return lowerBindingPattern(this, pattern, srcRef, srcType, isLet, out);
|
|
6246
|
+
return lowerBindingPattern(this, pattern, srcRef, srcType, isLet, out, dynSpell);
|
|
5952
6247
|
}
|
|
5953
6248
|
checkBindingElement(el, allowDefault = false) {
|
|
5954
6249
|
return checkBindingElement(this, el, allowDefault);
|
|
@@ -6029,6 +6324,16 @@ export class Lowerer {
|
|
|
6029
6324
|
const local = this.declareLocal(decl.name, decl.name.text, JSVAL, isLet);
|
|
6030
6325
|
return { kind: "varDecl", localId: local.id, init, loc: locOf(decl) };
|
|
6031
6326
|
}
|
|
6327
|
+
// The CHECKED-DYNAMIC twin of the handle rescue (the runtime-world
|
|
6328
|
+
// local rule): an unmappable declared type over a dyn initializer
|
|
6329
|
+
// (`const first = plugins[0]` — the checker spells 'string |
|
|
6330
|
+
// object' while the read is a DOM keyed read) keeps the binding
|
|
6331
|
+
// dyn; typed use sites ride validated extractions and the routed
|
|
6332
|
+
// engine ops, exactly the JSON.parse-binding story.
|
|
6333
|
+
if (mapped === null && init.type.kind === "dyn") {
|
|
6334
|
+
const local = this.declareLocal(decl.name, decl.name.text, DYN, isLet);
|
|
6335
|
+
return { kind: "varDecl", localId: local.id, init, loc: locOf(decl) };
|
|
6336
|
+
}
|
|
6032
6337
|
if (mapped === null)
|
|
6033
6338
|
this.badType(decl.name, this.typeOf(decl.name));
|
|
6034
6339
|
// A mappable declared type with a non-island initializer: the
|
|
@@ -6402,6 +6707,27 @@ export class Lowerer {
|
|
|
6402
6707
|
const spec = requireSpecOf(decl.initializer);
|
|
6403
6708
|
return spec !== null ? canonicalBuiltinModule(spec) : null;
|
|
6404
6709
|
}
|
|
6710
|
+
// A DESTRUCTURED sub-namespace binding — `const { promises } =
|
|
6711
|
+
// fs` / `= require('fs')`: the member is itself a supported module
|
|
6712
|
+
// ("fs/promises"), so the binding carries that module's namespace
|
|
6713
|
+
// surface. canonicalBuiltinModule gates the composition (an
|
|
6714
|
+
// ordinary destructured FUNCTION binding composes to an unknown
|
|
6715
|
+
// name and answers null — builtinImportOf owns those).
|
|
6716
|
+
if (ts.isBindingElement(decl) && ts.isObjectBindingPattern(decl.parent) &&
|
|
6717
|
+
ts.isVariableDeclaration(decl.parent.parent) && decl.parent.parent.initializer !== undefined &&
|
|
6718
|
+
decl.propertyName === undefined && decl.initializer === undefined) {
|
|
6719
|
+
const name = decl.name;
|
|
6720
|
+
if (name === undefined || !ts.isIdentifier(name))
|
|
6721
|
+
return null;
|
|
6722
|
+
const init = decl.parent.parent.initializer;
|
|
6723
|
+
const spec = requireSpecOf(init);
|
|
6724
|
+
const outer = spec !== null
|
|
6725
|
+
? canonicalBuiltinModule(spec)
|
|
6726
|
+
: ts.isIdentifier(init) ? this.builtinNamespaceModuleOf(init) : null;
|
|
6727
|
+
if (outer !== null)
|
|
6728
|
+
return canonicalBuiltinModule(`${outer}/${name.text}`);
|
|
6729
|
+
return null;
|
|
6730
|
+
}
|
|
6405
6731
|
}
|
|
6406
6732
|
// The INLINE CommonJS spelling: `require("cluster").isPrimary` — the
|
|
6407
6733
|
// call expression IS the module namespace (Node evaluates the member
|
|
@@ -6509,6 +6835,17 @@ export class Lowerer {
|
|
|
6509
6835
|
const streamServed = lowerStreamModuleCall(this, call, bi, locOf(access));
|
|
6510
6836
|
if (streamServed)
|
|
6511
6837
|
return streamServed;
|
|
6838
|
+
// fs._toUnixTimestamp — off the param tables (an underscore-stable
|
|
6839
|
+
// internal), served by its own spoke before the table fence.
|
|
6840
|
+
const fsTs = this.lowerFsToUnixTimestampCall(call, bi, locOf(access));
|
|
6841
|
+
if (fsTs)
|
|
6842
|
+
return fsTs;
|
|
6843
|
+
// The fs validation-ladder spoke (checked-dynamic lane): misuse of
|
|
6844
|
+
// implemented-namespace members throws Node's typed errors instead
|
|
6845
|
+
// of meeting the table fence.
|
|
6846
|
+
const fsLadder = this.lowerFsLadderCall(call, bi, locOf(access));
|
|
6847
|
+
if (fsLadder)
|
|
6848
|
+
return fsLadder;
|
|
6512
6849
|
const builtinFn = builtinModuleFnOf(this, bi.module, bi.member);
|
|
6513
6850
|
if (!builtinFn) {
|
|
6514
6851
|
this.noLowering(`${bi.module}.${bi.member}`, call, builtinFenceHintOf(bi.module, bi.member), this.checker.getSymbolAtLocation(access.name));
|
|
@@ -6539,6 +6876,11 @@ export class Lowerer {
|
|
|
6539
6876
|
const bi = this.builtinMemberOf(expr);
|
|
6540
6877
|
if (!bi)
|
|
6541
6878
|
return null;
|
|
6879
|
+
// events.defaultMaxListeners READS the process-wide default (its
|
|
6880
|
+
// write twin routes through emitter.setDefaultMaxChk).
|
|
6881
|
+
if (bi.module === "events" && bi.member === "defaultMaxListeners") {
|
|
6882
|
+
return { kind: "libCall", fn: "emitter.getDefaultMax", args: [], type: F64, loc };
|
|
6883
|
+
}
|
|
6542
6884
|
const c = builtinModuleConstOf(this, bi.module, bi.member);
|
|
6543
6885
|
if (c !== undefined)
|
|
6544
6886
|
return builtinConstLit(c, loc);
|
|
@@ -6554,6 +6896,12 @@ export class Lowerer {
|
|
|
6554
6896
|
lowerBuiltinModuleCall(expr, bi, fn, loc) {
|
|
6555
6897
|
return lowerBuiltinModuleCall(this, expr, bi, fn, loc);
|
|
6556
6898
|
}
|
|
6899
|
+
lowerFsToUnixTimestampCall(expr, bi, loc) {
|
|
6900
|
+
return lowerFsToUnixTimestampCall(this, expr, bi, loc);
|
|
6901
|
+
}
|
|
6902
|
+
lowerFsLadderCall(expr, bi, loc) {
|
|
6903
|
+
return lowerFsLadderCall(this, expr, bi, loc);
|
|
6904
|
+
}
|
|
6557
6905
|
lowerChildArgsArg(node, loc) {
|
|
6558
6906
|
return lowerChildArgsArg(this, node, loc);
|
|
6559
6907
|
}
|