@scriptc/compiler 0.0.7 → 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.
Files changed (94) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +13 -0
  2. package/dist/backend/cc.js +14 -0
  3. package/dist/backend/cc.js.map +1 -1
  4. package/dist/backend/emission/emit-exprs.js +155 -6
  5. package/dist/backend/emission/emit-exprs.js.map +1 -1
  6. package/dist/backend/emission/emit-island.js +9 -1
  7. package/dist/backend/emission/emit-island.js.map +1 -1
  8. package/dist/backend/emission/emit-stmts.js +3 -1
  9. package/dist/backend/emission/emit-stmts.js.map +1 -1
  10. package/dist/backend/emission/emit-types.d.ts +3 -0
  11. package/dist/backend/emission/emit-types.js +12 -0
  12. package/dist/backend/emission/emit-types.js.map +1 -1
  13. package/dist/backend/emission/emit-walkers.d.ts +7 -5
  14. package/dist/backend/emission/emit-walkers.js +45 -18
  15. package/dist/backend/emission/emit-walkers.js.map +1 -1
  16. package/dist/backend/emission/emitter.d.ts +1 -1
  17. package/dist/backend/emission/emitter.js +35 -10
  18. package/dist/backend/emission/emitter.js.map +1 -1
  19. package/dist/backend/emission/may-throw.js +4 -3
  20. package/dist/backend/emission/may-throw.js.map +1 -1
  21. package/dist/backend/llvm/emitter.js +300 -18
  22. package/dist/backend/llvm/emitter.js.map +1 -1
  23. package/dist/diagnostics/diagnostic.d.ts +98 -11
  24. package/dist/diagnostics/diagnostic.js +185 -25
  25. package/dist/diagnostics/diagnostic.js.map +1 -1
  26. package/dist/frontend/lib-contract.d.ts +24 -6
  27. package/dist/frontend/lib-contract.js +125 -44
  28. package/dist/frontend/lib-contract.js.map +1 -1
  29. package/dist/frontend/lowering/lower-assert.js +16 -0
  30. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  31. package/dist/frontend/lowering/lower-builtins.d.ts +11 -0
  32. package/dist/frontend/lowering/lower-builtins.js +127 -4
  33. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  34. package/dist/frontend/lowering/lower-calls.d.ts +77 -18
  35. package/dist/frontend/lowering/lower-calls.js +978 -44
  36. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  37. package/dist/frontend/lowering/lower-classes.d.ts +14 -1
  38. package/dist/frontend/lowering/lower-classes.js +112 -16
  39. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  40. package/dist/frontend/lowering/lower-containers.d.ts +4 -2
  41. package/dist/frontend/lowering/lower-containers.js +236 -44
  42. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  43. package/dist/frontend/lowering/lower-emitter.js +55 -1
  44. package/dist/frontend/lowering/lower-emitter.js.map +1 -1
  45. package/dist/frontend/lowering/lower-exprs.d.ts +26 -3
  46. package/dist/frontend/lowering/lower-exprs.js +507 -47
  47. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  48. package/dist/frontend/lowering/lower-island.d.ts +7 -0
  49. package/dist/frontend/lowering/lower-island.js +71 -10
  50. package/dist/frontend/lowering/lower-island.js.map +1 -1
  51. package/dist/frontend/lowering/lower-mixins.d.ts +1 -1
  52. package/dist/frontend/lowering/lower-mixins.js +1 -1
  53. package/dist/frontend/lowering/lower-modules.js +95 -4
  54. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  55. package/dist/frontend/lowering/lower-stmts.js +866 -56
  56. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  57. package/dist/frontend/lowering/lower-stream.js +28 -2
  58. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  59. package/dist/frontend/lowering/lowerer.d.ts +85 -17
  60. package/dist/frontend/lowering/lowerer.js +459 -37
  61. package/dist/frontend/lowering/lowerer.js.map +1 -1
  62. package/dist/frontend/lowering/surfaces.js +20 -3
  63. package/dist/frontend/lowering/surfaces.js.map +1 -1
  64. package/dist/frontend/npm-static-rewrite.d.ts +7 -2
  65. package/dist/frontend/npm-static-rewrite.js +566 -138
  66. package/dist/frontend/npm-static-rewrite.js.map +1 -1
  67. package/dist/frontend/npm-static.js +11 -2
  68. package/dist/frontend/npm-static.js.map +1 -1
  69. package/dist/frontend/program.js +5 -5
  70. package/dist/frontend/program.js.map +1 -1
  71. package/dist/frontend/shared.d.ts +6 -1
  72. package/dist/frontend/shared.js +46 -1
  73. package/dist/frontend/shared.js.map +1 -1
  74. package/dist/frontend/types.d.ts +28 -1
  75. package/dist/frontend/types.js +304 -10
  76. package/dist/frontend/types.js.map +1 -1
  77. package/dist/index.d.ts +2 -1
  78. package/dist/index.js +181 -26
  79. package/dist/index.js.map +1 -1
  80. package/dist/ir/nodes.d.ts +159 -9
  81. package/dist/ir/nodes.js +76 -6
  82. package/dist/ir/nodes.js.map +1 -1
  83. package/dist/ir/validate.js +93 -14
  84. package/dist/ir/validate.js.map +1 -1
  85. package/dist/library/profile.d.ts +17 -3
  86. package/dist/library/profile.js +38 -9
  87. package/dist/library/profile.js.map +1 -1
  88. package/dist/library/sidecar.js +162 -43
  89. package/dist/library/sidecar.js.map +1 -1
  90. package/dist/library/trap-teaching.d.ts +11 -0
  91. package/dist/library/trap-teaching.js +49 -0
  92. package/dist/library/trap-teaching.js.map +1 -0
  93. package/package.json +2 -2
  94. package/surface-manifest.json +46 -4
@@ -14,11 +14,11 @@
14
14
  */
15
15
  import { isRelativeSpecifier } from "../shared.js";
16
16
  import * as ts from "../ts7/adapter.js";
17
- import { anyOpRequiresDynamicDiag, blockedBindingUseDiag, checkerPanicDiag, isCheckerPanic, genericSignatureTypeDiag, indexSignatureTypeDiag, noLoweringDiag, recordShapeMismatchDiag, requiresDynamicApiDiag, requiresDynamicPackageDiag, requiresDynamicTypeDiag, unionMismatchDiag, unsupportedDiag, unsupportedTypeDiag, } from "../../diagnostics/diagnostic.js";
17
+ import { anyOpRequiresDynamicDiag, blockedBindingUseDiag, checkerPanicDiag, componentTypeDiag, isCheckerPanic, genericSignatureTypeDiag, indexSignatureTypeDiag, intersectionTypeDiag, noLoweringDiag, overloadedSignatureTypeDiag, recordShapeMismatchDiag, requiresDynamicApiDiag, requiresDynamicPackageDiag, requiresDynamicTypeDiag, unionMismatchDiag, unsupportedDiag, unsupportedTypeDiag, } from "../../diagnostics/diagnostic.js";
18
18
  import { arrayOf, BOOL, canAdaptDynFuncTo, canConvertToDyn, canCrossIslandBoundary, canExitIslandToType, canMarshalTypedFuncIntoIsland, DYN, F64, isJsonSafeType, isUndefinedArmedUnion, isUnitType, JSVAL, RUNTIME_ERROR_CLASSES, STRING, typeEquals, UNDEFINED_T, VOID } from "../../ir/nodes.js";
19
19
  import { provenanceActive } from "../provenance-registry.js";
20
20
  import { ambientDtsPath, canonicalBuiltinModule, cjsExportAssignmentOf, cjsExportDiscardReason, fallbackDtsPath, isCjsExportTableLiteral, isJsSourceFile, isNodeEsmFile, isNodeTypesPath, locOf, overridesDtsPath, npmStaticDepSf7, requireSpecOf, resolveImport, workspacePackageOfPath, } from "../program.js";
21
- import { containsRecord, containsUnion, formatIrType, ISLAND_AMBIENT_TYPES, isUnitOnlyTsType, mapType, ShapeRegistry, typeKey, UnionRegistry, withUndefinedArm as withUndefinedArmCanonical, } from "../types.js";
21
+ import { containsRecord, containsUnion, describeComponentBlocker, describeRecordMemberBlocker, 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
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";
@@ -26,8 +26,8 @@ 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";
30
- import { isIslandExpr, islandRegexpOf, jsvalIn, requireDynamicApi, islandGlobalFnOf, lowerDynamicImportCall, lowerFetchCall, lowerIslandMethodCall, lowerMathProperty, npmPackageOf, npmMemberFence, npmPackageOfSymbol } from "./lower-island.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
+ 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";
33
33
  import { lowerNodeTestModuleCall, lowerTestDirectCall, lowerTestMethodCall, lowerTestCtxProperty } from "./lower-test.js";
@@ -35,7 +35,7 @@ import { lowerAssertModuleCall, lowerAssertDirectCall } from "./lower-assert.js"
35
35
  import { lowerUtilModuleCall } from "./lower-inspect.js";
36
36
  import { lowerComptime, comptimeBakeable, rejectComptimeCaptures, comptimeValueToIr } from "./lower-comptime.js";
37
37
  import { lowerStmts, noteBlockedBindings, isBlockedBinding, lowerScopedBlock, predeclareForwardCapture, predeclareForwardFnDecl, predeclareForwardVar, rejectJumpCrossingFinally, lowerStmt, lowerVarStatement, lowerDestructuringDecl, lowerDestructuringAssignParts, lowerBindingPattern, lowerJsvalBindingPattern, checkBindingElement, bindPatternTarget, lowerVarDeclList, lowerVarDecl, lowerSwitch, lowerTry, lowerExprStatement, lowerForOf, lowerForStatement } from "./lower-stmts.js";
38
- import { lowerExpr, maybeNarrow, lowerUnitComparison, lowerNullishCoalesce, lowerOptionalChain, finishOptionalChain, lowerCondition, ensureBool, requireTruthyUnion, eqComparableUnion, lowerIntrinsicProperty, lowerArrayLiteral, lowerObjectLiteral, lowerShorthandValue, rejectThisInObjectMethod, lowerElementAccess, lowerElementWrite, lowerRecordKeyRead, ensureString, lowerTemplate, lowerAsExpression, lowerPrefixUnary, lowerBinary, lowerCaughtTypeofTest, caughtRead, caughtLocalOf, caughtToString, lowerInstanceOf, lowerRegexLiteral, lowerFieldRead, lowerUnionProperty, fieldTarget, fieldGetExpr, fieldSetStmt, lowerFieldCompound, uniqueSymbolKeyOf, foldedStringKeyOf } from "./lower-exprs.js";
38
+ import { lowerDynObjectLiteral, lowerExpr, maybeNarrow, lowerUnitComparison, lowerNullishCoalesce, lowerOptionalChain, finishOptionalChain, lowerCondition, ensureBool, requireTruthyUnion, eqComparableUnion, lowerIntrinsicProperty, lowerArrayLiteral, lowerObjectLiteral, lowerShorthandValue, rejectThisInObjectMethod, lowerElementAccess, lowerElementWrite, lowerRecordKeyRead, ensureString, lowerTemplate, lowerAsExpression, lowerPrefixUnary, lowerBinary, lowerCaughtTypeofTest, caughtRead, caughtLocalOf, caughtToString, lowerInstanceOf, lowerRegexLiteral, lowerFieldRead, lowerUnionProperty, fieldTarget, fieldGetExpr, fieldSetStmt, lowerFieldCompound, uniqueSymbolKeyOf, foldedStringKeyOf } from "./lower-exprs.js";
39
39
  import { lowerRecordFieldCall, lowerObjectMethodCall } from "./lower-calls.js";
40
40
  import { fenceCrossBlockNsRef, nsPathPrefix } from "./lower-namespaces.js";
41
41
  /** Entry function name. '%' cannot appear in a TS identifier, so a user
@@ -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
  *
@@ -468,6 +487,12 @@ export class Lowerer {
468
487
  /** Non-null while an instance body lowers: type-parameter symbol →
469
488
  * concrete IR type, consulted inside mapType's recursion. */
470
489
  typeParamBindings = null;
490
+ /** The ts-level twin of typeParamBindings, non-null while a CALL-keyed
491
+ * instance body lowers: type-parameter symbol → the bound CHECKER type,
492
+ * consulted where the mapped IrType has already widened away information
493
+ * the body needs — indexed accesses (`T[K]` needs K's literal key) and
494
+ * keyed record reads (`o[k]` where k's type is a literal-bound K). */
495
+ typeParamTsBindings = null;
471
496
  /** Non-null while an IMPLICIT-ANY instance body lowers (npm-static JS —
472
497
  * lower-calls' implicit-monomorphization section): bound param symbol →
473
498
  * the call site's checker type, consulted by typeOf for identifier
@@ -811,6 +836,7 @@ export class Lowerer {
811
836
  unions: this.unions,
812
837
  classNamer: this.classNamer,
813
838
  resolveTypeParam: this.typeParamResolver,
839
+ resolveTypeParamTs: this.typeParamTsResolver,
814
840
  genericClassInstance: (decl, ref) => this.genericClassInstanceType(decl, ref),
815
841
  mixinClassInstance: (decl) => this.mixinTypeContext && this.mixinTypeContext.classNode === decl
816
842
  ? { kind: "object", className: this.mixinTypeContext.className }
@@ -895,7 +921,11 @@ export class Lowerer {
895
921
  const recvDecl = recvDecls.find(ts.isImportClause) ?? recvDecls[0];
896
922
  if (recvDecl && ts.isVariableDeclaration(recvDecl) && recvDecl.initializer) {
897
923
  const spec = requireSpecOf(recvDecl.initializer);
898
- const dep = spec !== null ? resolveImport(this.program, recvDecl.getSourceFile(), spec) : null;
924
+ const dep = spec === null
925
+ ? null
926
+ : isRelativeSpecifier(spec)
927
+ ? resolveImport(this.program, recvDecl.getSourceFile(), spec)
928
+ : npmStaticDepSf7(this.program, recvDecl.getSourceFile(), spec);
899
929
  if (dep)
900
930
  symbol = this.cjsModuleExportSymbol(dep, ident.text);
901
931
  }
@@ -1092,12 +1122,14 @@ export class Lowerer {
1092
1122
  }
1093
1123
  /** True when `expr` is an identifier bound by a top-level
1094
1124
  * `const x = require("./local")` of a RELATIVE module — the CommonJS
1095
- * namespace binding — or by a DEFAULT import of a CommonJS JS module
1096
- * (`import d from "./lib.cjs"`: Node binds d to module.exports, the
1097
- * same value require answers). Member accesses on it resolve through
1098
- * the export table (property symbols → resolveValueSymbol); the bare
1099
- * value keeps the namespace-object fence, like ESM namespace imports
1100
- * of builtins. */
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. */
1101
1133
  cjsLocalModuleBindingOf(expr) {
1102
1134
  if (!ts.isIdentifier(expr))
1103
1135
  return false;
@@ -1115,8 +1147,12 @@ export class Lowerer {
1115
1147
  return false;
1116
1148
  }
1117
1149
  const spec = requireSpecOf(decl.initializer);
1118
- if (spec === null || !isRelativeSpecifier(spec))
1150
+ if (spec === null)
1119
1151
  return false;
1152
+ if (!isRelativeSpecifier(spec) &&
1153
+ npmStaticDepSf7(this.program, decl.getSourceFile(), spec) === null) {
1154
+ return false;
1155
+ }
1120
1156
  }
1121
1157
  // SINGLE-VALUE exporters (`module.exports = Countdown` / `= double` /
1122
1158
  // `= 42`): the requirer's binding IS the exported value, not a
@@ -1215,13 +1251,22 @@ export class Lowerer {
1215
1251
  /** The lowering of a CommonJS `require("./local")` occurrence: a call of
1216
1252
  * the required module's run-once %init at exactly this statement's
1217
1253
  * position — Node's inline evaluation, with the guard supplying the
1218
- * cache-hit behavior for every require after the first. Null when the
1219
- * specifier is not a relative program module (builtins load nothing;
1220
- * anything else kept its preflight fence). */
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). */
1221
1259
  requireInitStmt(spec, node) {
1222
- if (!isRelativeSpecifier(spec))
1223
- return null;
1224
- const dep = resolveImport(this.program, node.getSourceFile(), spec);
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);
1225
1270
  if (!dep || dep.fileName.endsWith(".json"))
1226
1271
  return null;
1227
1272
  const initName = this.initNameOf.get(dep);
@@ -1823,8 +1868,8 @@ export class Lowerer {
1823
1868
  throw new PoisonError();
1824
1869
  }
1825
1870
  // Would-be records with INDEX SIGNATURES (`Record<string, T>`,
1826
- // `{ [k: string]: T }`) get a message that points at Map<K, V> — the
1827
- // container that holds unbounded keys — instead of the generic
1871
+ // `{ [k: string]: T }`) get the index-signature fence (SC2006) naming
1872
+ // the supported key/value domain instead of the generic
1828
1873
  // supported-types recitation.
1829
1874
  if (widened.flags & (ts.TypeFlags.Object | ts.TypeFlags.Intersection) &&
1830
1875
  this.checker.getCallSignatures(widened).length === 0 &&
@@ -1904,6 +1949,77 @@ export class Lowerer {
1904
1949
  this.pushDiag(requiresDynamicTypeDiag(this.checker.typeToString(type), locOf(node)));
1905
1950
  throw new PoisonError();
1906
1951
  }
1952
+ // STANDARD-LIBRARY nominal provenance, decided once: interface/class
1953
+ // declarations in the lib's own files (Date, ArrayBuffer, WeakMap, the
1954
+ // iterator/constructor interfaces). Such types report the SC2020 story
1955
+ // below — the same one the index-signature-carrying lib types above
1956
+ // tell — rather than an overload/record claim no user can act on.
1957
+ const stdlibOwnSym = widened.getSymbol();
1958
+ const stdlibNominal = stdlibOwnSym !== undefined &&
1959
+ this.checker.declarationsOf(stdlibOwnSym).some((d) => (ts.isInterfaceDeclaration(d) || ts.isClassDeclaration(d)) &&
1960
+ this.isStdlibFile(d.getSourceFile()));
1961
+ // OVERLOADED call signatures (SC2007) — after the generic branch, so a
1962
+ // generic overload set keeps the monomorphization story: a value of a
1963
+ // multi-signature type has no single compiled signature to hold.
1964
+ if (!stdlibNominal && this.checker.getCallSignatures(widened).length > 1) {
1965
+ this.pushDiag(overloadedSignatureTypeDiag(this.checker.typeToString(type), locOf(node)));
1966
+ throw new PoisonError();
1967
+ }
1968
+ // INTERSECTIONS that resolved to no lowering (SC2008). The ones that
1969
+ // compile never get here: member intersections intern through the
1970
+ // record path, callable hybrids map to '%call' records, and pinned
1971
+ // mixin instantiations resolve by chain structure.
1972
+ if (widened.isIntersectionType()) {
1973
+ this.pushDiag(intersectionTypeDiag(this.checker.typeToString(type), locOf(node)));
1974
+ throw new PoisonError();
1975
+ }
1976
+ // SUPPORTED shapes over a component outside its slot (SC2009): the
1977
+ // Map/Set domains, array/tuple elements, union arms, function
1978
+ // parameters/returns. The container is not the blocker — name the
1979
+ // component instead of reciting the supported set. Checked BEFORE the
1980
+ // lib claim so Map/Set/Promise instantiation failures keep their
1981
+ // component story (describeComponentBlocker always answers for those
1982
+ // heads).
1983
+ {
1984
+ const detail = describeComponentBlocker(widened, this.typeCtx);
1985
+ if (detail !== null) {
1986
+ this.pushDiag(componentTypeDiag(this.checker.typeToString(type), detail, locOf(node)));
1987
+ throw new PoisonError();
1988
+ }
1989
+ }
1990
+ // STANDARD-LIBRARY nominal types with no lowering at all: the SC2020
1991
+ // story, naming the type — and for the families with a WHY, the same
1992
+ // pointed reason the identifier/constructor chokepoints teach.
1993
+ if (stdlibNominal) {
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 ?? ""]));
2012
+ throw new PoisonError();
2013
+ }
2014
+ // USER record shapes blocked by ONE member (SC2009's record arm):
2015
+ // name the member and its type.
2016
+ {
2017
+ const detail = describeRecordMemberBlocker(widened, this.typeCtx);
2018
+ if (detail !== null) {
2019
+ this.pushDiag(componentTypeDiag(this.checker.typeToString(type), detail, locOf(node)));
2020
+ throw new PoisonError();
2021
+ }
2022
+ }
1907
2023
  this.pushDiag(unsupportedTypeDiag(this.checker.typeToString(type), locOf(node)));
1908
2024
  throw new PoisonError();
1909
2025
  }
@@ -2051,6 +2167,17 @@ export class Lowerer {
2051
2167
  const sym = t.getSymbol();
2052
2168
  return (sym && this.typeParamBindings.get(sym)) ?? null;
2053
2169
  };
2170
+ /** The ts-level twin of typeParamResolver: the bound CHECKER type of a
2171
+ * type parameter in the current instantiation (typeParamTsBindings), for
2172
+ * the resolutions where mapType's widening already dropped what the body
2173
+ * needs (indexed accesses over literal-bound keys). Inert outside
2174
+ * call-keyed generic instantiation. */
2175
+ typeParamTsResolver = (t) => {
2176
+ if (!this.typeParamTsBindings || !(t.flags & ts.TypeFlags.TypeParameter))
2177
+ return null;
2178
+ const sym = t.getSymbol();
2179
+ return (sym && this.typeParamTsBindings.get(sym)) ?? null;
2180
+ };
2054
2181
  irTypeOf(node) {
2055
2182
  const t = this.typeOf(node);
2056
2183
  // A never-tainted JS type (neverTaintedJsType) maps — never rides as
@@ -2076,8 +2203,10 @@ export class Lowerer {
2076
2203
  }
2077
2204
  /** Exact-shape enforcement (SC2002). Records are monomorphic structs, so
2078
2205
  * everywhere a value flows into a typed slot (call arg, initializer,
2079
- * assignment, field, return) the shapes must MATCH — TS's structural width
2080
- * subtyping (`{a, b}` where `{a}` is expected) has no runtime coercion.
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).
2081
2210
  * Non-record mismatches are not reachable through tsc-clean programs; the
2082
2211
  * validator ICEs on them as the usual backstop. */
2083
2212
  requireExactShape(node, actual, expected) {
@@ -2136,7 +2265,13 @@ export class Lowerer {
2136
2265
  throw new PoisonError();
2137
2266
  }
2138
2267
  if (containsRecord(actual) || containsRecord(expected)) {
2139
- this.pushDiag(recordShapeMismatchDiag(this.fmt(expected), this.fmt(actual), locOf(node)));
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));
2140
2275
  throw new PoisonError();
2141
2276
  }
2142
2277
  // Everything else — a plain-kind mismatch like a string flowing into a
@@ -2634,10 +2769,23 @@ export class Lowerer {
2634
2769
  * recursively — NESTED width)
2635
2770
  * arr — array into array whose element pair lifts (per-element
2636
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
2637
2779
  * Null when the pair isn't in the relation — callers keep their fences. */
2638
2780
  widthLiftPlan(src, dst) {
2639
2781
  if (typeEquals(src, dst))
2640
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
+ }
2641
2789
  if (dst.kind === "union") {
2642
2790
  if (src.kind === "union") {
2643
2791
  return this.unionRetagMappable(src.unionId, dst.unionId) ? { how: "retag" } : null;
@@ -2667,6 +2815,32 @@ export class Lowerer {
2667
2815
  return null;
2668
2816
  return { how: "liftWrap", tag: candidates[0].tag, arm: candidates[0].arm };
2669
2817
  }
2818
+ // A UNION source into a slot that is ONE of its arms (a width copy
2819
+ // whose target field narrowed — the option-table choices shape:
2820
+ // `value: boolean | string` copying into a `value: string` slot the
2821
+ // checker approved): the CHECKED extraction — narrowedArmHelper,
2822
+ // exactly `x!`'s machinery — the proven arm's payload comes out, any
2823
+ // other arm throws the catchable TypeError (divergence 38's stance).
2824
+ if (src.kind === "union" && !isUnitType(dst) && dst.kind !== "void" && this.armTag(src.unionId, dst) >= 0) {
2825
+ return { how: "narrow" };
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
+ }
2670
2844
  if (dst.kind === "record" && src.kind === "record") {
2671
2845
  return this.recordWidthPlan(src.shapeId, dst.shapeId) !== null ? { how: "width" } : null;
2672
2846
  }
@@ -2786,6 +2960,32 @@ export class Lowerer {
2786
2960
  throw new Error("lowerer bug: planned clsWidth lift failed to intern");
2787
2961
  return { kind: "call", callee: helper, args: [value], type: dst, loc };
2788
2962
  }
2963
+ case "narrow": {
2964
+ if (value.type.kind !== "union")
2965
+ throw new Error("lowerer bug: narrow lift on a non-union");
2966
+ const helper = this.narrowedArmHelper(value.type.unionId, dst, loc);
2967
+ if (!helper)
2968
+ throw new Error("lowerer bug: planned narrow lift failed to intern");
2969
+ return { kind: "call", callee: helper, args: [value], type: dst, loc };
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
+ }
2789
2989
  default: {
2790
2990
  const _exhaustive = lift;
2791
2991
  void _exhaustive;
@@ -2803,9 +3003,11 @@ export class Lowerer {
2803
3003
  * optional-flavored field completes to its undefined arm (the
2804
3004
  * literal-completion rule). TUPLES width-coerce too, arity-exact (TS
2805
3005
  * permits no other tuple width): per-position lifts, never completion.
2806
- * Index-signature shapes keep the exactness fences here (the overflow
2807
- * CAPTURE helper owns their reshapes). Null when the shapes don't
2808
- * relate that way. */
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. */
2809
3011
  /** The pure planning half of recordWidthHelper — every target field's
2810
3012
  * lift, or null when the pair isn't width-coercible. Callers that must
2811
3013
  * validate a WHOLE plan before interning anything (the retag helper's
@@ -2813,7 +3015,13 @@ export class Lowerer {
2813
3015
  recordWidthPlan(fromId, toId) {
2814
3016
  const from = this.shapes.get(fromId);
2815
3017
  const to = this.shapes.get(toId);
2816
- if (!from || !to || from.indexValue || to.indexValue)
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)
2817
3025
  return null;
2818
3026
  // Tuple↔record pairs never relate; tuple↔tuple only arity-exact.
2819
3027
  if (!!from.tuple !== !!to.tuple)
@@ -2838,8 +3046,12 @@ export class Lowerer {
2838
3046
  // the absent-property read: the options-record call shape
2839
3047
  // against `{ plugins: unknown, ... }`). Never for tuples: a
2840
3048
  // completed position would change .length and JSON where Node
2841
- // keeps the source arity.
2842
- if (from.tuple)
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)
2843
3055
  return null;
2844
3056
  if (tf.type.kind === "dyn") {
2845
3057
  plan.set(tf.name, { absentDyn: true });
@@ -2865,6 +3077,92 @@ export class Lowerer {
2865
3077
  this.widthPlanning.delete(key);
2866
3078
  }
2867
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
+ }
2868
3166
  recordWidthHelper(fromId, toId, loc) {
2869
3167
  const from = this.shapes.get(fromId);
2870
3168
  const to = this.shapes.get(toId);
@@ -3503,8 +3801,14 @@ export class Lowerer {
3503
3801
  return this.boundaryExitSafe(dst);
3504
3802
  if (dst.kind === "dyn")
3505
3803
  return src.kind !== "dyn" && this.dynConvertible(src);
3506
- if (src.kind === "dyn")
3507
- return this.jsonSafe(dst);
3804
+ if (src.kind === "dyn") {
3805
+ // The checked-dynamic function boundary's OUT direction joins the
3806
+ // mechanical set: a dyn result landing in an adaptable func slot
3807
+ // takes dynCheck's per-target shim (coerceToExpected's funcOk rule
3808
+ // — the production/development function-choice ternary shape).
3809
+ return (this.jsonSafe(dst) ||
3810
+ (dst.kind === "func" && canAdaptDynFuncTo(dst, (id) => this.shapes.get(id), (id) => this.unions.get(id))));
3811
+ }
3508
3812
  if (dst.kind === "union") {
3509
3813
  if (src.kind === "union")
3510
3814
  return this.unionRetagMappable(src.unionId, dst.unionId);
@@ -3517,6 +3821,28 @@ export class Lowerer {
3517
3821
  }
3518
3822
  return false;
3519
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
+ }
3520
3846
  /** Interned `%fn.adapt.<n>(f)` — the GENERAL function-value adapter: a
3521
3847
  * `fromT` function value flowing into a `toT` slot whose pieces differ
3522
3848
  * only by coercibleValue conversions. The slot's callers pass toT's
@@ -3552,10 +3878,19 @@ export class Lowerer {
3552
3878
  strandParams = true;
3553
3879
  }
3554
3880
  let voidRet = null;
3881
+ let strandRet = false;
3555
3882
  if (toT.ret.kind !== "void" && !this.coercibleValue(fromT.ret, toT.ret)) {
3556
- if (fromT.ret.kind !== "void")
3557
- return null;
3558
- voidRet = toT.ret.kind === "dyn" ? "dyn" : toT.ret.kind === "jsval" ? "jsval" : "strand";
3883
+ if (fromT.ret.kind !== "void") {
3884
+ // A RESULT that cannot convert — the strandParams stance, result
3885
+ // side (the production/development function-choice ternary: the
3886
+ // untaken arm's result shape never lands in the slot's): the
3887
+ // assignment compiles, INVOKING the slot runs the function and
3888
+ // throws the stranded TypeError where its result would convert.
3889
+ strandRet = true;
3890
+ }
3891
+ else {
3892
+ voidRet = toT.ret.kind === "dyn" ? "dyn" : toT.ret.kind === "jsval" ? "jsval" : "strand";
3893
+ }
3559
3894
  }
3560
3895
  if (toT.ret.kind === "void" && fromT.ret.kind === "jsval")
3561
3896
  return null;
@@ -3623,6 +3958,12 @@ export class Lowerer {
3623
3958
  strandThrow(`a void result where the '${this.fmt(toT)}' slot promises '${this.fmt(toT.ret)}' (a thrower typed 'never' never reaches this; a genuinely void function has no result to hand over)`),
3624
3959
  ];
3625
3960
  }
3961
+ else if (strandRet) {
3962
+ body = [
3963
+ { kind: "exprStmt", expr: call, loc },
3964
+ strandThrow(`a '${this.fmt(fromT)}' function invoked through a '${this.fmt(toT)}' slot (the result cannot convert to '${this.fmt(toT.ret)}' — the checker's loose function compatibility admitted the assignment, but the call has no exact lowering)`),
3965
+ ];
3966
+ }
3626
3967
  else {
3627
3968
  const result = this.coerceToExpected(call, toT.ret);
3628
3969
  if (!typeEquals(result.type, toT.ret))
@@ -4646,6 +4987,25 @@ export class Lowerer {
4646
4987
  e = { kind: "call", callee: helper, args: [e], type: expected, loc: e.loc };
4647
4988
  }
4648
4989
  }
4990
+ // A JS FUNC value outside the island marshal set flowing into a
4991
+ // jsval slot (`withPlugins(getSupportInfoWithoutPlugins, 0)` — a
4992
+ // wrapper built at module init around a function the run may never
4993
+ // call): the crossing defers to a call-time fence closure instead of
4994
+ // stopping the statement — jsvalIn's deferral, the implicit-coercion
4995
+ // spelling.
4996
+ if (expected.kind === "jsval" && e.type.kind === "func" && !typeEquals(e.type, expected)) {
4997
+ const diagsBefore = this.diags.length;
4998
+ try {
4999
+ this.requireExactShape(node, e.type, expected);
5000
+ }
5001
+ catch (err) {
5002
+ const fence = islandFuncValueFence(this, err, diagsBefore, node);
5003
+ if (fence)
5004
+ return fence;
5005
+ throw err;
5006
+ }
5007
+ return e;
5008
+ }
4649
5009
  this.requireExactShape(node, e.type, expected);
4650
5010
  return e;
4651
5011
  }
@@ -4732,6 +5092,55 @@ export class Lowerer {
4732
5092
  return this.coerceInto(node, this.lowerArrayLiteral(x, expected), expected);
4733
5093
  }
4734
5094
  }
5095
+ // An OBJECT LITERAL against a checked-dynamic slot in a JS file (the
5096
+ // getSupportInfo options argument — a dyn-ABI param): the value's
5097
+ // world IS the DOM — build the DOM literal directly, before the
5098
+ // island gate could claim the checker's `any` context (an island
5099
+ // build could never land in the slot: no engine→DOM crossing).
5100
+ if (expected?.kind === "dyn") {
5101
+ let x = node;
5102
+ while (ts.isParenthesizedExpression(x))
5103
+ x = x.expression;
5104
+ if (ts.isObjectLiteralExpression(x) && isJsSourceFile(x.getSourceFile())) {
5105
+ return lowerDynObjectLiteral(this, x);
5106
+ }
5107
+ }
5108
+ // An ARRAY LITERAL against a UNION slot whose own type has no static
5109
+ // home (the JS dyn fallback — the checker gave no usable context):
5110
+ // when the union has exactly ONE array-family arm — an array, or an
5111
+ // arity-matching tuple (the option-table `default: [{ value: [] }]`
5112
+ // shape) — build AS that arm and wrap; the IR-directed twin of
5113
+ // lowerArrayLiteral's contextual-union rule.
5114
+ if (expected?.kind === "union") {
5115
+ let x = node;
5116
+ while (ts.isParenthesizedExpression(x))
5117
+ x = x.expression;
5118
+ if (ts.isArrayLiteralExpression(x)) {
5119
+ const own = this.mapTypeOf(this.checker.getContextualType(x) ?? this.typeOf(x));
5120
+ // Elements beyond bare null/undefined literals can never live in
5121
+ // a unit-only-element array — a checker type that degraded to one
5122
+ // (`[]`-flavored inference over a populated literal) carries no
5123
+ // element information.
5124
+ const nonUnitElems = x.elements.some((el) => !ts.isOmittedExpression(el) &&
5125
+ el.kind !== ts.SyntaxKind.NullKeyword &&
5126
+ !(ts.isIdentifier(el) && el.text === "undefined"));
5127
+ if (own === null || own.kind === "dyn" || own.kind === "jsval" ||
5128
+ (own.kind === "array" && nonUnitElems && this.unitOnlyElem(own.elem)) ||
5129
+ this.widthLiftPlan(own, expected) === null) {
5130
+ const def = this.unions.get(expected.unionId);
5131
+ const arms = (def?.arms ?? []).filter((a) => (a.kind === "array" && !(nonUnitElems && this.unitOnlyElem(a.elem))) ||
5132
+ (a.kind === "record" &&
5133
+ !!this.shapes.get(a.shapeId)?.tuple &&
5134
+ this.shapes.get(a.shapeId).fields.length === x.elements.length &&
5135
+ !x.elements.some(ts.isSpreadElement)));
5136
+ if (arms.length === 1) {
5137
+ const arm = arms[0];
5138
+ const built = this.lowerArrayLiteral(x, arm);
5139
+ return this.coerceInto(node, built, expected);
5140
+ }
5141
+ }
5142
+ }
5143
+ }
4735
5144
  const e = this.lowerExpr(node);
4736
5145
  return expected ? this.coerceInto(node, e, expected) : e;
4737
5146
  }
@@ -4999,8 +5408,8 @@ export class Lowerer {
4999
5408
  lowerGenericFnValue(ref, info) {
5000
5409
  return lowerGenericFnValue(this, ref, info);
5001
5410
  }
5002
- inferTypeParamBindings(expr, info, rsig) {
5003
- return inferTypeParamBindings(this, expr, info, rsig);
5411
+ inferTypeParamBindings(expr, info, rsig, tsBindings) {
5412
+ return inferTypeParamBindings(this, expr, info, rsig, tsBindings);
5004
5413
  }
5005
5414
  lowerGenericInstance(info, inst) {
5006
5415
  return lowerGenericInstance(this, info, inst);
@@ -6332,6 +6741,11 @@ export class Lowerer {
6332
6741
  const streamServed = lowerStreamModuleCall(this, call, bi, locOf(access));
6333
6742
  if (streamServed)
6334
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;
6335
6749
  const builtinFn = builtinModuleFnOf(this, bi.module, bi.member);
6336
6750
  if (!builtinFn) {
6337
6751
  this.noLowering(`${bi.module}.${bi.member}`, call, builtinFenceHintOf(bi.module, bi.member), this.checker.getSymbolAtLocation(access.name));
@@ -6362,6 +6776,11 @@ export class Lowerer {
6362
6776
  const bi = this.builtinMemberOf(expr);
6363
6777
  if (!bi)
6364
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
+ }
6365
6784
  const c = builtinModuleConstOf(this, bi.module, bi.member);
6366
6785
  if (c !== undefined)
6367
6786
  return builtinConstLit(c, loc);
@@ -6377,6 +6796,9 @@ export class Lowerer {
6377
6796
  lowerBuiltinModuleCall(expr, bi, fn, loc) {
6378
6797
  return lowerBuiltinModuleCall(this, expr, bi, fn, loc);
6379
6798
  }
6799
+ lowerFsToUnixTimestampCall(expr, bi, loc) {
6800
+ return lowerFsToUnixTimestampCall(this, expr, bi, loc);
6801
+ }
6380
6802
  lowerChildArgsArg(node, loc) {
6381
6803
  return lowerChildArgsArg(this, node, loc);
6382
6804
  }