@scriptc/compiler 0.0.8 → 0.0.9
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 +108 -5
- 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 +23 -10
- 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/emitter.js +206 -11
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +55 -10
- package/dist/diagnostics/diagnostic.js +82 -20
- package/dist/diagnostics/diagnostic.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 +11 -0
- package/dist/frontend/lowering/lower-builtins.js +111 -3
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +30 -11
- package/dist/frontend/lowering/lower-calls.js +418 -8
- 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 +4 -2
- package/dist/frontend/lowering/lower-containers.js +193 -43
- package/dist/frontend/lowering/lower-containers.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 +52 -7
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +445 -13
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.js +28 -2
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +66 -14
- package/dist/frontend/lowering/lowerer.js +273 -28
- 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.js +4 -2
- package/dist/frontend/types.js.map +1 -1
- package/dist/index.js +150 -25
- package/dist/index.js.map +1 -1
- package/dist/ir/nodes.d.ts +131 -7
- package/dist/ir/nodes.js +41 -3
- package/dist/ir/nodes.js.map +1 -1
- package/dist/ir/validate.js +58 -8
- package/dist/ir/validate.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, 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,25 @@ 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
|
+
}
|
|
283
302
|
/** The checked-dynamic declaration fallback for unmappable binding types
|
|
284
303
|
* (see irTypeOf), two gates over one story:
|
|
285
304
|
*
|
|
@@ -902,7 +921,11 @@ export class Lowerer {
|
|
|
902
921
|
const recvDecl = recvDecls.find(ts.isImportClause) ?? recvDecls[0];
|
|
903
922
|
if (recvDecl && ts.isVariableDeclaration(recvDecl) && recvDecl.initializer) {
|
|
904
923
|
const spec = requireSpecOf(recvDecl.initializer);
|
|
905
|
-
const dep = spec
|
|
924
|
+
const dep = spec === null
|
|
925
|
+
? null
|
|
926
|
+
: isRelativeSpecifier(spec)
|
|
927
|
+
? resolveImport(this.program, recvDecl.getSourceFile(), spec)
|
|
928
|
+
: npmStaticDepSf7(this.program, recvDecl.getSourceFile(), spec);
|
|
906
929
|
if (dep)
|
|
907
930
|
symbol = this.cjsModuleExportSymbol(dep, ident.text);
|
|
908
931
|
}
|
|
@@ -1099,12 +1122,14 @@ export class Lowerer {
|
|
|
1099
1122
|
}
|
|
1100
1123
|
/** True when `expr` is an identifier bound by a top-level
|
|
1101
1124
|
* `const x = require("./local")` of a RELATIVE module — the CommonJS
|
|
1102
|
-
* namespace binding — or
|
|
1103
|
-
*
|
|
1104
|
-
* same
|
|
1105
|
-
*
|
|
1106
|
-
*
|
|
1107
|
-
*
|
|
1125
|
+
* namespace binding — or of a bare specifier naming an opted-in
|
|
1126
|
+
* --npm-static package (its CJS entry is a program module, so the
|
|
1127
|
+
* binding is the same namespace over the same export table), or by a
|
|
1128
|
+
* DEFAULT import of a CommonJS JS module (`import d from "./lib.cjs"`:
|
|
1129
|
+
* Node binds d to module.exports, the same value require answers).
|
|
1130
|
+
* Member accesses on it resolve through the export table (property
|
|
1131
|
+
* symbols → resolveValueSymbol); the bare value keeps the
|
|
1132
|
+
* namespace-object fence, like ESM namespace imports of builtins. */
|
|
1108
1133
|
cjsLocalModuleBindingOf(expr) {
|
|
1109
1134
|
if (!ts.isIdentifier(expr))
|
|
1110
1135
|
return false;
|
|
@@ -1122,8 +1147,12 @@ export class Lowerer {
|
|
|
1122
1147
|
return false;
|
|
1123
1148
|
}
|
|
1124
1149
|
const spec = requireSpecOf(decl.initializer);
|
|
1125
|
-
if (spec === null
|
|
1150
|
+
if (spec === null)
|
|
1126
1151
|
return false;
|
|
1152
|
+
if (!isRelativeSpecifier(spec) &&
|
|
1153
|
+
npmStaticDepSf7(this.program, decl.getSourceFile(), spec) === null) {
|
|
1154
|
+
return false;
|
|
1155
|
+
}
|
|
1127
1156
|
}
|
|
1128
1157
|
// SINGLE-VALUE exporters (`module.exports = Countdown` / `= double` /
|
|
1129
1158
|
// `= 42`): the requirer's binding IS the exported value, not a
|
|
@@ -1222,13 +1251,22 @@ export class Lowerer {
|
|
|
1222
1251
|
/** The lowering of a CommonJS `require("./local")` occurrence: a call of
|
|
1223
1252
|
* the required module's run-once %init at exactly this statement's
|
|
1224
1253
|
* position — Node's inline evaluation, with the guard supplying the
|
|
1225
|
-
* cache-hit behavior for every require after the first.
|
|
1226
|
-
*
|
|
1227
|
-
*
|
|
1254
|
+
* cache-hit behavior for every require after the first. Bare specifiers
|
|
1255
|
+
* naming an opted-in --npm-static package resolve to that package's
|
|
1256
|
+
* program entry (the same edge preflight admitted — bundle dists require
|
|
1257
|
+
* their external dependencies by name). Null for everything else
|
|
1258
|
+
* (builtins load nothing; the rest kept its preflight fence). */
|
|
1228
1259
|
requireInitStmt(spec, node) {
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1260
|
+
// Relative requires resolve within the program; a BARE require can be
|
|
1261
|
+
// a program-module edge too when it names an opted-in --npm-static
|
|
1262
|
+
// package (one package requiring another — the resolution answered
|
|
1263
|
+
// its shipped JS, the file is in the module order, and the reads
|
|
1264
|
+
// alias its globals). Without the guarded %init call at this position
|
|
1265
|
+
// those globals stay uninitialized: the dep's module body would never
|
|
1266
|
+
// run.
|
|
1267
|
+
const dep = isRelativeSpecifier(spec)
|
|
1268
|
+
? resolveImport(this.program, node.getSourceFile(), spec)
|
|
1269
|
+
: npmStaticDepSf7(this.program, node.getSourceFile(), spec);
|
|
1232
1270
|
if (!dep || dep.fileName.endsWith(".json"))
|
|
1233
1271
|
return null;
|
|
1234
1272
|
const initName = this.initNameOf.get(dep);
|
|
@@ -1830,8 +1868,8 @@ export class Lowerer {
|
|
|
1830
1868
|
throw new PoisonError();
|
|
1831
1869
|
}
|
|
1832
1870
|
// Would-be records with INDEX SIGNATURES (`Record<string, T>`,
|
|
1833
|
-
// `{ [k: string]: T }`) get
|
|
1834
|
-
//
|
|
1871
|
+
// `{ [k: string]: T }`) get the index-signature fence (SC2006) naming
|
|
1872
|
+
// the supported key/value domain instead of the generic
|
|
1835
1873
|
// supported-types recitation.
|
|
1836
1874
|
if (widened.flags & (ts.TypeFlags.Object | ts.TypeFlags.Intersection) &&
|
|
1837
1875
|
this.checker.getCallSignatures(widened).length === 0 &&
|
|
@@ -1950,9 +1988,27 @@ export class Lowerer {
|
|
|
1950
1988
|
}
|
|
1951
1989
|
}
|
|
1952
1990
|
// STANDARD-LIBRARY nominal types with no lowering at all: the SC2020
|
|
1953
|
-
// story, naming the type
|
|
1991
|
+
// story, naming the type — and for the families with a WHY, the same
|
|
1992
|
+
// pointed reason the identifier/constructor chokepoints teach.
|
|
1954
1993
|
if (stdlibNominal) {
|
|
1955
|
-
|
|
1994
|
+
const intlHint = "Intl formatter values have no representation — the COMPOSED en-US forms lower: " +
|
|
1995
|
+
'new Intl.NumberFormat("en-US").format(x) and x.toLocaleString("en-US") with default options; ' +
|
|
1996
|
+
"the rest is ICU locale data the binary does not carry";
|
|
1997
|
+
const typeHints = {
|
|
1998
|
+
ArrayBuffer: "no free-standing ArrayBuffer value exists — typed arrays own their storage " +
|
|
1999
|
+
"(new Uint8Array(n) allocates; new Uint8Array(new ArrayBuffer(n)) erases the buffer into the view)",
|
|
2000
|
+
SharedArrayBuffer: "no shared-memory threads exist in a compiled program — Uint8Array is the byte storage",
|
|
2001
|
+
NumberFormat: intlHint,
|
|
2002
|
+
DateTimeFormat: intlHint,
|
|
2003
|
+
DurationFormat: intlHint,
|
|
2004
|
+
PluralRules: intlHint,
|
|
2005
|
+
Collator: intlHint,
|
|
2006
|
+
ListFormat: intlHint,
|
|
2007
|
+
RelativeTimeFormat: intlHint,
|
|
2008
|
+
Segmenter: intlHint,
|
|
2009
|
+
DisplayNames: intlHint,
|
|
2010
|
+
};
|
|
2011
|
+
this.pushDiag(noLoweringDiag(this.checker.typeToString(type), locOf(node), typeHints[stdlibOwnSym?.name ?? ""]));
|
|
1956
2012
|
throw new PoisonError();
|
|
1957
2013
|
}
|
|
1958
2014
|
// USER record shapes blocked by ONE member (SC2009's record arm):
|
|
@@ -2147,8 +2203,10 @@ export class Lowerer {
|
|
|
2147
2203
|
}
|
|
2148
2204
|
/** Exact-shape enforcement (SC2002). Records are monomorphic structs, so
|
|
2149
2205
|
* everywhere a value flows into a typed slot (call arg, initializer,
|
|
2150
|
-
* assignment, field, return) the shapes must MATCH —
|
|
2151
|
-
*
|
|
2206
|
+
* assignment, field, return) the shapes must MATCH — or width-coerce:
|
|
2207
|
+
* coerceToExpected already ran widthCoerce (the copy-reshape family),
|
|
2208
|
+
* so what reaches here is the RESIDUE its rules decline, and the
|
|
2209
|
+
* diagnostic names the first blocking rule (describeRecordWidthBlocker).
|
|
2152
2210
|
* Non-record mismatches are not reachable through tsc-clean programs; the
|
|
2153
2211
|
* validator ICEs on them as the usual backstop. */
|
|
2154
2212
|
requireExactShape(node, actual, expected) {
|
|
@@ -2207,7 +2265,13 @@ export class Lowerer {
|
|
|
2207
2265
|
throw new PoisonError();
|
|
2208
2266
|
}
|
|
2209
2267
|
if (containsRecord(actual) || containsRecord(expected)) {
|
|
2210
|
-
|
|
2268
|
+
// A record→record pair gets the pointed story: WHICH width rule
|
|
2269
|
+
// declined (a field that doesn't lift, a required field with no
|
|
2270
|
+
// source, an index signature that could hold the completed key).
|
|
2271
|
+
const detail = actual.kind === "record" && expected.kind === "record"
|
|
2272
|
+
? (this.describeRecordWidthBlocker(actual.shapeId, expected.shapeId) ?? undefined)
|
|
2273
|
+
: undefined;
|
|
2274
|
+
this.pushDiag(recordShapeMismatchDiag(this.fmt(expected), this.fmt(actual), locOf(node), detail));
|
|
2211
2275
|
throw new PoisonError();
|
|
2212
2276
|
}
|
|
2213
2277
|
// Everything else — a plain-kind mismatch like a string flowing into a
|
|
@@ -2705,10 +2769,23 @@ export class Lowerer {
|
|
|
2705
2769
|
* recursively — NESTED width)
|
|
2706
2770
|
* arr — array into array whose element pair lifts (per-element
|
|
2707
2771
|
* copy loop, arrayWidthHelper)
|
|
2772
|
+
* dynIn — a typed value into an 'unknown' (dyn) slot — the same
|
|
2773
|
+
* static→DOM deep copy coerceToExpected applies top-level
|
|
2774
|
+
* upcast — a derived class instance into a base-typed slot (the
|
|
2775
|
+
* prefix-layout pointer reinterpret, no copy)
|
|
2776
|
+
* funcAdapt — a function into a slot whose signature differs only by
|
|
2777
|
+
* CLEAN mechanical conversions (cleanFuncAdaptable); the
|
|
2778
|
+
* stranded (trap-only) dispositions stay out of the plan
|
|
2708
2779
|
* Null when the pair isn't in the relation — callers keep their fences. */
|
|
2709
2780
|
widthLiftPlan(src, dst) {
|
|
2710
2781
|
if (typeEquals(src, dst))
|
|
2711
2782
|
return { how: "copy" };
|
|
2783
|
+
// An 'unknown' (dyn) DESTINATION slot: the static→DOM conversion —
|
|
2784
|
+
// dynFrom, a DEEP COPY (`{ v: 5 }` into `{ v: unknown }`, `number[]`
|
|
2785
|
+
// into `unknown[]` — tsc's top type over the width family's copies).
|
|
2786
|
+
if (dst.kind === "dyn" && src.kind !== "dyn" && this.dynConvertible(src)) {
|
|
2787
|
+
return { how: "dynIn" };
|
|
2788
|
+
}
|
|
2712
2789
|
if (dst.kind === "union") {
|
|
2713
2790
|
if (src.kind === "union") {
|
|
2714
2791
|
return this.unionRetagMappable(src.unionId, dst.unionId) ? { how: "retag" } : null;
|
|
@@ -2747,6 +2824,23 @@ export class Lowerer {
|
|
|
2747
2824
|
if (src.kind === "union" && !isUnitType(dst) && dst.kind !== "void" && this.armTag(src.unionId, dst) >= 0) {
|
|
2748
2825
|
return { how: "narrow" };
|
|
2749
2826
|
}
|
|
2827
|
+
// A DERIVED instance into a BASE-typed slot (`{ p: Q }` copying into
|
|
2828
|
+
// `{ p: P }`): the same implicit upcast coerceToExpected performs at
|
|
2829
|
+
// top level — prefix layout, a pointer reinterpret, no copy.
|
|
2830
|
+
if (dst.kind === "object" &&
|
|
2831
|
+
src.kind === "object" &&
|
|
2832
|
+
this.isSubclassOf(src.className, dst.className)) {
|
|
2833
|
+
return { how: "upcast" };
|
|
2834
|
+
}
|
|
2835
|
+
// A FUNCTION into a slot whose signature differs only by CLEAN
|
|
2836
|
+
// mechanical conversions (fewer params — JS ignores extras — and
|
|
2837
|
+
// coercibleValue pieces): the general function-value adapter, plan-
|
|
2838
|
+
// gated to the clean subset. The stranded (trap-only) dispositions
|
|
2839
|
+
// funcCoerceAdapter also builds stay TOP-LEVEL only: a width plan
|
|
2840
|
+
// never promises a bridge that can only throw.
|
|
2841
|
+
if (dst.kind === "func" && src.kind === "func" && this.cleanFuncAdaptable(src, dst)) {
|
|
2842
|
+
return { how: "funcAdapt" };
|
|
2843
|
+
}
|
|
2750
2844
|
if (dst.kind === "record" && src.kind === "record") {
|
|
2751
2845
|
return this.recordWidthPlan(src.shapeId, dst.shapeId) !== null ? { how: "width" } : null;
|
|
2752
2846
|
}
|
|
@@ -2874,6 +2968,24 @@ export class Lowerer {
|
|
|
2874
2968
|
throw new Error("lowerer bug: planned narrow lift failed to intern");
|
|
2875
2969
|
return { kind: "call", callee: helper, args: [value], type: dst, loc };
|
|
2876
2970
|
}
|
|
2971
|
+
case "dynIn": {
|
|
2972
|
+
if (dst.kind !== "dyn")
|
|
2973
|
+
throw new Error("lowerer bug: dynIn lift against a non-dyn slot");
|
|
2974
|
+
return { kind: "dynFrom", value, type: DYN, loc };
|
|
2975
|
+
}
|
|
2976
|
+
case "upcast": {
|
|
2977
|
+
if (dst.kind !== "object" || value.type.kind !== "object")
|
|
2978
|
+
throw new Error("lowerer bug: upcast lift shape");
|
|
2979
|
+
return this.upcastTo(value, dst.className);
|
|
2980
|
+
}
|
|
2981
|
+
case "funcAdapt": {
|
|
2982
|
+
if (dst.kind !== "func" || value.type.kind !== "func")
|
|
2983
|
+
throw new Error("lowerer bug: funcAdapt lift shape");
|
|
2984
|
+
const adapter = this.funcCoerceAdapter(value.type, dst, loc);
|
|
2985
|
+
if (!adapter)
|
|
2986
|
+
throw new Error("lowerer bug: planned funcAdapt lift failed to intern");
|
|
2987
|
+
return { kind: "call", callee: adapter, args: [value], type: dst, loc };
|
|
2988
|
+
}
|
|
2877
2989
|
default: {
|
|
2878
2990
|
const _exhaustive = lift;
|
|
2879
2991
|
void _exhaustive;
|
|
@@ -2891,9 +3003,11 @@ export class Lowerer {
|
|
|
2891
3003
|
* optional-flavored field completes to its undefined arm (the
|
|
2892
3004
|
* literal-completion rule). TUPLES width-coerce too, arity-exact (TS
|
|
2893
3005
|
* permits no other tuple width): per-position lifts, never completion.
|
|
2894
|
-
* Index-signature
|
|
2895
|
-
*
|
|
2896
|
-
*
|
|
3006
|
+
* Index-signature SOURCES narrow here like any wider record — declared
|
|
3007
|
+
* fields copy, the overflow drops with the width (missing target
|
|
3008
|
+
* fields decline: the overflow could hold them). Index-signature
|
|
3009
|
+
* TARGETS keep the overflow CAPTURE helper (widthCoerce's other arm).
|
|
3010
|
+
* Null when the shapes don't relate that way. */
|
|
2897
3011
|
/** The pure planning half of recordWidthHelper — every target field's
|
|
2898
3012
|
* lift, or null when the pair isn't width-coercible. Callers that must
|
|
2899
3013
|
* validate a WHOLE plan before interning anything (the retag helper's
|
|
@@ -2901,7 +3015,13 @@ export class Lowerer {
|
|
|
2901
3015
|
recordWidthPlan(fromId, toId) {
|
|
2902
3016
|
const from = this.shapes.get(fromId);
|
|
2903
3017
|
const to = this.shapes.get(toId);
|
|
2904
|
-
|
|
3018
|
+
// INDEX-SIGNATURE sources narrow like any wider record — the target
|
|
3019
|
+
// fields copy off the declared struct slots and the overflow drops
|
|
3020
|
+
// with the rest of the width (divergence 36's stance; the absent-
|
|
3021
|
+
// completion rule below is the one extra fence). Index-signature
|
|
3022
|
+
// TARGETS keep the overflow CAPTURE helper (widthCoerce's other arm):
|
|
3023
|
+
// a fresh hybrid needs keyed writes, not a field-list literal.
|
|
3024
|
+
if (!from || !to || to.indexValue)
|
|
2905
3025
|
return null;
|
|
2906
3026
|
// Tuple↔record pairs never relate; tuple↔tuple only arity-exact.
|
|
2907
3027
|
if (!!from.tuple !== !!to.tuple)
|
|
@@ -2926,8 +3046,12 @@ export class Lowerer {
|
|
|
2926
3046
|
// the absent-property read: the options-record call shape
|
|
2927
3047
|
// against `{ plugins: unknown, ... }`). Never for tuples: a
|
|
2928
3048
|
// completed position would change .length and JSON where Node
|
|
2929
|
-
// keeps the source arity.
|
|
2930
|
-
|
|
3049
|
+
// keeps the source arity. Never for INDEX-SIGNATURE sources:
|
|
3050
|
+
// the overflow may hold this very key at runtime (tsc lets the
|
|
3051
|
+
// signature satisfy optional target members), so completing to
|
|
3052
|
+
// undefined would drop a value Node keeps — the pair stays
|
|
3053
|
+
// fenced.
|
|
3054
|
+
if (from.tuple || from.indexValue)
|
|
2931
3055
|
return null;
|
|
2932
3056
|
if (tf.type.kind === "dyn") {
|
|
2933
3057
|
plan.set(tf.name, { absentDyn: true });
|
|
@@ -2953,6 +3077,92 @@ export class Lowerer {
|
|
|
2953
3077
|
this.widthPlanning.delete(key);
|
|
2954
3078
|
}
|
|
2955
3079
|
}
|
|
3080
|
+
/** Post-hoc classifier for SC2002's record→record residue: WHY the
|
|
3081
|
+
* width family (recordWidthPlan and the overflow capture — widthCoerce's
|
|
3082
|
+
* two record arms) declined this pair — the FIRST blocking rule, named.
|
|
3083
|
+
* Pure description on the failure path (the site already carries the
|
|
3084
|
+
* rejection): mirrors the planners' gates, never changes what coerces,
|
|
3085
|
+
* and answers null when no pointed story applies (the generic message
|
|
3086
|
+
* stands). */
|
|
3087
|
+
describeRecordWidthBlocker(fromId, toId) {
|
|
3088
|
+
const from = this.shapes.get(fromId);
|
|
3089
|
+
const to = this.shapes.get(toId);
|
|
3090
|
+
if (!from || !to)
|
|
3091
|
+
return null;
|
|
3092
|
+
if (to.indexValue) {
|
|
3093
|
+
// The overflow CAPTURE's gates (lowerRecordOvfCaptureHelper).
|
|
3094
|
+
if (from.tuple || to.tuple)
|
|
3095
|
+
return "a tuple cannot reshape into an index-signature record";
|
|
3096
|
+
const tIv = to.indexValue;
|
|
3097
|
+
const slotOk = (t) => typeEquals(t, tIv) ||
|
|
3098
|
+
(tIv.kind === "dyn" && (t.kind === "dyn" || this.dynConvertible(t))) ||
|
|
3099
|
+
this.widthLiftPlan(t, tIv) !== null;
|
|
3100
|
+
const consumed = new Set();
|
|
3101
|
+
for (const tf of to.fields) {
|
|
3102
|
+
const sf = from.fields.find((f) => f.name === tf.name);
|
|
3103
|
+
if (sf) {
|
|
3104
|
+
if (this.widthLiftPlan(sf.type, tf.type) !== null) {
|
|
3105
|
+
consumed.add(tf.name);
|
|
3106
|
+
continue;
|
|
3107
|
+
}
|
|
3108
|
+
return `field '${tf.name}': '${this.fmt(sf.type)}' does not lift into '${this.fmt(tf.type)}'`;
|
|
3109
|
+
}
|
|
3110
|
+
if (tf.type.kind !== "union" || this.armTag(tf.type.unionId, UNDEFINED_T) < 0) {
|
|
3111
|
+
return `the expected field '${tf.name}' is required and the source has no field to copy into it`;
|
|
3112
|
+
}
|
|
3113
|
+
if (tIv.kind === "dyn" ? !this.dynConvertible(tf.type) : !typeEquals(tf.type, tIv)) {
|
|
3114
|
+
return `the expected field '${tf.name}' ('${this.fmt(tf.type)}') cannot take a runtime key collision from the '${this.fmt(tIv)}' signature slot`;
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
3117
|
+
for (const ff of from.fields) {
|
|
3118
|
+
if (consumed.has(ff.name))
|
|
3119
|
+
continue;
|
|
3120
|
+
if (!slotOk(ff.type)) {
|
|
3121
|
+
return `the source field '${ff.name}' ('${this.fmt(ff.type)}') cannot enter the expected '[key: string]: ${this.fmt(tIv)}' slot`;
|
|
3122
|
+
}
|
|
3123
|
+
}
|
|
3124
|
+
if (from.indexValue && !slotOk(from.indexValue)) {
|
|
3125
|
+
return `the source's '[key: string]: ${this.fmt(from.indexValue)}' slot cannot enter the expected '[key: string]: ${this.fmt(tIv)}' slot`;
|
|
3126
|
+
}
|
|
3127
|
+
// The dispatch-writes gate: runtime-keyed writes can collide with a
|
|
3128
|
+
// declared field whose type is not the slot's.
|
|
3129
|
+
const dispatchWrites = from.indexValue !== undefined ||
|
|
3130
|
+
from.fields.some((ff) => !consumed.has(ff.name) && to.fields.some((f) => f.name === ff.name));
|
|
3131
|
+
if (dispatchWrites) {
|
|
3132
|
+
const bad = to.fields.find((f) => tIv.kind === "dyn" ? !this.dynConvertible(f.type) : !typeEquals(f.type, tIv));
|
|
3133
|
+
if (bad) {
|
|
3134
|
+
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`;
|
|
3135
|
+
}
|
|
3136
|
+
}
|
|
3137
|
+
return null;
|
|
3138
|
+
}
|
|
3139
|
+
// The field-copy plan's gates (recordWidthPlan).
|
|
3140
|
+
if (!!from.tuple !== !!to.tuple)
|
|
3141
|
+
return null;
|
|
3142
|
+
if (from.tuple && from.fields.length !== to.fields.length) {
|
|
3143
|
+
return `tuple arities differ (${from.fields.length} vs ${to.fields.length}; TS permits no tuple width)`;
|
|
3144
|
+
}
|
|
3145
|
+
for (const tf of to.fields) {
|
|
3146
|
+
const ff = from.fields.find((f) => f.name === tf.name);
|
|
3147
|
+
if (!ff) {
|
|
3148
|
+
if (from.tuple)
|
|
3149
|
+
return null;
|
|
3150
|
+
if (from.indexValue) {
|
|
3151
|
+
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)`;
|
|
3152
|
+
}
|
|
3153
|
+
if (tf.type.kind === "dyn")
|
|
3154
|
+
continue;
|
|
3155
|
+
if (tf.type.kind !== "union" || this.armTag(tf.type.unionId, UNDEFINED_T) < 0) {
|
|
3156
|
+
return `the expected field '${tf.name}' is missing on the source and is not optional`;
|
|
3157
|
+
}
|
|
3158
|
+
continue;
|
|
3159
|
+
}
|
|
3160
|
+
if (this.widthLiftPlan(ff.type, tf.type) === null) {
|
|
3161
|
+
return `field '${tf.name}': '${this.fmt(ff.type)}' does not lift into '${this.fmt(tf.type)}'`;
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
3164
|
+
return null;
|
|
3165
|
+
}
|
|
2956
3166
|
recordWidthHelper(fromId, toId, loc) {
|
|
2957
3167
|
const from = this.shapes.get(fromId);
|
|
2958
3168
|
const to = this.shapes.get(toId);
|
|
@@ -3611,6 +3821,28 @@ export class Lowerer {
|
|
|
3611
3821
|
}
|
|
3612
3822
|
return false;
|
|
3613
3823
|
}
|
|
3824
|
+
/** True when a `src` function value enters a `dst` slot through
|
|
3825
|
+
* funcCoerceAdapter with NO stranded (trap-only) piece: no rest packs,
|
|
3826
|
+
* no surplus source params, every slot parameter converts into the
|
|
3827
|
+
* wrapped function's own type, and the result converts back (a void
|
|
3828
|
+
* slot drops it; a void result answers the exact JS undefined for
|
|
3829
|
+
* dyn/jsval slots). The width family's func gate — widthLiftPlan
|
|
3830
|
+
* bridges only signatures whose every call succeeds by construction. */
|
|
3831
|
+
cleanFuncAdaptable(src, dst) {
|
|
3832
|
+
if (src.rest === true || dst.rest === true)
|
|
3833
|
+
return false;
|
|
3834
|
+
if (src.params.length > dst.params.length)
|
|
3835
|
+
return false;
|
|
3836
|
+
for (let i = 0; i < src.params.length; i++) {
|
|
3837
|
+
if (!this.coercibleValue(dst.params[i], src.params[i]))
|
|
3838
|
+
return false;
|
|
3839
|
+
}
|
|
3840
|
+
if (dst.ret.kind === "void")
|
|
3841
|
+
return src.ret.kind !== "jsval";
|
|
3842
|
+
if (this.coercibleValue(src.ret, dst.ret))
|
|
3843
|
+
return true;
|
|
3844
|
+
return src.ret.kind === "void" && (dst.ret.kind === "dyn" || dst.ret.kind === "jsval");
|
|
3845
|
+
}
|
|
3614
3846
|
/** Interned `%fn.adapt.<n>(f)` — the GENERAL function-value adapter: a
|
|
3615
3847
|
* `fromT` function value flowing into a `toT` slot whose pieces differ
|
|
3616
3848
|
* only by coercibleValue conversions. The slot's callers pass toT's
|
|
@@ -6509,6 +6741,11 @@ export class Lowerer {
|
|
|
6509
6741
|
const streamServed = lowerStreamModuleCall(this, call, bi, locOf(access));
|
|
6510
6742
|
if (streamServed)
|
|
6511
6743
|
return streamServed;
|
|
6744
|
+
// fs._toUnixTimestamp — off the param tables (an underscore-stable
|
|
6745
|
+
// internal), served by its own spoke before the table fence.
|
|
6746
|
+
const fsTs = this.lowerFsToUnixTimestampCall(call, bi, locOf(access));
|
|
6747
|
+
if (fsTs)
|
|
6748
|
+
return fsTs;
|
|
6512
6749
|
const builtinFn = builtinModuleFnOf(this, bi.module, bi.member);
|
|
6513
6750
|
if (!builtinFn) {
|
|
6514
6751
|
this.noLowering(`${bi.module}.${bi.member}`, call, builtinFenceHintOf(bi.module, bi.member), this.checker.getSymbolAtLocation(access.name));
|
|
@@ -6539,6 +6776,11 @@ export class Lowerer {
|
|
|
6539
6776
|
const bi = this.builtinMemberOf(expr);
|
|
6540
6777
|
if (!bi)
|
|
6541
6778
|
return null;
|
|
6779
|
+
// events.defaultMaxListeners READS the process-wide default (its
|
|
6780
|
+
// write twin routes through emitter.setDefaultMaxChk).
|
|
6781
|
+
if (bi.module === "events" && bi.member === "defaultMaxListeners") {
|
|
6782
|
+
return { kind: "libCall", fn: "emitter.getDefaultMax", args: [], type: F64, loc };
|
|
6783
|
+
}
|
|
6542
6784
|
const c = builtinModuleConstOf(this, bi.module, bi.member);
|
|
6543
6785
|
if (c !== undefined)
|
|
6544
6786
|
return builtinConstLit(c, loc);
|
|
@@ -6554,6 +6796,9 @@ export class Lowerer {
|
|
|
6554
6796
|
lowerBuiltinModuleCall(expr, bi, fn, loc) {
|
|
6555
6797
|
return lowerBuiltinModuleCall(this, expr, bi, fn, loc);
|
|
6556
6798
|
}
|
|
6799
|
+
lowerFsToUnixTimestampCall(expr, bi, loc) {
|
|
6800
|
+
return lowerFsToUnixTimestampCall(this, expr, bi, loc);
|
|
6801
|
+
}
|
|
6557
6802
|
lowerChildArgsArg(node, loc) {
|
|
6558
6803
|
return lowerChildArgsArg(this, node, loc);
|
|
6559
6804
|
}
|