@scriptc/compiler 0.2.0 → 0.2.1

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 (194) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +25 -15
  2. package/dist/backend/cycle-analysis.js +1 -0
  3. package/dist/backend/cycle-analysis.js.map +1 -1
  4. package/dist/backend/llvm/classes.js +21 -5
  5. package/dist/backend/llvm/classes.js.map +1 -1
  6. package/dist/backend/llvm/dyn.d.ts +5 -0
  7. package/dist/backend/llvm/dyn.js +166 -99
  8. package/dist/backend/llvm/dyn.js.map +1 -1
  9. package/dist/backend/llvm/emitter.d.ts +2 -2
  10. package/dist/backend/llvm/emitter.js +79 -20
  11. package/dist/backend/llvm/emitter.js.map +1 -1
  12. package/dist/backend/llvm/expr-bytes.d.ts +1 -1
  13. package/dist/backend/llvm/expr-bytes.js +28 -17
  14. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  15. package/dist/backend/llvm/expr-control.js +1 -1
  16. package/dist/backend/llvm/expr-control.js.map +1 -1
  17. package/dist/backend/llvm/expr-dynamic.js +18 -9
  18. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  19. package/dist/backend/llvm/expr-primitives.js +11 -1
  20. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  21. package/dist/backend/llvm/expr-records.js +11 -3
  22. package/dist/backend/llvm/expr-records.js.map +1 -1
  23. package/dist/backend/llvm/expr-stream-bridges.js +125 -17
  24. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  25. package/dist/backend/llvm/lib-process.js +23 -3
  26. package/dist/backend/llvm/lib-process.js.map +1 -1
  27. package/dist/backend/llvm/lib-shared.js +45 -2
  28. package/dist/backend/llvm/lib-shared.js.map +1 -1
  29. package/dist/backend/llvm/shapes.js +8 -2
  30. package/dist/backend/llvm/shapes.js.map +1 -1
  31. package/dist/backend/native-toolchain.d.ts +3 -6
  32. package/dist/backend/native-toolchain.js +53 -23
  33. package/dist/backend/native-toolchain.js.map +1 -1
  34. package/dist/backend/native-toolchain.test.js +72 -0
  35. package/dist/backend/native-toolchain.test.js.map +1 -1
  36. package/dist/backend/runtime-abi.d.ts +2 -2
  37. package/dist/backend/runtime-abi.js +2 -2
  38. package/dist/backend/runtime-pack-native.js +4 -1
  39. package/dist/backend/runtime-pack-native.js.map +1 -1
  40. package/dist/backend/runtime-pack-targets.test.js +1 -1
  41. package/dist/backend/runtime-pack.test.js +1 -1
  42. package/dist/backend/targets.js +10 -6
  43. package/dist/backend/targets.js.map +1 -1
  44. package/dist/backend/targets.test.js +7 -0
  45. package/dist/backend/targets.test.js.map +1 -1
  46. package/dist/compat/fetch-profile.js +34 -4
  47. package/dist/compat/fetch-profile.js.map +1 -1
  48. package/dist/diagnostics/diagnostic.js +2 -7
  49. package/dist/diagnostics/diagnostic.js.map +1 -1
  50. package/dist/frontend/lowering/class-callbacks.d.ts +3 -3
  51. package/dist/frontend/lowering/class-callbacks.js +26 -15
  52. package/dist/frontend/lowering/class-callbacks.js.map +1 -1
  53. package/dist/frontend/lowering/class-construction.d.ts +12 -0
  54. package/dist/frontend/lowering/class-construction.js +156 -0
  55. package/dist/frontend/lowering/class-construction.js.map +1 -0
  56. package/dist/frontend/lowering/class-descriptors.d.ts +1 -0
  57. package/dist/frontend/lowering/class-descriptors.js +46 -5
  58. package/dist/frontend/lowering/class-descriptors.js.map +1 -1
  59. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +11 -1
  60. package/dist/frontend/lowering/class-dynamic-dispatch.js +403 -48
  61. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  62. package/dist/frontend/lowering/class-dynamic-dispatch.test.js +2 -1
  63. package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
  64. package/dist/frontend/lowering/class-instance-constructor.js +4 -1
  65. package/dist/frontend/lowering/class-instance-constructor.js.map +1 -1
  66. package/dist/frontend/lowering/class-method-values.d.ts +4 -1
  67. package/dist/frontend/lowering/class-method-values.js +72 -7
  68. package/dist/frontend/lowering/class-method-values.js.map +1 -1
  69. package/dist/frontend/lowering/class-prototypes.d.ts +5 -2
  70. package/dist/frontend/lowering/class-prototypes.js +121 -13
  71. package/dist/frontend/lowering/class-prototypes.js.map +1 -1
  72. package/dist/frontend/lowering/class-runtime-statics.d.ts +8 -0
  73. package/dist/frontend/lowering/class-runtime-statics.js +66 -0
  74. package/dist/frontend/lowering/class-runtime-statics.js.map +1 -0
  75. package/dist/frontend/lowering/class-static-data.js +2 -2
  76. package/dist/frontend/lowering/class-static-data.js.map +1 -1
  77. package/dist/frontend/lowering/containers/bytes.js +49 -13
  78. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  79. package/dist/frontend/lowering/containers/string-and-regexp.js +19 -47
  80. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  81. package/dist/frontend/lowering/error-methods.d.ts +4 -1
  82. package/dist/frontend/lowering/error-methods.js +100 -1
  83. package/dist/frontend/lowering/error-methods.js.map +1 -1
  84. package/dist/frontend/lowering/expressions/native-proxy.js +3 -1
  85. package/dist/frontend/lowering/expressions/native-proxy.js.map +1 -1
  86. package/dist/frontend/lowering/expressions/nullish-assignment.js +19 -11
  87. package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -1
  88. package/dist/frontend/lowering/expressions/object-literals.js +38 -7
  89. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  90. package/dist/frontend/lowering/expressions/optional-chains.d.ts +3 -4
  91. package/dist/frontend/lowering/expressions/optional-chains.js +69 -17
  92. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
  93. package/dist/frontend/lowering/function-context.d.ts +11 -3
  94. package/dist/frontend/lowering/function-context.js +11 -5
  95. package/dist/frontend/lowering/function-context.js.map +1 -1
  96. package/dist/frontend/lowering/generator-dynamic-dispatch.d.ts +1 -0
  97. package/dist/frontend/lowering/generator-dynamic-dispatch.js +39 -1
  98. package/dist/frontend/lowering/generator-dynamic-dispatch.js.map +1 -1
  99. package/dist/frontend/lowering/lib-boundary.d.ts +2 -0
  100. package/dist/frontend/lowering/lib-boundary.js +54 -1
  101. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  102. package/dist/frontend/lowering/lower-builtin-values.d.ts +7 -1
  103. package/dist/frontend/lowering/lower-builtin-values.js +113 -3
  104. package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
  105. package/dist/frontend/lowering/lower-builtins.d.ts +6 -5
  106. package/dist/frontend/lowering/lower-builtins.js +156 -41
  107. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  108. package/dist/frontend/lowering/lower-calls.d.ts +8 -5
  109. package/dist/frontend/lowering/lower-calls.js +448 -83
  110. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  111. package/dist/frontend/lowering/lower-classes.d.ts +13 -13
  112. package/dist/frontend/lowering/lower-classes.js +650 -176
  113. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  114. package/dist/frontend/lowering/lower-containers.d.ts +9 -0
  115. package/dist/frontend/lowering/lower-containers.js +135 -36
  116. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  117. package/dist/frontend/lowering/lower-dgram.js +3 -2
  118. package/dist/frontend/lowering/lower-dgram.js.map +1 -1
  119. package/dist/frontend/lowering/lower-exprs.d.ts +2 -2
  120. package/dist/frontend/lowering/lower-exprs.js +531 -126
  121. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  122. package/dist/frontend/lowering/lower-generators.js +12 -1
  123. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  124. package/dist/frontend/lowering/lower-island.d.ts +2 -0
  125. package/dist/frontend/lowering/lower-island.js +32 -10
  126. package/dist/frontend/lowering/lower-island.js.map +1 -1
  127. package/dist/frontend/lowering/lower-modules.js +220 -17
  128. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  129. package/dist/frontend/lowering/lower-modules.test.d.ts +1 -0
  130. package/dist/frontend/lowering/lower-modules.test.js +39 -0
  131. package/dist/frontend/lowering/lower-modules.test.js.map +1 -0
  132. package/dist/frontend/lowering/lower-stmts.d.ts +7 -3
  133. package/dist/frontend/lowering/lower-stmts.js +135 -26
  134. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  135. package/dist/frontend/lowering/lower-stream.js +1 -1
  136. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  137. package/dist/frontend/lowering/lowerer.d.ts +27 -1
  138. package/dist/frontend/lowering/lowerer.js +172 -50
  139. package/dist/frontend/lowering/lowerer.js.map +1 -1
  140. package/dist/frontend/lowering/lowerer.test.js +149 -3
  141. package/dist/frontend/lowering/lowerer.test.js.map +1 -1
  142. package/dist/frontend/lowering/surfaces.d.ts +2 -0
  143. package/dist/frontend/lowering/surfaces.js +25 -8
  144. package/dist/frontend/lowering/surfaces.js.map +1 -1
  145. package/dist/frontend/lowering/text-decoder-encoding.d.ts +2 -0
  146. package/dist/frontend/lowering/text-decoder-encoding.js +5 -0
  147. package/dist/frontend/lowering/text-decoder-encoding.js.map +1 -1
  148. package/dist/frontend/lowering/unregistered-class-types.test.js +3 -3
  149. package/dist/frontend/lowering/unregistered-class-types.test.js.map +1 -1
  150. package/dist/frontend/npm-static-prune.js +116 -34
  151. package/dist/frontend/npm-static-prune.js.map +1 -1
  152. package/dist/frontend/npm-static-prune.test.js +8 -0
  153. package/dist/frontend/npm-static-prune.test.js.map +1 -1
  154. package/dist/frontend/program.d.ts +1 -1
  155. package/dist/frontend/program.js +53 -24
  156. package/dist/frontend/program.js.map +1 -1
  157. package/dist/frontend/program.test.js +18 -0
  158. package/dist/frontend/program.test.js.map +1 -1
  159. package/dist/frontend/ts7/ast.js +4 -3
  160. package/dist/frontend/ts7/ast.js.map +1 -1
  161. package/dist/frontend/ts7/semantic-json.js +5 -10
  162. package/dist/frontend/ts7/semantic-json.js.map +1 -1
  163. package/dist/frontend/type-mapper.d.ts +9 -1
  164. package/dist/frontend/type-mapper.js +90 -13
  165. package/dist/frontend/type-mapper.js.map +1 -1
  166. package/dist/frontend/type-mapper.test.js +23 -0
  167. package/dist/frontend/type-mapper.test.js.map +1 -1
  168. package/dist/frontend/union-discriminants.d.ts +1 -1
  169. package/dist/frontend/union-discriminants.js +2 -2
  170. package/dist/frontend/union-discriminants.js.map +1 -1
  171. package/dist/ir/analysis.js +2 -0
  172. package/dist/ir/analysis.js.map +1 -1
  173. package/dist/ir/ir.d.ts +52 -33
  174. package/dist/ir/ir.js +142 -42
  175. package/dist/ir/ir.js.map +1 -1
  176. package/dist/ir/ir.test.js +35 -0
  177. package/dist/ir/ir.test.js.map +1 -1
  178. package/dist/ir/serialize.js +15 -3
  179. package/dist/ir/serialize.js.map +1 -1
  180. package/dist/ir/serialize.test.js +5 -1
  181. package/dist/ir/serialize.test.js.map +1 -1
  182. package/dist/ir/validate.js +80 -11
  183. package/dist/ir/validate.js.map +1 -1
  184. package/dist/ir/validate.test.js +61 -1
  185. package/dist/ir/validate.test.js.map +1 -1
  186. package/dist/native/sanitizer.js +3 -1
  187. package/dist/native/sanitizer.js.map +1 -1
  188. package/dist/native/toolchain.d.ts +1 -1
  189. package/dist/native/toolchain.js +26 -6
  190. package/dist/native/toolchain.js.map +1 -1
  191. package/dist/native/toolchain.test.js +53 -1
  192. package/dist/native/toolchain.test.js.map +1 -1
  193. package/package.json +20 -20
  194. package/surface-manifest.json +56 -81
@@ -16,16 +16,16 @@ import { BOOL, DYN, F64, JSVAL, RUNTIME_ERROR_CLASSES, STRING, VOID, arrayOf, ca
16
16
  import { ENTRY_NAME, PoisonError, boundIdentifiersOf, dynFallbackType, dynUndefinedExpr, importCallHandleType, newFnCtx, staticImportNamespaceType, uncheckedOverloadHandleCall } from "./lowerer.js";
17
17
  import { isNativeFfiRequire, builtinMemberRequireDecl, builtinNamespaceDestructureModuleOf, createRequireBindingDecl, createRequireNamespaceDecl, createRequireProgramModuleDecl, createRequireSpecOf, isPromisifyCall, registerBuiltinCallableAlias, stripTypeCasts } from "./lower-builtins.js";
18
18
  import { bindingContextualGenericFnNodeOf, bindingGenericFnAliasInfoOf, bindingGenericFnInfoOf, bindingGenericFnNodeOf, bindingNeverReassigned, deadUnmappableBinding, funcTypeFromParamShapes, implicitLocalFnInfoOf, implicitLocalFnNodeOf, nullishGenericBindingUnitOf, registerOverloadedCallableAlias } from "./lower-calls.js";
19
- import { hasJsTypeAnnotation, isVarDeclared, numericIteratorSourceOf, provenanceElidedConstDecl } from "./lower-stmts.js";
19
+ import { jsBindingHasOpenWrites, hasJsTypeAnnotation, isVarDeclared, numericIteratorSourceOf, provenanceElidedConstDecl } from "./lower-stmts.js";
20
20
  import { objectFactorySignature } from "./object-factory-new.js";
21
21
  import { streamClassAliasDecl } from "./lower-stream.js";
22
22
  import { stdlibGlobalAliasDecl, stdlibGlobalAliasNameOf, stdlibGlobalNameOf } from "./surfaces.js";
23
23
  import { isNativeBuiltinValueInitializer } from "./lower-builtin-values.js";
24
- import { collectNamespaceStmt, nsPathPrefix, trapDeclRootOf } from "./lower-namespaces.js";
24
+ import { collectNamespaceStmt, nsMemberIdentOf, nsPathPrefix, trapDeclRootOf } from "./lower-namespaces.js";
25
25
  import { collectExpandoMembers } from "./lower-expando.js";
26
26
  import { recordTextCodecClass } from "../../ir/ir.js";
27
27
  import { isUnitOnlyTsType, unitOnlyUnion } from "../type-mapper.js";
28
- import { collectVirtualJsMethods, decoratorNodesOf, genericIfaceBindingKeepsClass, guaranteedDecorationThrow } from "./lower-classes.js";
28
+ import { collectVirtualJsMethods, decoratorNodesOf, genericIfaceBindingKeepsClass, guaranteedDecorationThrow, storedClassValueType } from "./lower-classes.js";
29
29
  import { isMixinFnBinding, mixinResultBindingClassOf } from "./lower-mixins.js";
30
30
  import { cjsModuleRef, cjsModuleRegistryPrelude } from "./lower-node-module.js";
31
31
  import { forkTargetPaths } from "../fork-target.js";
@@ -228,12 +228,41 @@ export function appendDynamicImportModules(program, order, onCycle) {
228
228
  * signatures are cheap and calls resolve against them; only BODY lowering
229
229
  * is reachability-gated. */
230
230
  export function collectProgram(lowerer, parts) {
231
+ const computed = new Set();
232
+ for (const fp of parts)
233
+ for (const decl of fp.classDecls) {
234
+ const heritage = decl.heritageClauses?.find((clause) => clause.token === ts.SyntaxKind.ExtendsKeyword)?.types[0]?.expression;
235
+ if (heritage && ts.isCallExpression(heritage))
236
+ computed.add(decl);
237
+ }
238
+ // Descendants need the computed ancestor's completed layout before
239
+ // their own fields and inherited methods can be collected.
240
+ const computedSymbols = new Set([...computed].map((decl) => declSymbolOf(lowerer, decl)).filter((symbol) => symbol !== undefined));
241
+ let expanded = true;
242
+ while (expanded) {
243
+ expanded = false;
244
+ for (const fp of parts)
245
+ for (const decl of fp.classDecls) {
246
+ if (computed.has(decl))
247
+ continue;
248
+ const heritage = decl.heritageClauses?.find((clause) => clause.token === ts.SyntaxKind.ExtendsKeyword)?.types[0]?.expression;
249
+ const base = heritage && ts.isIdentifier(heritage) ? lowerer.resolveValueSymbol(heritage) : undefined;
250
+ if (!base || !computedSymbols.has(base))
251
+ continue;
252
+ computed.add(decl);
253
+ const symbol = declSymbolOf(lowerer, decl);
254
+ if (symbol)
255
+ computedSymbols.add(symbol);
256
+ expanded = true;
257
+ }
258
+ }
231
259
  lowerer.collecting = true;
232
260
  try {
233
261
  collectVirtualJsMethods(lowerer, parts.map((part) => part.sf));
234
262
  for (const fp of parts)
235
263
  for (const decl of fp.classDecls)
236
- lowerer.collectClassShape(decl);
264
+ if (!computed.has(decl))
265
+ lowerer.collectClassShape(decl);
237
266
  for (const fp of parts)
238
267
  for (const decl of fp.fnDecls)
239
268
  lowerer.collectSignature(decl);
@@ -263,6 +292,60 @@ export function collectProgram(lowerer, parts) {
263
292
  lowerer.collectNpmImports(parts);
264
293
  lowerer.collectJsonImports(parts);
265
294
  }
295
+ for (const decl of computed) {
296
+ const symbol = declSymbolOf(lowerer, decl);
297
+ const wasCollecting = lowerer.collecting;
298
+ lowerer.collecting = true;
299
+ const previousSink = lowerer.diagSink;
300
+ const deferred = [];
301
+ lowerer.diagSink = deferred;
302
+ const expression = decl.heritageClauses.find((clause) => clause.token === ts.SyntaxKind.ExtendsKeyword).types[0].expression;
303
+ const context = newFnCtx(false, null, null, DYN);
304
+ lowerer.fnStack.push(context);
305
+ try {
306
+ let value = lowerer.lowerExpr(expression);
307
+ const known = value.type.kind === "dyn" ? storedClassValueType(lowerer, expression) : null;
308
+ if (known?.kind === "classval")
309
+ value = lowerer.coerceToExpected(value, known);
310
+ if (value.type.kind === "dyn" || value.type.kind === "func") {
311
+ const name = `%class.base.${lowerer.classNamer(decl)}`;
312
+ const loc = locOf(expression);
313
+ lowerer.liftedFns.push({ name, params: [], returnType: value.type, locals: context.locals,
314
+ body: [{ kind: "return", value, loc }], loc });
315
+ lowerer.computedCallableBases.set(decl, { kind: "call", callee: name, args: [], type: value.type, loc });
316
+ }
317
+ if (value.type.kind === "classval") {
318
+ const classInfo = lowerer.classes.get(value.type.className);
319
+ if (classInfo) {
320
+ const name = `%class.base.${lowerer.classNamer(decl)}`;
321
+ const loc = locOf(expression);
322
+ lowerer.liftedFns.push({ name, params: [], returnType: value.type, locals: context.locals,
323
+ body: [{ kind: "return", value, loc }], loc });
324
+ lowerer.computedClassBases.set(lowerer.classNamer(decl), { value: { kind: "call", callee: name, args: [], type: value.type, loc }, classInfo });
325
+ }
326
+ }
327
+ }
328
+ catch (error) {
329
+ if (!(error instanceof PoisonError))
330
+ throw error;
331
+ }
332
+ finally {
333
+ lowerer.fnStack.pop();
334
+ lowerer.diagSink = previousSink;
335
+ }
336
+ lowerer.diagSink = deferred;
337
+ try {
338
+ lowerer.collectClassShape(decl);
339
+ }
340
+ finally {
341
+ lowerer.diagSink = previousSink;
342
+ }
343
+ if (symbol && deferred.length) {
344
+ lowerer.deferredDiags.set(symbol, [...(lowerer.deferredDiags.get(symbol) ?? []), ...deferred]);
345
+ lowerer.deferredClassByName.set(lowerer.classNamer(decl), symbol);
346
+ }
347
+ lowerer.collecting = wasCollecting;
348
+ }
266
349
  }
267
350
  /** The npm-import chokepoint, run once per pass during collection (so
268
351
  * bodies lowered in ANY pass resolve the bindings). In a static build
@@ -655,15 +738,41 @@ export function moduleArtifacts(lowerer, functions) {
655
738
  const pendingClasses = [];
656
739
  const pendingShapes = [];
657
740
  const pendingUnions = [];
741
+ const boxedChild = (type, seen = new Set()) => {
742
+ switch (type.kind) {
743
+ case "child": return true;
744
+ case "array":
745
+ case "set": return boxedChild(type.elem, seen);
746
+ case "promise": return boxedChild(type.inner, seen);
747
+ case "map": return boxedChild(type.key, seen) || boxedChild(type.value, seen);
748
+ case "func": return boxedChild(type.ret, seen);
749
+ case "record":
750
+ if (seen.has(type.shapeId))
751
+ return false;
752
+ seen.add(type.shapeId);
753
+ return lowerer.shapes.get(type.shapeId)?.fields.some((field) => boxedChild(field.type, seen)) ?? false;
754
+ case "union":
755
+ if (seen.has(type.unionId))
756
+ return false;
757
+ seen.add(type.unionId);
758
+ return lowerer.unions.get(type.unionId)?.arms.some((arm) => boxedChild(arm, seen)) ?? false;
759
+ default: return false;
760
+ }
761
+ };
658
762
  const visit = (node) => {
659
763
  if (Array.isArray(node)) {
660
- for (const item of node)
661
- visit(item);
764
+ // This walk only reads compiler-owned arrays. A callback traversal
765
+ // reuses one checked view instead of refreshing it at each step.
766
+ node.forEach(visit);
662
767
  return;
663
768
  }
664
769
  if (node === null || typeof node !== "object")
665
770
  return;
666
771
  const rec = node;
772
+ if (rec["kind"] === "dynFrom" && boxedChild(rec["value"].type)) {
773
+ // A generic child can expose native stdio without importing stream.
774
+ visit([{ className: "%Readable" }, { className: "%Writable" }]);
775
+ }
667
776
  if (typeof rec["className"] === "string" && !classNames.has(rec["className"])) {
668
777
  classNames.add(rec["className"]);
669
778
  pendingClasses.push(rec["className"]);
@@ -681,8 +790,25 @@ export function moduleArtifacts(lowerer, functions) {
681
790
  visit(rec[key]);
682
791
  }
683
792
  };
684
- visit(functions);
685
- visit(lowerer.globalsList);
793
+ // Keep function lists and their typed slots in native storage. Reflective
794
+ // array iteration refreshes a complete view at each step; only executable
795
+ // nodes and individual types need the general dependency walk.
796
+ for (const fn of functions) {
797
+ for (const param of fn.params)
798
+ visit(param.type);
799
+ visit(fn.returnType);
800
+ for (const local of fn.locals)
801
+ visit(local.type);
802
+ for (const capture of fn.captures ?? [])
803
+ visit(capture.type);
804
+ for (const capture of fn.classCaptures ?? [])
805
+ visit(capture.type);
806
+ visit(fn.generator);
807
+ for (const stmt of fn.body)
808
+ visit(stmt);
809
+ }
810
+ for (const global of lowerer.globalsList)
811
+ visit(global.type);
686
812
  // The builtin error classes ride EVERY module: the runtime's own throws
687
813
  // (JSON/dynCheck/regex failures) mint instances of them whether or not
688
814
  // user code mentions Error, and the uncaught printer tells Error
@@ -803,7 +929,7 @@ function cjsScalarLiteral(e) {
803
929
  * a checked-dynamic (or unit) value, so a DYN module global can hold it:
804
930
  * no initializer, a unit literal, or a checker-`any` call/member/
805
931
  * identifier read (any-typed operations lower through the checked-dynamic tree in JS).
806
- * `new` expressions stay OUT even when checker-any (`new Anon.Sub()` over
932
+ * User-class `new` expressions stay OUT even when checker-any (`new Anon.Sub()` over
807
933
  * an expando class member constructs a TYPED instance — corpus 2032), as
808
934
  * does everything else (object/array literals have their own rules;
809
935
  * typed-but-unmappable initializers keep the %init-local adoption). */
@@ -827,6 +953,16 @@ function jsDynHoldableInitializer(lowerer, init) {
827
953
  e = e.expression;
828
954
  if (checkedGlobalReference(lowerer, e))
829
955
  return true;
956
+ if (ts.isCallExpression(e) && ts.isPropertyAccessExpression(e.expression) &&
957
+ ["freeze", "seal", "preventExtensions"].includes(e.expression.name.text) &&
958
+ lowerer.stdlibGlobalMember(e.expression, "Object") !== null && e.arguments[0] &&
959
+ ts.isArrayLiteralExpression(e.arguments[0]))
960
+ return true;
961
+ // The built-in Array constructor can create an evolving array whose
962
+ // inferred element type has no native mapping. Its checked reference
963
+ // must remain shared with separately declared functions and aliases.
964
+ if ((ts.isCallExpression(e) || ts.isNewExpression(e)) && lowerer.isStdlibGlobal(e.expression, "Array"))
965
+ return true;
830
966
  // JavaScript process streams lower to native checked handles even when
831
967
  // their declared method overloads prevent a structural type mapping.
832
968
  // Register the shared slot before separately declared functions lower.
@@ -834,6 +970,8 @@ function jsDynHoldableInitializer(lowerer, init) {
834
970
  const member = lowerer.stdlibGlobalMember(e, "process");
835
971
  if (member === "stdin" || member === "stdout" || member === "stderr")
836
972
  return true;
973
+ if (e.name.text === "constructor" && lowerer.checker.getCallSignatures(lowerer.typeOf(e.expression)).length > 0)
974
+ return true;
837
975
  }
838
976
  if (e.kind === ts.SyntaxKind.NullKeyword)
839
977
  return true;
@@ -851,6 +989,11 @@ function jsDynHoldableInitializer(lowerer, init) {
851
989
  if ((ts.isPropertyAccessExpression(e) || ts.isElementAccessExpression(e)) &&
852
990
  ts.isIdentifier(e.expression) && lowerer.globalOf(e.expression)?.type.kind === "dyn")
853
991
  return true;
992
+ if (ts.isPropertyAccessExpression(e)) {
993
+ const member = nsMemberIdentOf(lowerer, e);
994
+ if (member && (lowerer.globalOf(member)?.type.kind === "dyn" || lowerer.genericFnOf(member)?.implicitParams))
995
+ return true;
996
+ }
854
997
  // Optional callable reads (for example descriptor?.get) can be held in
855
998
  // the same checked slot as a callable. Their nullish arm must remain
856
999
  // observable by functions declared outside the module initializer.
@@ -862,6 +1005,8 @@ function jsDynHoldableInitializer(lowerer, init) {
862
1005
  if (arms?.some(arm => arm.kind === "func") && arms.every(arm => isUnitType(arm) || (arm.kind === "func" && canBoxFuncIntoDyn(arm, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id)))))
863
1006
  return true;
864
1007
  }
1008
+ if ((ts.isFunctionExpression(e) || ts.isArrowFunction(e)) && !e.typeParameters?.length && isJsSourceFile(e.getSourceFile()))
1009
+ return true;
865
1010
  if (ts.isIdentifier(e) || ts.isArrowFunction(e) || ts.isFunctionExpression(e)) {
866
1011
  if (ts.isIdentifier(e)) {
867
1012
  if (lowerer.globalOf(e)?.type.kind === "dyn")
@@ -1123,8 +1268,12 @@ export function collectGlobals(lowerer, sf, topStmts) {
1123
1268
  const diagsBefore = lowerer.diags.length;
1124
1269
  try {
1125
1270
  const strict = lowerer.typeOf(rhs);
1126
- const t = lowerer.mapTypeOf(strict) ??
1271
+ let t = lowerer.mapTypeOf(strict) ??
1127
1272
  (fnValued || factoryValued ? dynFallbackType(lowerer, rhs, strict) : null);
1273
+ // A returned object remains the live CommonJS root; later
1274
+ // exports.member writes must update that same open object.
1275
+ if (factoryValued && t?.kind === "record" && lowerer.dynConvertible(t))
1276
+ t = DYN;
1128
1277
  if (t && t.kind !== "void") {
1129
1278
  const g = { id: `%g.${tag}exports`, name: "exports", type: t, mutable: false };
1130
1279
  lowerer.globalsByDeclNode.set(cjs.expr, g);
@@ -1493,6 +1642,23 @@ export function collectGlobals(lowerer, sf, topStmts) {
1493
1642
  for (const nameNode of boundIdentifiersOf(decl.name)) {
1494
1643
  const diagsBefore = lowerer.diags.length;
1495
1644
  try {
1645
+ // Checked JavaScript factories can expose inferred callables by
1646
+ // destructuring. Keep each exported binding in module storage so
1647
+ // separately lowered functions see the initialized value.
1648
+ if (isJsSourceFile(sf) && !ts.isIdentifier(decl.name) && decl.initializer &&
1649
+ !decl.type && !hasJsTypeAnnotation(decl) && !lowerer.mapTypeOf(lowerer.typeOf(nameNode))) {
1650
+ const symbol = lowerer.checker.getSymbolAtLocation(nameNode);
1651
+ if (symbol && !lowerer.globalsBySymbol.has(symbol)) {
1652
+ const g = { id: `%g.${tag}${nsPrefix}${nameNode.text}`, name: nameNode.text,
1653
+ type: DYN, mutable: isLet, source: bindingSource(nameNode),
1654
+ ...(!isVarDeclared(decl) ? { tdz: true } : {}) };
1655
+ lowerer.globalsBySymbol.set(symbol, g);
1656
+ lowerer.globalsList.push(g);
1657
+ if (isVarDeclared(decl))
1658
+ noteVarGlobalEntryInit(lowerer, sf, g);
1659
+ }
1660
+ continue;
1661
+ }
1496
1662
  // Builtin declarations do not always describe the concrete native
1497
1663
  // callable ABI. Preserve checked-native values in shared storage;
1498
1664
  // adapting the loader to (string) would replace its validation.
@@ -1543,7 +1709,8 @@ export function collectGlobals(lowerer, sf, topStmts) {
1543
1709
  if (isJsSourceFile(sf) && ts.isIdentifier(decl.name) && nameNode === decl.name &&
1544
1710
  decl.initializer && ts.isObjectLiteralExpression(decl.initializer) &&
1545
1711
  decl.initializer.properties.some((p) => !ts.isSpreadAssignment(p) &&
1546
- (ts.isMethodDeclaration(p) || ts.isAccessor(p) || ts.isComputedPropertyName(p.name)))) {
1712
+ (ts.isMethodDeclaration(p) || ts.isAccessor(p) || ts.isComputedPropertyName(p.name) ||
1713
+ ts.isShorthandPropertyAssignment(p) && lowerer.checker.getCallSignatures(lowerer.typeOf(p.name)).length > 0))) {
1547
1714
  const symbol = lowerer.checker.getSymbolAtLocation(nameNode);
1548
1715
  if (symbol && !lowerer.globalsBySymbol.has(symbol)) {
1549
1716
  const g = { id: `%g.${tag}${nsPrefix}${nameNode.text}`, name: nameNode.text, type: DYN, mutable: isLet, source: bindingSource(nameNode) };
@@ -1649,9 +1816,16 @@ export function collectGlobals(lowerer, sf, topStmts) {
1649
1816
  if (isJsSourceFile(sf) && !lowerer.mapTypeOf(lowerer.typeOf(nameNode)) &&
1650
1817
  ts.isIdentifier(decl.name) && nameNode === decl.name && decl.initializer &&
1651
1818
  jsDynHoldableInitializer(lowerer, decl.initializer)) {
1652
- const fallback = dynFallbackType(lowerer, nameNode, lowerer.typeOf(nameNode));
1819
+ const initializer = decl.initializer;
1820
+ const member = ts.isPropertyAccessExpression(initializer) ? nsMemberIdentOf(lowerer, initializer) : null;
1821
+ const generic = member && lowerer.genericFnOf(member);
1822
+ const fallback = (ts.isArrowFunction(initializer) || ts.isFunctionExpression(initializer)) && !initializer.typeParameters?.length
1823
+ ? lowerer.lambdaSignature(initializer).funcType
1824
+ : member && lowerer.globalOf(member)?.type.kind === "dyn" ? DYN
1825
+ : member && generic?.implicitParams ? lowerer.lowerGenericFnValue(member, generic).type
1826
+ : dynFallbackType(lowerer, nameNode, lowerer.typeOf(nameNode));
1653
1827
  const symbol = lowerer.checker.getSymbolAtLocation(nameNode);
1654
- if (symbol && fallback && (fallback.kind === "func" || fallback.kind === "union") && lowerer.dynConvertible(fallback)) {
1828
+ if (symbol && fallback && (fallback.kind === "dyn" || fallback.kind === "func" || fallback.kind === "union") && lowerer.dynConvertible(fallback)) {
1655
1829
  if (!lowerer.globalsBySymbol.has(symbol)) {
1656
1830
  const g = {
1657
1831
  id: `%g.${tag}${nsPrefix}${nameNode.text}`, name: nameNode.text,
@@ -1691,7 +1865,30 @@ export function collectGlobals(lowerer, sf, topStmts) {
1691
1865
  // exactly the local rule (uncheckedOverloadHandleCall).
1692
1866
  (uncheckedOverloadHandleCall(lowerer, decl.initializer) ? JSVAL : null) : null)
1693
1867
  : null;
1694
- let type = handleT ?? factoryType ?? lowerer.irTypeOf(nameNode);
1868
+ // Unannotated results of JavaScript calls can carry callable
1869
+ // objects or heterogeneous unions absent from the native type
1870
+ // map. Their compiled initializer still validates every crossing.
1871
+ const callSignature = !decl.type && !hasJsTypeAnnotation(decl) && decl.initializer && ts.isCallExpression(decl.initializer)
1872
+ ? lowerer.checker.getResolvedSignature(decl.initializer) : undefined;
1873
+ const callDeclaration = callSignature && lowerer.checker.signatureDeclaration(callSignature);
1874
+ const inferredJsCall = callDeclaration && isJsSourceFile(callDeclaration.getSourceFile()) &&
1875
+ !lowerer.mapTypeOf(lowerer.typeOf(nameNode));
1876
+ let type = handleT ?? factoryType ?? (inferredJsCall ? DYN : lowerer.irTypeOf(nameNode));
1877
+ if (isJsSourceFile(sf) && !decl.type && !hasJsTypeAnnotation(decl) && decl.initializer &&
1878
+ (ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer)) &&
1879
+ !decl.initializer.typeParameters?.length) {
1880
+ type = lowerer.lambdaSignature(decl.initializer).funcType;
1881
+ }
1882
+ if (isJsSourceFile(sf) && !decl.type && !hasJsTypeAnnotation(decl) &&
1883
+ decl.initializer && ts.isCallExpression(decl.initializer) && type.kind === "union") {
1884
+ const arms = lowerer.unions.get(type.unionId)?.arms;
1885
+ if (arms?.some((arm) => arm.kind === "record") && arms.every((arm) => isUnitType(arm) || arm.kind === "record"))
1886
+ type = DYN;
1887
+ }
1888
+ if (isJsSourceFile(sf) && !decl.type && !hasJsTypeAnnotation(decl) && decl.initializer &&
1889
+ ts.isNewExpression(decl.initializer) && lowerer.mapTypeOf(lowerer.typeOf(decl.initializer.expression))?.kind === "dyn" &&
1890
+ !(ts.isIdentifier(decl.initializer.expression) && lowerer.isStdlibSymbol(lowerer.checker.getSymbolAtLocation(decl.initializer.expression))))
1891
+ type = DYN;
1695
1892
  // Calls through checked function values retain their object
1696
1893
  // identity, including symbol keys absent from inferred records.
1697
1894
  if (isJsSourceFile(sf) && !decl.type && !hasJsTypeAnnotation(decl) && type.kind === "record" &&
@@ -1711,6 +1908,9 @@ export function collectGlobals(lowerer, sf, topStmts) {
1711
1908
  // a fixed-signature adapter to reconstruct its hidden rest ABI.
1712
1909
  if (!decl.type && !hasJsTypeAnnotation(decl) && type.kind === "func" && type.rest === true && type.restAbi === undefined)
1713
1910
  type = DYN;
1911
+ if (isJsSourceFile(sf) && isLet && !decl.type && !hasJsTypeAnnotation(decl) &&
1912
+ (type.kind === "object" || jsBindingHasOpenWrites(lowerer, decl)))
1913
+ type = DYN;
1714
1914
  // JavaScript call results may retain a checked array supplied by
1715
1915
  // the caller. A typed global here would copy it on extraction.
1716
1916
  if (isJsSourceFile(sf) && !decl.type && !hasJsTypeAnnotation(decl) && type.kind === "array" &&
@@ -1793,8 +1993,7 @@ export function collectGlobals(lowerer, sf, topStmts) {
1793
1993
  // adapter would re-copy at the assignment.
1794
1994
  if (isJsSourceFile(sf) &&
1795
1995
  type.kind === "func" &&
1796
- type.ret.kind === "record" &&
1797
- lowerer.dynConvertible(type.ret) &&
1996
+ (type.ret.kind === "date" || type.ret.kind === "record" && lowerer.dynConvertible(type.ret)) &&
1798
1997
  decl.initializer !== undefined &&
1799
1998
  (ts.isFunctionExpression(decl.initializer) || ts.isArrowFunction(decl.initializer)) &&
1800
1999
  decl.initializer.type === undefined &&
@@ -1811,6 +2010,10 @@ export function collectGlobals(lowerer, sf, topStmts) {
1811
2010
  type = DYN;
1812
2011
  }
1813
2012
  // Module vars hold real undefined until their declaration runs.
2013
+ // Unannotated JS function values need that state too: callers
2014
+ // before the initializer must see undefined and a TypeError.
2015
+ if (isJsSourceFile(sf) && isVarDeclared(decl) && type.kind === "func" && lowerer.dynConvertible(type))
2016
+ type = DYN;
1814
2017
  // Codec records keep that state in the ordinary optional union;
1815
2018
  // lexical codec declarations retain their separate TDZ guard.
1816
2019
  const codec = type.kind === "record" && recordTextCodecClass(lowerer.shapes.get(type.shapeId)) !== null;
@@ -2214,7 +2417,7 @@ export function lowerFileInit(lowerer, sf, stmts, name) {
2214
2417
  // SITE's position instead (below) — their inner class node may
2215
2418
  // even live in another file.
2216
2419
  c.decl && ts.isClassDeclaration(c.decl) && !c.mixinInstance && c.decl.getSourceFile() === sf &&
2217
- (c.callableBase !== undefined || c.staticFields.length > 0 || (c.staticBlocks?.length ?? 0) > 0 || c.classDecorators !== undefined))
2420
+ (c.callableBase !== undefined || c.def.baseValueGlobal !== undefined || c.staticFields.length > 0 || (c.staticBlocks?.length ?? 0) > 0 || c.classDecorators !== undefined))
2218
2421
  .map((c) => ({ pos: c.decl.getStart(), info: c }));
2219
2422
  // Statics-bearing MIXIN instantiations whose call evaluates in THIS
2220
2423
  // file: their declaration-time code runs when the call does — the