@scriptc/compiler 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +258 -64
  2. package/dist/backend/c/async.d.ts +30 -0
  3. package/dist/backend/c/async.js +224 -0
  4. package/dist/backend/c/async.js.map +1 -1
  5. package/dist/backend/c/c-emitter.d.ts +13 -0
  6. package/dist/backend/c/c-emitter.js +28 -9
  7. package/dist/backend/c/c-emitter.js.map +1 -1
  8. package/dist/backend/c/exprs.d.ts +8 -1
  9. package/dist/backend/c/exprs.js +445 -60
  10. package/dist/backend/c/exprs.js.map +1 -1
  11. package/dist/backend/c/shapes.js +15 -13
  12. package/dist/backend/c/shapes.js.map +1 -1
  13. package/dist/backend/c/types.d.ts +4 -0
  14. package/dist/backend/c/types.js +20 -1
  15. package/dist/backend/c/types.js.map +1 -1
  16. package/dist/backend/c/types.test.js +8 -1
  17. package/dist/backend/c/types.test.js.map +1 -1
  18. package/dist/backend/c/walkers.js +32 -11
  19. package/dist/backend/c/walkers.js.map +1 -1
  20. package/dist/backend/json-literal.d.ts +7 -0
  21. package/dist/backend/json-literal.js +17 -0
  22. package/dist/backend/json-literal.js.map +1 -0
  23. package/dist/backend/json-literal.test.d.ts +1 -0
  24. package/dist/backend/json-literal.test.js +17 -0
  25. package/dist/backend/json-literal.test.js.map +1 -0
  26. package/dist/backend/link-plan.d.ts +2 -1
  27. package/dist/backend/link-plan.js +6 -1
  28. package/dist/backend/link-plan.js.map +1 -1
  29. package/dist/backend/llvm/classes.js +8 -7
  30. package/dist/backend/llvm/classes.js.map +1 -1
  31. package/dist/backend/llvm/common.d.ts +4 -0
  32. package/dist/backend/llvm/common.js +6 -0
  33. package/dist/backend/llvm/common.js.map +1 -1
  34. package/dist/backend/llvm/common.test.d.ts +1 -0
  35. package/dist/backend/llvm/common.test.js +9 -0
  36. package/dist/backend/llvm/common.test.js.map +1 -0
  37. package/dist/backend/llvm/dyn.d.ts +4 -0
  38. package/dist/backend/llvm/dyn.js +24 -13
  39. package/dist/backend/llvm/dyn.js.map +1 -1
  40. package/dist/backend/llvm/emitter.js +54 -12
  41. package/dist/backend/llvm/emitter.js.map +1 -1
  42. package/dist/backend/llvm/expr-bytes.d.ts +1 -1
  43. package/dist/backend/llvm/expr-bytes.js +8 -8
  44. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  45. package/dist/backend/llvm/expr-callbacks.d.ts +9 -0
  46. package/dist/backend/llvm/expr-callbacks.js +125 -0
  47. package/dist/backend/llvm/expr-callbacks.js.map +1 -1
  48. package/dist/backend/llvm/expr-context.d.ts +18 -2
  49. package/dist/backend/llvm/expr-dispatch.js +1 -0
  50. package/dist/backend/llvm/expr-dispatch.js.map +1 -1
  51. package/dist/backend/llvm/expr-dynamic.js +9 -0
  52. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  53. package/dist/backend/llvm/expr-primitives.d.ts +1 -1
  54. package/dist/backend/llvm/expr-primitives.js +38 -9
  55. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  56. package/dist/backend/llvm/expr-primitives.test.d.ts +1 -0
  57. package/dist/backend/llvm/expr-primitives.test.js +38 -0
  58. package/dist/backend/llvm/expr-primitives.test.js.map +1 -0
  59. package/dist/backend/llvm/expr-records.js +3 -3
  60. package/dist/backend/llvm/expr-records.js.map +1 -1
  61. package/dist/backend/llvm/expr-stream-bridges.js +2 -1
  62. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  63. package/dist/backend/llvm/expr-stream-callbacks.d.ts +6 -0
  64. package/dist/backend/llvm/expr-stream-callbacks.js +122 -0
  65. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  66. package/dist/backend/llvm/lib-dispatch.js +22 -0
  67. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  68. package/dist/backend/llvm/lib-filesystem.js +68 -10
  69. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  70. package/dist/backend/llvm/lib-network.js +18 -2
  71. package/dist/backend/llvm/lib-network.js.map +1 -1
  72. package/dist/backend/llvm/lib-process.js +206 -11
  73. package/dist/backend/llvm/lib-process.js.map +1 -1
  74. package/dist/backend/llvm/lib-shared.js +82 -0
  75. package/dist/backend/llvm/lib-shared.js.map +1 -1
  76. package/dist/backend/llvm/lib-stream.js +23 -0
  77. package/dist/backend/llvm/lib-stream.js.map +1 -1
  78. package/dist/backend/llvm/shapes.js +10 -8
  79. package/dist/backend/llvm/shapes.js.map +1 -1
  80. package/dist/backend/llvm/walkers.js +7 -5
  81. package/dist/backend/llvm/walkers.js.map +1 -1
  82. package/dist/backend/native-link-info.d.ts +2 -1
  83. package/dist/backend/native-link-info.js +4 -0
  84. package/dist/backend/native-link-info.js.map +1 -1
  85. package/dist/backend/native-link-info.test.js +24 -1
  86. package/dist/backend/native-link-info.test.js.map +1 -1
  87. package/dist/backend/native-toolchain.d.ts +11 -6
  88. package/dist/backend/native-toolchain.js +30 -13
  89. package/dist/backend/native-toolchain.js.map +1 -1
  90. package/dist/backend/native-toolchain.test.js +36 -1
  91. package/dist/backend/native-toolchain.test.js.map +1 -1
  92. package/dist/backend/runtime-pack-targets.test.js +1 -1
  93. package/dist/backend/runtime-pack-targets.test.js.map +1 -1
  94. package/dist/backend/runtime-pack.test.js +29 -10
  95. package/dist/backend/runtime-pack.test.js.map +1 -1
  96. package/dist/backend/targets.d.ts +9 -0
  97. package/dist/backend/targets.js +22 -0
  98. package/dist/backend/targets.js.map +1 -1
  99. package/dist/backend/targets.test.js +13 -1
  100. package/dist/backend/targets.test.js.map +1 -1
  101. package/dist/coverage/surface-manifest.js +9 -0
  102. package/dist/coverage/surface-manifest.js.map +1 -1
  103. package/dist/diagnostics/diagnostic.js +4 -4
  104. package/dist/diagnostics/diagnostic.js.map +1 -1
  105. package/dist/executable/executable-cache.d.ts +3 -0
  106. package/dist/executable/executable-cache.js +4 -0
  107. package/dist/executable/executable-cache.js.map +1 -1
  108. package/dist/executable/executable-cache.test.js +1 -0
  109. package/dist/executable/executable-cache.test.js.map +1 -1
  110. package/dist/frontend/fork-target.d.ts +17 -0
  111. package/dist/frontend/fork-target.js +256 -0
  112. package/dist/frontend/fork-target.js.map +1 -0
  113. package/dist/frontend/lowering/abstract-equality.d.ts +6 -0
  114. package/dist/frontend/lowering/abstract-equality.js +250 -0
  115. package/dist/frontend/lowering/abstract-equality.js.map +1 -0
  116. package/dist/frontend/lowering/containers/bytes.d.ts +0 -4
  117. package/dist/frontend/lowering/containers/bytes.js +112 -28
  118. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  119. package/dist/frontend/lowering/lower-assert.js +87 -12
  120. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  121. package/dist/frontend/lowering/lower-builtins.d.ts +72 -44
  122. package/dist/frontend/lowering/lower-builtins.js +1323 -165
  123. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  124. package/dist/frontend/lowering/lower-calls.d.ts +37 -27
  125. package/dist/frontend/lowering/lower-calls.js +682 -132
  126. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  127. package/dist/frontend/lowering/lower-classes.js +39 -8
  128. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  129. package/dist/frontend/lowering/lower-containers.js +162 -8
  130. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  131. package/dist/frontend/lowering/lower-event-emitter.js +212 -21
  132. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
  133. package/dist/frontend/lowering/lower-exprs.js +238 -87
  134. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  135. package/dist/frontend/lowering/lower-inspect.d.ts +4 -0
  136. package/dist/frontend/lowering/lower-inspect.js +8 -1
  137. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  138. package/dist/frontend/lowering/lower-island.d.ts +6 -3
  139. package/dist/frontend/lowering/lower-island.js +165 -6
  140. package/dist/frontend/lowering/lower-island.js.map +1 -1
  141. package/dist/frontend/lowering/lower-modules.d.ts +6 -0
  142. package/dist/frontend/lowering/lower-modules.js +192 -38
  143. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  144. package/dist/frontend/lowering/lower-namespaces.js +7 -0
  145. package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
  146. package/dist/frontend/lowering/lower-server.d.ts +1 -1
  147. package/dist/frontend/lowering/lower-server.js +130 -27
  148. package/dist/frontend/lowering/lower-server.js.map +1 -1
  149. package/dist/frontend/lowering/lower-stmts.d.ts +5 -4
  150. package/dist/frontend/lowering/lower-stmts.js +141 -21
  151. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  152. package/dist/frontend/lowering/lower-stream.d.ts +3 -0
  153. package/dist/frontend/lowering/lower-stream.js +7 -0
  154. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  155. package/dist/frontend/lowering/lowerer.d.ts +90 -13
  156. package/dist/frontend/lowering/lowerer.js +416 -76
  157. package/dist/frontend/lowering/lowerer.js.map +1 -1
  158. package/dist/frontend/lowering/surfaces.d.ts +31 -3
  159. package/dist/frontend/lowering/surfaces.js +173 -90
  160. package/dist/frontend/lowering/surfaces.js.map +1 -1
  161. package/dist/frontend/npm-static-declarations.d.ts +4 -0
  162. package/dist/frontend/npm-static-declarations.js +83 -14
  163. package/dist/frontend/npm-static-declarations.js.map +1 -1
  164. package/dist/frontend/npm-static-declarations.test.js +33 -2
  165. package/dist/frontend/npm-static-declarations.test.js.map +1 -1
  166. package/dist/frontend/npm-static.js +6 -5
  167. package/dist/frontend/npm-static.js.map +1 -1
  168. package/dist/frontend/npm.d.ts +15 -3
  169. package/dist/frontend/npm.js +80 -8
  170. package/dist/frontend/npm.js.map +1 -1
  171. package/dist/frontend/npm.test.js +76 -9
  172. package/dist/frontend/npm.test.js.map +1 -1
  173. package/dist/frontend/program.js +110 -12
  174. package/dist/frontend/program.js.map +1 -1
  175. package/dist/frontend/resolve.d.ts +28 -7
  176. package/dist/frontend/resolve.js +90 -26
  177. package/dist/frontend/resolve.js.map +1 -1
  178. package/dist/frontend/resolve.test.js +21 -1
  179. package/dist/frontend/resolve.test.js.map +1 -1
  180. package/dist/frontend/type-mapper.d.ts +5 -0
  181. package/dist/frontend/type-mapper.js +115 -33
  182. package/dist/frontend/type-mapper.js.map +1 -1
  183. package/dist/index.d.ts +5 -0
  184. package/dist/index.js +30 -3
  185. package/dist/index.js.map +1 -1
  186. package/dist/ir/analysis.js +1 -0
  187. package/dist/ir/analysis.js.map +1 -1
  188. package/dist/ir/ir.d.ts +155 -66
  189. package/dist/ir/ir.js +143 -6
  190. package/dist/ir/ir.js.map +1 -1
  191. package/dist/ir/ir.test.js +14 -1
  192. package/dist/ir/ir.test.js.map +1 -1
  193. package/dist/ir/serialize.d.ts +1 -1
  194. package/dist/ir/serialize.js +1 -1
  195. package/dist/ir/serialize.js.map +1 -1
  196. package/dist/ir/validate.js +242 -18
  197. package/dist/ir/validate.js.map +1 -1
  198. package/dist/library/int-infer.test.js +4 -4
  199. package/dist/library/int-infer.test.js.map +1 -1
  200. package/dist/library/library-cache.d.ts +1 -0
  201. package/dist/library/library-cache.js +1 -0
  202. package/dist/library/library-cache.js.map +1 -1
  203. package/dist/library/library-cache.test.js +18 -5
  204. package/dist/library/library-cache.test.js.map +1 -1
  205. package/package.json +17 -17
  206. package/surface-manifest.json +163 -54
@@ -9,7 +9,7 @@ import * as ts from "../ts7/adapter.js";
9
9
  import { dirname, posix } from "node:path";
10
10
  import { pathToFileURL } from "node:url";
11
11
  import { wasiGuestPath } from "../../wasi-paths.js";
12
- import { BOOL, CAUGHT, DYN, DYN_HANDLE_KINDS, F64, JSVAL, NULL_T, REF_TRUTHY_KINDS, REGEX, RUNTIME_ERROR_CLASSES, SEARCH_PARAMS_T, STRING, UNDEFINED_T, VOID, arrayOf, canAdaptDynFuncTo, canBoxFuncIntoDyn, funcOf, isDynTypedRefType, isJsonSafeType, isSupportedArrayElem, isUnitType, jsOpResultKind, shapeHasAccessorSlots, typeEquals, typeKey, unionFuncSetArmsOk } from "../../ir/ir.js";
12
+ import { BIGINT_T, BOOL, CAUGHT, DYN, DYN_HANDLE_KINDS, F64, JSVAL, NULL_T, REF_TRUTHY_KINDS, REGEX, RUNTIME_ERROR_CLASSES, SEARCH_PARAMS_T, STRING, UNDEFINED_T, VOID, arrayOf, canAdaptDynFuncTo, canBoxFuncIntoDyn, funcOf, isDynTypedRefType, isJsonSafeType, isSupportedArrayElem, isUnitType, jsOpResultKind, shapeHasAccessorSlots, typeEquals, typeKey, unionFuncSetArmsOk } from "../../ir/ir.js";
13
13
  import { cjsClassExprWholeExportOf, cjsExportAssignmentOf, cjsExportDiscardReason, isCjsExportTableLiteral, isCjsJsFile, isJsSourceFile, isModuleExportsAccess, isNodeEsmFile, locOf } from "../program.js";
14
14
  import { ARRAY_METHODS, builtinConstLit, builtinFenceHintOf, builtinModuleConstOf, builtinModulesArrayLit, builtinModuleFnOf, ISLAND_SURFACE, isChildSurfaceMember, MAP_METHODS, NARROW_FIRST, SET_METHODS, STR_METHODS, UNSUPPORTED_EXPR, sideEffectFreeOptionValue, stdlibGlobalNameOf } from "./surfaces.js";
15
15
  import { blockedBindingUseDiag, requiresDynamicPackageDiag, unsupportedDiag } from "../../diagnostics/diagnostic.js";
@@ -23,7 +23,7 @@ import { ambientNsRootOf, ambientUndefReadType, ambientUndefVarRootOf, ambientUn
23
23
  import { expandoMemberRead, expandoWritableTarget } from "./lower-expando.js";
24
24
  import { lowerSocketInstanceOf, lowerTlsRootCertificates } from "./lower-server.js";
25
25
  import { findGenericMethodOn, lowerStaticFieldRead } from "./lower-classes.js";
26
- import { bindingNeverReassigned, implicitMonoFile, lowerTaggedTemplate, nullishGenericBindingUnitOf, objLitGenericFnInfoOf, objLitGenericFnNodeOf, requireObjLitGenericReceiver } from "./lower-calls.js";
26
+ import { bindingNeverReassigned, funcTypeFromParamShapes, implicitMonoFile, lowerTaggedTemplate, nullishGenericBindingUnitOf, objLitGenericFnInfoOf, objLitGenericFnNodeOf, requireObjLitGenericReceiver } from "./lower-calls.js";
27
27
  import { mixinFnOfCallee } from "./lower-mixins.js";
28
28
  import { isConstAssertionTypeNode, isGenericCallableMemberType, isParseArgsDynTypeName, underConstAssertion, unitOnlyUnion } from "../type-mapper.js";
29
29
  import { lowerYield } from "./lower-generators.js";
@@ -34,6 +34,7 @@ import { hasOptionalChainGuard, isOptionalChainTail, isRequireMainFilename } fro
34
34
  import { conditionalSpreadOf, foldedStringKeyOf } from "./expressions/object-literals.js";
35
35
  import { tryLowerExpression } from "./expressions/try-lower-expression.js";
36
36
  import { fenceNodeModuleMutation, isNodeModuleValue, lowerNodeModuleIdentifier, lowerNodeModuleProperty, lowerRequireCacheElement, lowerRequireCacheHas, lowerRequireMainProperty } from "./lower-node-module.js";
37
+ import { lowerAbstractEquality } from "./abstract-equality.js";
37
38
  /** A template piece's RAW text (String.raw's contract: escapes stay
38
39
  * characters). 7's client AST ships no rawText at runtime (the typing
39
40
  * declares it; the serialized node data omits it), so the raw span comes
@@ -143,6 +144,16 @@ function lowerExprInner(lowerer, expr) {
143
144
  }
144
145
  return { kind: "numLit", value, type: F64, loc };
145
146
  }
147
+ if (ts.isBigIntLiteral(expr)) {
148
+ const spelling = expr.getText().replace(/_/g, "").replace(/n$/i, "");
149
+ return {
150
+ kind: "libCall",
151
+ fn: "bigint.parse",
152
+ args: [{ kind: "strLit", value: spelling, type: STRING, loc }],
153
+ type: BIGINT_T,
154
+ loc,
155
+ };
156
+ }
146
157
  if (expr.kind === ts.SyntaxKind.TrueKeyword) {
147
158
  return { kind: "boolLit", value: true, type: BOOL, loc };
148
159
  }
@@ -583,11 +594,12 @@ function lowerExprInner(lowerer, expr) {
583
594
  operand = operand.value;
584
595
  }
585
596
  const FOLD = {
586
- f64: "number", string: "string", bool: "boolean", func: "function",
597
+ f64: "number", bigint: "bigint", string: "string", bool: "boolean", func: "function",
587
598
  array: "object", object: "object", record: "object",
588
599
  symbol: "symbol",
589
600
  map: "object", set: "object", promise: "object", bytes: "object",
590
601
  regexp: "object", generator: "object", classval: "function",
602
+ moduleNs: "object",
591
603
  undefinedT: "undefined", nullT: "object",
592
604
  };
593
605
  const folded = FOLD[operand.type.kind];
@@ -639,13 +651,22 @@ function lowerExprInner(lowerer, expr) {
639
651
  if (expr.text === "arguments" && lowerer.ctx.argumentsLocal) {
640
652
  return { kind: "varRef", localId: lowerer.ctx.argumentsLocal.id, type: DYN, loc };
641
653
  }
642
- // A `const x = promisify(execFile)` binding as a VALUE: the
643
- // promisified function never exists at runtime (its calls lower to
644
- // the interned async-exec helper) — call it directly.
654
+ // A compiler-projected adapter as a VALUE: the adapter has no
655
+ // runtime function object (its calls rewrite directly) — call it
656
+ // through its immutable binding instead.
645
657
  {
646
658
  const sym = lowerer.resolveValueSymbol(expr);
647
- if (sym && lowerer.promisifiedExecFile.has(sym)) {
648
- lowerer.unsupported("SC1090", expr, `a promisified execFile as a value (call '${expr.text}' directly)`);
659
+ const projection = sym ? lowerer.staticCallables.get(sym) : undefined;
660
+ if (projection?.kind === "promisified-exec-file" || projection?.kind === "promisified-builtin") {
661
+ lowerer.unsupported("SC1090", expr, `a promisified builtin as a value (call '${expr.text}' directly)`);
662
+ }
663
+ if (projection?.kind === "builtin-function") {
664
+ if (!isJsSourceFile(expr.getSourceFile())) {
665
+ const callable = lowerer.lowerBuiltinCallableValue(projection, loc);
666
+ if (callable)
667
+ return callable;
668
+ }
669
+ lowerer.unsupported("SC1090", expr, `a builtin function alias as an escaping value (call '${expr.text}' directly)`);
649
670
  }
650
671
  }
651
672
  // Union-typed bindings read through tsc's control-flow narrowing:
@@ -799,17 +820,12 @@ function lowerExprInner(lowerer, expr) {
799
820
  if (sig && lowerer.isTopLevelFnSymbol(expr)) {
800
821
  // A declared function used as a value: a zero-capture closure. The
801
822
  // backend interns one per function so `f === f` holds (JS identity).
802
- // The value's type is the completed ABI signature — exact-arity, so
803
- // optional/default/rest declarations pass the value fence first.
823
+ // The value's type is the completed ABI signature; optional/default
824
+ // slots and typed rest arrays pass the value fence first.
804
825
  lowerer.noteEdge(sig.name);
805
826
  // dynRest slots stay out of the VALUE type's param list (fn.length
806
827
  // semantics); the rest marker carries the trailing dyn-array ABI.
807
- const funcType = {
808
- kind: "func",
809
- params: sig.params.filter((p) => p.mode !== "dynRest").map((p) => p.type),
810
- ret: sig.returnType,
811
- ...(sig.params.some((p) => p.mode === "dynRest") ? { rest: true } : {}),
812
- };
828
+ const funcType = funcTypeFromParamShapes(sig.params, sig.returnType);
813
829
  lowerer.requireExactArityValue(expr, expr, sig.params, funcType);
814
830
  return { kind: "closure", fnName: sig.name, captures: [], type: funcType, loc };
815
831
  }
@@ -869,6 +885,11 @@ function lowerExprInner(lowerer, expr) {
869
885
  if (isJsSourceFile(expr.getSourceFile())) {
870
886
  return { kind: "strLit", value: `[builtin ${bi.module}.${bi.member}]`, type: STRING, loc };
871
887
  }
888
+ {
889
+ const callable = lowerer.lowerBuiltinCallableValue(bi, loc);
890
+ if (callable)
891
+ return callable;
892
+ }
872
893
  if (builtinModuleFnOf(lowerer, bi.module, bi.member)) {
873
894
  lowerer.unsupported("SC1090", expr, `library functions as values (call '${expr.text}' directly)`);
874
895
  }
@@ -879,7 +900,12 @@ function lowerExprInner(lowerer, expr) {
879
900
  // the namespace object has no representation — members lower at
880
901
  // their access sites only. The CommonJS namespace binding
881
902
  // (`const lib = require("./lib.js")`) gets the same fence.
882
- if (lowerer.builtinNamespaceModuleOf(expr) !== null || lowerer.cjsLocalModuleBindingOf(expr)) {
903
+ const builtinNamespace = lowerer.builtinNamespaceModuleOf(expr);
904
+ if (builtinNamespace !== null) {
905
+ const type = { kind: "moduleNs", moduleId: `builtin:${builtinNamespace}` };
906
+ return { kind: "moduleNsRef", moduleId: type.moduleId, type, loc };
907
+ }
908
+ if (lowerer.cjsLocalModuleBindingOf(expr)) {
883
909
  lowerer.unsupported("SC1090", expr, `module namespace objects as values (access '${expr.text}' members directly)`);
884
910
  }
885
911
  if (lowerer.islandGlobalFnOf(expr)) {
@@ -931,11 +957,14 @@ function lowerExprInner(lowerer, expr) {
931
957
  // type-mapper.ts pins the one concrete signature `(value: string) =>
932
958
  // primitive`; direct calls `String(x)` never reach here — the call
933
959
  // lowering intercepts them with the wider static coercions).
934
- // JavaScript sources keep the identity-token path below.
960
+ const jsPrimitiveCtorSelector = isJsSourceFile(expr.getSourceFile()) &&
961
+ expr.parent !== undefined &&
962
+ ts.isArrowFunction(expr.parent) &&
963
+ expr.parent.body === expr;
935
964
  if ((expr.text === "String" || expr.text === "Number" || expr.text === "Boolean") &&
936
- !isJsSourceFile(expr.getSourceFile()) &&
965
+ (!isJsSourceFile(expr.getSourceFile()) || jsPrimitiveCtorSelector) &&
937
966
  lowerer.isStdlibSymbol(lowerer.checker.getSymbolAtLocation(expr))) {
938
- return primitiveCtorClosure(lowerer, expr.text, loc);
967
+ return primitiveCtorClosure(lowerer, expr.text, loc, jsPrimitiveCtorSelector);
939
968
  }
940
969
  // The lib fence's IDENTIFIER chokepoint: the real standard library
941
970
  // resolves names the old minimal ambient world never declared
@@ -960,7 +989,6 @@ function lowerExprInner(lowerer, expr) {
960
989
  // The families with a WHY: each hint states what makes the
961
990
  // surface genuinely non-static (or what to use instead).
962
991
  const globalHints = {
963
- BigInt: "arbitrary-precision integers have no static representation — f64 is the one number type (Number.MAX_SAFE_INTEGER bounds exact integers)",
964
992
  Proxy: "property-access metaprogramming has no static lowering (every property read must resolve at compile time)",
965
993
  Reflect: "reflective property access has no static lowering — read and call members directly",
966
994
  Intl: "locale- and ICU-backed behavior lives outside the static runtime (the localeCompare stance: code-unit order, no collation/locale data) — what lowers: the composed new Intl.NumberFormat(\"en-US\").format(x) and x.toLocaleString(\"en-US\") with default options",
@@ -1072,6 +1100,15 @@ function lowerExprInner(lowerer, expr) {
1072
1100
  // representation (ambient namespaces compile to Node's
1073
1101
  // ReferenceError instead — the object never exists at runtime).
1074
1102
  {
1103
+ const moduleNs = lowerer.mapTypeOf(lowerer.typeOf(expr));
1104
+ if (moduleNs?.kind === "moduleNs") {
1105
+ return { kind: "moduleNsRef", moduleId: moduleNs.moduleId, type: moduleNs, loc };
1106
+ }
1107
+ const builtinNs = lowerer.builtinNamespaceModuleOf(expr);
1108
+ if (builtinNs !== null) {
1109
+ const type = { kind: "moduleNs", moduleId: `builtin:${builtinNs}` };
1110
+ return { kind: "moduleNsRef", moduleId: type.moduleId, type, loc };
1111
+ }
1075
1112
  const ns = lowerNsIdentifierValue(lowerer, expr);
1076
1113
  if (ns)
1077
1114
  return ns;
@@ -2957,6 +2994,9 @@ export function ensureBool(lowerer, e, node) {
2957
2994
  if (e.type.kind === "f64" || e.type.kind === "string") {
2958
2995
  return { kind: "toBool", operand: e, type: BOOL, loc: e.loc };
2959
2996
  }
2997
+ if (e.type.kind === "bigint") {
2998
+ return { kind: "libCall", fn: "bigint.truthy", args: [e], type: BOOL, loc: e.loc };
2999
+ }
2960
3000
  if (e.type.kind === "dyn") {
2961
3001
  // ToBoolean over the checked-dynamic tree (`if (pkg)` on a JSON.parse result): every
2962
3002
  // dyn kind has a JS-exact answer — the truthy dynTest reads the kind
@@ -3072,10 +3112,10 @@ export function lowerIntrinsicProperty(lowerer, expr) {
3072
3112
  const receiver = lowerer.lowerExpr(expr.expression);
3073
3113
  return { kind: "libCall", fn: "child.killed", args: [receiver], type: BOOL, loc };
3074
3114
  }
3075
- if (name === "on" || name === "kill" || name === "unref") {
3115
+ if (name === "on" || name === "once" || name === "kill" || name === "unref") {
3076
3116
  lowerer.unsupported("SC1090", expr, `child methods as values (call '${name}' directly)`);
3077
3117
  }
3078
- lowerer.noLowering(`ChildProcess.${name}`, expr, "on(\"exit\" | \"error\", cb), pid, exitCode, killed, kill(signal?), and unref() are the supported ChildProcess members", lowerer.checker.getSymbolAtLocation(expr.name));
3118
+ lowerer.noLowering(`ChildProcess.${name}`, expr, "on/once(\"exit\" | \"close\" | \"error\", cb), pid, exitCode, killed, kill(signal?), and unref() are the supported ChildProcess members", lowerer.checker.getSymbolAtLocation(expr.name));
3079
3119
  }
3080
3120
  if (kind === "spawnRes") {
3081
3121
  // The spawnSync-result reads. status is the interned `number | null`
@@ -3125,7 +3165,7 @@ export function lowerIntrinsicProperty(lowerer, expr) {
3125
3165
  if (name === "isFile" || name === "isDirectory") {
3126
3166
  lowerer.unsupported("SC1090", expr, `Stats methods as values (call '${name}' directly)`);
3127
3167
  }
3128
- lowerer.noLowering(`Stats.${name}`, expr, "isFile(), isDirectory(), isSymbolicLink(), size, blocks, nlink, atimeMs, and mtimeMs are the supported Stats members", lowerer.checker.getSymbolAtLocation(expr.name));
3168
+ lowerer.noLowering(`Stats.${name}`, expr, "isFile(), isDirectory(), isSymbolicLink(), dev, ino, size, blocks, nlink, atimeMs, mtimeMs, and ctimeMs are the supported Stats members", lowerer.checker.getSymbolAtLocation(expr.name));
3129
3169
  }
3130
3170
  if (kind === "date") {
3131
3171
  const methods = new Set([
@@ -3166,22 +3206,30 @@ export function lowerIntrinsicProperty(lowerer, expr) {
3166
3206
  // serialization: lowercased hostname, `:port` appended exactly when
3167
3207
  // a non-default port is present (scr_url_host — Node-exact,
3168
3208
  // opaque-path URLs answer ""); `hostname` is the stored port-less
3169
- // host field verbatim (Node would keep IPv6 brackets here, but the
3170
- // parser rejects IPv6 hosts — documented divergence — so the getter
3171
- // never sees one).
3172
- if (name === "protocol" || name === "pathname" || name === "href" || name === "host" || name === "hostname" || name === "search") {
3209
+ // host field verbatim, including IPv6 brackets.
3210
+ if (name === "protocol" || name === "origin" || name === "username" || name === "password" || name === "pathname" || name === "href" || name === "host" || name === "hostname" || name === "port" || name === "search" || name === "hash") {
3173
3211
  const receiver = lowerer.lowerExpr(expr.expression);
3174
3212
  const fn = name === "protocol"
3175
3213
  ? "url.protocol"
3176
- : name === "pathname"
3177
- ? "url.pathname"
3178
- : name === "host"
3179
- ? "url.host"
3180
- : name === "hostname"
3181
- ? "url.hostname"
3182
- : name === "search"
3183
- ? "url.search"
3184
- : "url.href";
3214
+ : name === "origin"
3215
+ ? "url.origin"
3216
+ : name === "username"
3217
+ ? "url.username"
3218
+ : name === "password"
3219
+ ? "url.password"
3220
+ : name === "pathname"
3221
+ ? "url.pathname"
3222
+ : name === "host"
3223
+ ? "url.host"
3224
+ : name === "hostname"
3225
+ ? "url.hostname"
3226
+ : name === "port"
3227
+ ? "url.port"
3228
+ : name === "search"
3229
+ ? "url.search"
3230
+ : name === "hash"
3231
+ ? "url.hash"
3232
+ : "url.href";
3185
3233
  return { kind: "libCall", fn, args: [receiver], type: STRING, loc: locOf(expr) };
3186
3234
  }
3187
3235
  // `u.searchParams`: the LIVE cached view (one identity per URL —
@@ -3194,7 +3242,7 @@ export function lowerIntrinsicProperty(lowerer, expr) {
3194
3242
  if (name === "toString" || name === "toJSON") {
3195
3243
  lowerer.unsupported("SC1090", expr, `URL methods as values (call '${name}' directly)`);
3196
3244
  }
3197
- lowerer.noLowering(`URL.${name}`, expr, "protocol, pathname, href, host, hostname, search, searchParams, and toString() are the supported URL members", lowerer.checker.getSymbolAtLocation(expr.name));
3245
+ lowerer.noLowering(`URL.${name}`, expr, "protocol, origin, username, password, pathname, href, host, hostname, port, search, hash, searchParams, and toString() are the supported URL members", lowerer.checker.getSymbolAtLocation(expr.name));
3198
3246
  }
3199
3247
  if (kind === "searchParams") {
3200
3248
  const SEARCH_PARAMS_METHODS = new Set(["get", "getAll", "set", "append", "delete", "has", "sort", "toString", "forEach", "keys", "values", "entries"]);
@@ -4863,6 +4911,15 @@ export function lowerElementWrite(lowerer, expr) {
4863
4911
  export function ensureString(lowerer, e, node) {
4864
4912
  if (e.type.kind === "string")
4865
4913
  return e;
4914
+ if (e.type.kind === "bigint") {
4915
+ return {
4916
+ kind: "libCall",
4917
+ fn: "bigint.toString",
4918
+ args: [e, { kind: "numLit", value: 10, type: F64, loc: e.loc }],
4919
+ type: STRING,
4920
+ loc: e.loc,
4921
+ };
4922
+ }
4866
4923
  if (e.type.kind === "dyn") {
4867
4924
  // String(u) / `${u}`: a runtime dispatch over the dyn kind — Node's
4868
4925
  // String() exactly (undefined/null texts, JS number formatting,
@@ -4892,7 +4949,7 @@ export function ensureString(lowerer, e, node) {
4892
4949
  // JS would print "[object Object]" and friends — narrow first.
4893
4950
  const def = lowerer.unions.get(e.type.unionId);
4894
4951
  const stringable = def?.arms.every((a) => a.kind === "undefinedT" || a.kind === "nullT" ||
4895
- a.kind === "string" || a.kind === "f64" || a.kind === "bool");
4952
+ a.kind === "string" || a.kind === "f64" || a.kind === "bigint" || a.kind === "bool");
4896
4953
  if (stringable) {
4897
4954
  return { kind: "toString", operand: e, type: STRING, loc: e.loc };
4898
4955
  }
@@ -5171,6 +5228,9 @@ export function lowerPrefixUnary(lowerer, expr) {
5171
5228
  if (raw.type.kind === "jsval") {
5172
5229
  return { kind: "jsOp", op: "neg", args: [raw], type: JSVAL, loc };
5173
5230
  }
5231
+ if (raw.type.kind === "bigint") {
5232
+ return { kind: "libCall", fn: "bigint.neg", args: [raw], type: BIGINT_T, loc };
5233
+ }
5174
5234
  const operand = lowerOptionalNumber(lowerer, raw, loc, expr.operand);
5175
5235
  if (operand.type.kind !== "f64")
5176
5236
  lowerer.unsupported("SC1043", expr);
@@ -5201,7 +5261,18 @@ export function lowerPrefixUnary(lowerer, expr) {
5201
5261
  }
5202
5262
  case ts.SyntaxKind.TildeToken: {
5203
5263
  // `~x`: ToInt32, complement, back to f64 (JS-exact, incl. NaN → -1).
5204
- const operand = lowerOptionalNumber(lowerer, lowerer.lowerExpr(expr.operand), loc, expr.operand);
5264
+ const raw = lowerer.lowerExpr(expr.operand);
5265
+ if (raw.type.kind === "bigint") {
5266
+ return { kind: "libCall", fn: "bigint.not", args: [raw], type: BIGINT_T, loc };
5267
+ }
5268
+ // A checked-dynamic value retains enough JavaScript structure to
5269
+ // run exact ToNumber, including the object valueOf/toString
5270
+ // protocol. This is the static `any`/JS-lane answer for idioms
5271
+ // such as `while (~index)`, where inference may have widened an
5272
+ // otherwise numeric slot to the checked-dynamic tree.
5273
+ const operand = raw.type.kind === "dyn"
5274
+ ? { kind: "libCall", fn: "dyn.toNumberCoerce", args: [raw], type: F64, loc }
5275
+ : lowerOptionalNumber(lowerer, raw, loc, expr.operand);
5205
5276
  if (operand.type.kind !== "f64")
5206
5277
  lowerer.unsupported("SC1043", expr);
5207
5278
  return { kind: "unary", op: "~", operand, type: F64, loc };
@@ -5490,23 +5561,10 @@ export function lowerBinary(lowerer, expr) {
5490
5561
  const nullTest = lowerLooseNullCompare(lowerer, expr, loc);
5491
5562
  if (nullTest)
5492
5563
  return nullTest;
5493
- // SAME-KIND loose equality IS strict equality (the spec's ==
5494
- // dispatches to === when both operands share a type): `typeof v ==
5495
- // 'object'`, `n != 0`, `flag == true` all lower exactly. Mixed
5496
- // kinds (where == coerces) keep the fence.
5497
- {
5498
- const negated = op === ts.SyntaxKind.ExclamationEqualsToken;
5499
- const left = lowerer.lowerExpr(expr.left);
5500
- const right = lowerer.lowerExpr(expr.right);
5501
- if (left.type.kind === "string" && right.type.kind === "string") {
5502
- return { kind: "strEq", negated, left, right, type: BOOL, loc };
5503
- }
5504
- if ((left.type.kind === "f64" && right.type.kind === "f64") ||
5505
- (left.type.kind === "bool" && right.type.kind === "bool")) {
5506
- return { kind: "bin", op: negated ? "!==" : "===", left, right, type: BOOL, loc };
5507
- }
5508
- }
5509
- lowerer.unsupported("SC1040", expr);
5564
+ const loose = lowerAbstractEquality(lowerer, lowerer.lowerExpr(expr.left), lowerer.lowerExpr(expr.right), op === ts.SyntaxKind.ExclamationEqualsToken, loc);
5565
+ if (loose)
5566
+ return loose;
5567
+ lowerer.unsupported("SC1040", expr, undefined, "object-to-primitive loose equality can call user-defined valueOf/toString methods — compare explicit primitive conversions instead");
5510
5568
  }
5511
5569
  if (op === ts.SyntaxKind.AmpersandAmpersandToken || op === ts.SyntaxKind.BarBarToken) {
5512
5570
  if (op === ts.SyntaxKind.BarBarToken) {
@@ -5530,6 +5588,15 @@ export function lowerBinary(lowerer, expr) {
5530
5588
  if (left.kind === "unitLit") {
5531
5589
  return op === ts.SyntaxKind.BarBarToken ? right : left;
5532
5590
  }
5591
+ // JS objects and symbols are always truthy. In `ref || fallback`
5592
+ // the fallback is therefore unreachable and the result is the
5593
+ // already-evaluated left value — the browser-fallback idiom used by
5594
+ // packages for `process.argv || []` and `process.env || {}`. The
5595
+ // operand itself remains in the IR, preserving reads/calls that
5596
+ // produce the reference; only the unreachable right lowering drops.
5597
+ if (op === ts.SyntaxKind.BarBarToken && REF_TRUTHY_KINDS.has(left.type.kind)) {
5598
+ return left;
5599
+ }
5533
5600
  if (left.type.kind === "dyn" || right.type.kind === "dyn") {
5534
5601
  // A checked-dynamic operand (`fn.name || '<anonymous>'` —
5535
5602
  // test/common's _mustCallInner): both sides live in the checked-dynamic tree and
@@ -5877,6 +5944,73 @@ export function lowerBinary(lowerer, expr) {
5877
5944
  if (left.type.kind === "jsval" || right.type.kind === "jsval") {
5878
5945
  return lowerAnyBinaryInIsland(lowerer, expr, left, right, loc);
5879
5946
  }
5947
+ if (left.type.kind === "bigint" && right.type.kind === "bigint") {
5948
+ const binary = {
5949
+ [ts.SyntaxKind.PlusToken]: "bigint.add",
5950
+ [ts.SyntaxKind.MinusToken]: "bigint.sub",
5951
+ [ts.SyntaxKind.AsteriskToken]: "bigint.mul",
5952
+ [ts.SyntaxKind.SlashToken]: "bigint.div",
5953
+ [ts.SyntaxKind.PercentToken]: "bigint.mod",
5954
+ [ts.SyntaxKind.AsteriskAsteriskToken]: "bigint.pow",
5955
+ [ts.SyntaxKind.AmpersandToken]: "bigint.and",
5956
+ [ts.SyntaxKind.BarToken]: "bigint.or",
5957
+ [ts.SyntaxKind.CaretToken]: "bigint.xor",
5958
+ [ts.SyntaxKind.LessThanLessThanToken]: "bigint.shl",
5959
+ [ts.SyntaxKind.GreaterThanGreaterThanToken]: "bigint.shr",
5960
+ };
5961
+ const fn = binary[op];
5962
+ if (fn)
5963
+ return { kind: "libCall", fn, args: [left, right], type: BIGINT_T, loc };
5964
+ if (op === ts.SyntaxKind.EqualsEqualsEqualsToken ||
5965
+ op === ts.SyntaxKind.ExclamationEqualsEqualsToken) {
5966
+ const equal = { kind: "libCall", fn: "bigint.eq", args: [left, right], type: BOOL, loc };
5967
+ return op === ts.SyntaxKind.ExclamationEqualsEqualsToken
5968
+ ? { kind: "unary", op: "!", operand: equal, type: BOOL, loc }
5969
+ : equal;
5970
+ }
5971
+ if (op === ts.SyntaxKind.LessThanToken || op === ts.SyntaxKind.LessThanEqualsToken ||
5972
+ op === ts.SyntaxKind.GreaterThanToken || op === ts.SyntaxKind.GreaterThanEqualsToken) {
5973
+ const cmp = { kind: "libCall", fn: "bigint.cmp", args: [left, right], type: F64, loc };
5974
+ const zero = { kind: "numLit", value: 0, type: F64, loc };
5975
+ const cmpOp = op === ts.SyntaxKind.LessThanToken ? "<"
5976
+ : op === ts.SyntaxKind.LessThanEqualsToken ? "<="
5977
+ : op === ts.SyntaxKind.GreaterThanToken ? ">" : ">=";
5978
+ return { kind: "bin", op: cmpOp, left: cmp, right: zero, type: BOOL, loc };
5979
+ }
5980
+ }
5981
+ if ((left.type.kind === "bigint" && right.type.kind === "f64") ||
5982
+ (left.type.kind === "f64" && right.type.kind === "bigint")) {
5983
+ if (op === ts.SyntaxKind.LessThanToken || op === ts.SyntaxKind.LessThanEqualsToken ||
5984
+ op === ts.SyntaxKind.GreaterThanToken || op === ts.SyntaxKind.GreaterThanEqualsToken) {
5985
+ const big = left.type.kind === "bigint" ? left : right;
5986
+ const num = left.type.kind === "f64" ? left : right;
5987
+ const cmp = { kind: "libCall", fn: "bigint.cmpNumber", args: [big, num], type: F64, loc };
5988
+ const cmpLocal = lowerer.declareHiddenLocal("%bigcmp", F64);
5989
+ const cmpRef = { kind: "varRef", localId: cmpLocal.id, type: F64, loc };
5990
+ const unordered = {
5991
+ kind: "bin", op: "===", left: cmpRef,
5992
+ right: { kind: "numLit", value: 2, type: F64, loc }, type: BOOL, loc,
5993
+ };
5994
+ const zero = { kind: "numLit", value: 0, type: F64, loc };
5995
+ const leftBig = left.type.kind === "bigint";
5996
+ const cmpOp = leftBig
5997
+ ? op === ts.SyntaxKind.LessThanToken ? "<" : op === ts.SyntaxKind.LessThanEqualsToken ? "<=" : op === ts.SyntaxKind.GreaterThanToken ? ">" : ">="
5998
+ : op === ts.SyntaxKind.LessThanToken ? ">" : op === ts.SyntaxKind.LessThanEqualsToken ? ">=" : op === ts.SyntaxKind.GreaterThanToken ? "<" : "<=";
5999
+ const result = {
6000
+ kind: "logical", op: "&&",
6001
+ left: { kind: "unary", op: "!", operand: unordered, type: BOOL, loc },
6002
+ right: { kind: "bin", op: cmpOp, left: cmpRef, right: zero, type: BOOL, loc },
6003
+ type: BOOL, loc,
6004
+ };
6005
+ return {
6006
+ kind: "seqExpr",
6007
+ stmts: [{ kind: "varDecl", localId: cmpLocal.id, init: cmp, loc }],
6008
+ result,
6009
+ type: BOOL,
6010
+ loc,
6011
+ };
6012
+ }
6013
+ }
5880
6014
  // An unchecked array read keeps its undefined arm in the IR even when
5881
6015
  // the checker typed the binding as `string`. An optional string is not
5882
6016
  // itself a string operand for `+`: `undefined + 1` and
@@ -6158,6 +6292,9 @@ export function lowerBinary(lowerer, expr) {
6158
6292
  if (idLeft.type.kind === "classval" && idRight.type.kind === "classval") {
6159
6293
  return { kind: "bin", op: negated ? "!==" : "===", left: idLeft, right: idRight, type: BOOL, loc };
6160
6294
  }
6295
+ if (idLeft.type.kind === "moduleNs" && idRight.type.kind === "moduleNs") {
6296
+ return { kind: "bin", op: negated ? "!==" : "===", left: idLeft, right: idRight, type: BOOL, loc };
6297
+ }
6161
6298
  if ((idLeft.type.kind === "array" ||
6162
6299
  idLeft.type.kind === "map" ||
6163
6300
  idLeft.type.kind === "set" ||
@@ -6390,6 +6527,7 @@ function typeofAnswer(arm) {
6390
6527
  case "undefinedT": return "undefined";
6391
6528
  case "func": return "function";
6392
6529
  case "symbol": return "symbol";
6530
+ case "bigint": return "bigint";
6393
6531
  case "nullT":
6394
6532
  case "array":
6395
6533
  case "map":
@@ -6409,7 +6547,10 @@ function typeofAnswer(arm) {
6409
6547
  case "httpClientReq":
6410
6548
  case "secureCtx":
6411
6549
  case "fsWatcher":
6550
+ case "cryptoHash":
6551
+ case "cryptoHmac":
6412
6552
  case "childStream":
6553
+ case "childWriter":
6413
6554
  case "procStream":
6414
6555
  case "object":
6415
6556
  case "record":
@@ -7260,10 +7401,10 @@ function lowerInExpression(lowerer, expr, loc) {
7260
7401
  // Compile-time-known STRING keys fold — literals, and the same
7261
7402
  // const/enum-literal and template folding computed property keys get
7262
7403
  // (foldedStringKeyOf); runtime-valued keys keep the fence.
7263
- // NUMERIC literal keys answer on ARRAY receivers: dense arrays hold
7264
- // exactly the indices [0, length), so `3 in xs` is a length test (and
7265
- // a negative/fractional literal is a constant miss — the receiver
7266
- // still evaluates once through its own length read).
7404
+ // NUMERIC literal keys answer on ARRAY receivers through the shared
7405
+ // presence query. Arrays retain holes independently from length, and
7406
+ // noncanonical numeric keys live in their ordinary-property table, so
7407
+ // a length comparison is not an honest `in` answer.
7267
7408
  {
7268
7409
  let kNode = expr.left;
7269
7410
  while (ts.isParenthesizedExpression(kNode))
@@ -7271,12 +7412,14 @@ function lowerInExpression(lowerer, expr, loc) {
7271
7412
  if (ts.isNumericLiteral(kNode) && lowerer.mapTypeOf(lowerer.typeOf(expr.right))?.kind === "array") {
7272
7413
  const recvArr = lowerer.lowerExpr(expr.right);
7273
7414
  if (recvArr.type.kind === "array") {
7274
- const len = { kind: "arrIntrinsic", method: "length", receiver: recvArr, args: [], type: F64, loc };
7275
7415
  const n = Number(kNode.text);
7276
- if (Number.isInteger(n) && n >= 0) {
7277
- return { kind: "bin", op: "<", left: { kind: "numLit", value: n, type: F64, loc }, right: len, type: BOOL, loc };
7278
- }
7279
- return { kind: "bin", op: "<", left: len, right: { kind: "numLit", value: 0, type: F64, loc }, type: BOOL, loc };
7416
+ return {
7417
+ kind: "arrayHas",
7418
+ arr: recvArr,
7419
+ index: { kind: "numLit", value: n, type: F64, loc },
7420
+ type: BOOL,
7421
+ loc,
7422
+ };
7280
7423
  }
7281
7424
  }
7282
7425
  }
@@ -8912,32 +9055,40 @@ function lowerStreamObjectProperty(lowerer, expr) {
8912
9055
  return lowerStreamProperty(lowerer, expr, info);
8913
9056
  }
8914
9057
  /** The primitive-constructor closure (`String`/`Number`/`Boolean` as a
8915
- * VALUE): interns one synthesized module function per constructor —
8916
- * `%builtin.String` et al. — and returns the zero-capture closure over it.
8917
- * The body IS the string-coercion the type mapping promised
8918
- * (`(value: string) => primitive`): String is identity, Number the ECMA
8919
- * StringToNumber (num.fromString — the same runtime call the direct
8920
- * `Number(s)` lowering emits), Boolean the emptiness test. Interning makes
8921
- * every reference the SAME immortal closure, so `opt.type === String`
8922
- * compares like JS function identity. */
8923
- function primitiveCtorClosure(lowerer, name, loc) {
9058
+ * VALUE): interns one synthesized module function per constructor/ABI and
9059
+ * returns the zero-capture closure over it. Typed sources use the mapped
9060
+ * `(value: string) => primitive` signature; a recognized JavaScript
9061
+ * concise-arrow selector (`() => String`, the picocolors fallback) takes
9062
+ * dyn so its ordinary coercion signature survives inference residue. The
9063
+ * dyn bodies run exact ToString/ToNumber/ToBoolean, including object hooks.
9064
+ * Interning makes every reference under one ABI the SAME immortal closure,
9065
+ * so `opt.type === String` compares like JS function identity. */
9066
+ function primitiveCtorClosure(lowerer, name, loc, dynamicInput) {
8924
9067
  const ret = name === "String" ? STRING : name === "Number" ? F64 : BOOL;
8925
- const fnT = funcOf([STRING], ret);
8926
- let fnName = lowerer.primitiveCtorFns.get(name);
9068
+ const input = dynamicInput ? DYN : STRING;
9069
+ const fnT = funcOf([input], ret);
9070
+ const key = `${name}:${dynamicInput ? "dyn" : "string"}`;
9071
+ let fnName = lowerer.primitiveCtorFns.get(key);
8927
9072
  if (!fnName) {
8928
- fnName = `%builtin.${name}`;
8929
- lowerer.primitiveCtorFns.set(name, fnName);
8930
- const s = { kind: "varRef", localId: "v.0", type: STRING, loc };
8931
- const value = name === "String"
8932
- ? s
8933
- : name === "Number"
8934
- ? { kind: "libCall", fn: "num.fromString", args: [s], type: F64, loc }
8935
- : { kind: "strEq", negated: true, left: s, right: { kind: "strLit", value: "", type: STRING, loc }, type: BOOL, loc };
9073
+ fnName = `%builtin.${name}${dynamicInput ? ".dyn" : ""}`;
9074
+ lowerer.primitiveCtorFns.set(key, fnName);
9075
+ const v = { kind: "varRef", localId: "v.0", type: input, loc };
9076
+ const value = dynamicInput
9077
+ ? name === "String"
9078
+ ? { kind: "libCall", fn: "dyn.toStringCoerce", args: [v], type: STRING, loc }
9079
+ : name === "Number"
9080
+ ? { kind: "libCall", fn: "dyn.toNumberCoerce", args: [v], type: F64, loc }
9081
+ : { kind: "dynTest", test: "truthy", value: v, type: BOOL, loc }
9082
+ : name === "String"
9083
+ ? v
9084
+ : name === "Number"
9085
+ ? { kind: "libCall", fn: "num.fromString", args: [v], type: F64, loc }
9086
+ : { kind: "strEq", negated: true, left: v, right: { kind: "strLit", value: "", type: STRING, loc }, type: BOOL, loc };
8936
9087
  const fn = {
8937
9088
  name: fnName,
8938
- params: [{ localId: "v.0", name: "value", type: STRING }],
9089
+ params: [{ localId: "v.0", name: "value", type: input }],
8939
9090
  returnType: ret,
8940
- locals: [{ id: "v.0", name: "value", type: STRING, mutable: false }],
9091
+ locals: [{ id: "v.0", name: "value", type: input, mutable: false }],
8941
9092
  body: [{ kind: "return", value, loc }],
8942
9093
  loc,
8943
9094
  };