@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
@@ -1,6 +1,9 @@
1
1
  import * as ts from "../ts7/adapter.js";
2
2
  import type { Lowerer } from "./lowerer.js";
3
3
  import { type IrExpr, type IrFunction, type IrRecordShape, type IrStmt, type IrType, type SrcLoc } from "../../ir/ir.js";
4
+ /** Object() and new Object() preserve known object inputs. Primitive
5
+ * boxing and unproven checked-dynamic values retain their refusal. */
6
+ export declare function lowerObjectConstructor(lowerer: Lowerer, args: readonly ts.Expression[], loc: SrcLoc): IrExpr | null;
4
7
  /** Ambient array method calls. `push`/`unshift`/`pop`/`reverse`/
5
8
  * `indexOf`/`includes`/`join`
6
9
  * lower to arrIntrinsic; the HOF family — `map`/`filter`/`forEach`/
@@ -29,6 +32,12 @@ export declare const lowerNpmStaticSafeIndexRead: typeof lowerSafeIndexRead;
29
32
  export declare function lowerArrayConstructor(lowerer: Lowerer, expr: ts.CallExpression | ts.NewExpression, args: readonly ts.Expression[]): IrExpr;
30
33
  /** `Array.of` creates an array of its arguments, including a lone number. */
31
34
  export declare function lowerArrayOfCall(lowerer: Lowerer, call: ts.CallExpression, access: ts.PropertyAccessExpression): IrExpr | null;
35
+ /** Mapper-less checked Array.from: acquire once, then step through emitted
36
+ * property and call dispatch so native class iterators retain their methods. */
37
+ export declare function lowerCheckedArrayFrom(lowerer: Lowerer, source: IrExpr, loc: SrcLoc, mapper?: IrExpr, receiver?: IrExpr, numeric?: boolean): Extract<IrExpr, {
38
+ kind: "seqExpr";
39
+ }>;
40
+ export declare function lowerArrayFromValue(lowerer: Lowerer, loc: SrcLoc): IrExpr;
32
41
  /** `Array.from({ length: n }, mapfn)` — the counted-generation idiom — on
33
42
  * THE stdlib Array global. The source must be an OBJECT LITERAL whose
34
43
  * single property is `length` (the shape the idiom always spells; the
@@ -14,10 +14,25 @@ import { islandPrimitiveExit, lowerDynDispatchMethodCall } from "./lower-calls.j
14
14
  import { buildArraySortFn } from "./lower-array-sort.js";
15
15
  import { arrayIndexPresent, arrayValueRead, arrayValueStore, arrayValueType, currentArrayIndexPresent } from "./array-values.js";
16
16
  import { typeKey } from "../type-mapper.js";
17
- import { nodeThrowExpr } from "./lowerer.js";
17
+ import { dynUndefinedExpr, newFnCtx, nodeThrowExpr } from "./lowerer.js";
18
18
  import { boolLit, countedFor, numLit, strLit, varRef } from "../../ir/build.js";
19
19
  import { defaultAfterUndefined, lowerPositionArgument, lowerStaticallyUndefinedArgument, positionNumber } from "./optional-arguments.js";
20
20
  import { lowerArrayCopyWithin, lowerArrayFill } from "./array-indexed-mutation.js";
21
+ /** Object() and new Object() preserve known object inputs. Primitive
22
+ * boxing and unproven checked-dynamic values retain their refusal. */
23
+ export function lowerObjectConstructor(lowerer, args, loc) {
24
+ if (args.length === 0) {
25
+ return { kind: "recordLit", fields: [], type: { kind: "record", shapeId: lowerer.shapes.intern([]) }, loc };
26
+ }
27
+ if (args.length !== 1 || ts.isSpreadElement(args[0]))
28
+ return null;
29
+ const value = lowerer.lowerExpr(args[0]);
30
+ if (value.kind === "dynObjLit" || value.kind === "dynArrLit")
31
+ return value;
32
+ if (["record", "array", "object", "regex", "date", "bytes", "map", "set", "func", "classval"].includes(value.type.kind))
33
+ return value;
34
+ return null;
35
+ }
21
36
  function primitivePositionType(lowerer, type) {
22
37
  if (type.kind === "union") {
23
38
  return lowerer.unions.get(type.unionId)?.arms.every((arm) => primitivePositionType(lowerer, arm)) ?? false;
@@ -144,9 +159,6 @@ function lowerArrayJoinSeparator(lowerer, node, loc) {
144
159
  * directly from its IR return type. Fence element kinds ScrArr cannot hold
145
160
  * before constructing that array type. */
146
161
  function fenceProducedArrayElem(lowerer, node, producer, elem) {
147
- if (elem.kind === "dyn") {
148
- lowerer.unsupported("SC1090", node, `${producer} with a callback returning 'unknown'-typed values (the result array has no static element type — annotate the callback's return)`);
149
- }
150
162
  if (!isSupportedArrayElem(elem)) {
151
163
  lowerer.unsupported("SC1090", node, `${producer} with a callback returning '${lowerer.fmt(elem)}' values (arrays of this element kind have no representation — store the values individually)`);
152
164
  }
@@ -545,7 +557,12 @@ export function lowerArrayMethodCall(lowerer, call, access) {
545
557
  // IsArray says spread; no honest static answer exists.
546
558
  lowerer.unsupported("SC1090", argNode, "concat of a bare inner array onto an array-of-arrays (JS would SPREAD it one level — wrap it: a.concat([inner]))");
547
559
  }
548
- const arg = lowerer.lowerExpr(argNode);
560
+ // Declaration-backed JS methods can return checked values even
561
+ // when their public signature names a concrete array. Validate
562
+ // that boundary before spreading the represented elements.
563
+ let arg = lowerer.lowerExpr(argNode);
564
+ if (arg.type.kind === "dyn")
565
+ arg = lowerer.coerceInto(argNode, arg, argArrayType);
549
566
  if (arg.type.kind !== "array")
550
567
  lowerer.badType(argNode, lowerer.typeOf(argNode));
551
568
  shape.push("a");
@@ -615,6 +632,12 @@ export function lowerArrayMethodCall(lowerer, call, access) {
615
632
  return { kind: "arrIntrinsic", method: "shift", receiver, args: [], type: arrayValueType(lowerer, elem), loc };
616
633
  }
617
634
  if (name === "join") {
635
+ if (elem.kind === "dyn") {
636
+ const receiver = lowerer.coerceToExpected(lowerer.lowerExpr(access.expression), DYN);
637
+ const args = call.arguments.length ? [lowerer.lowerExprExpecting(call.arguments[0], DYN)] : [];
638
+ return lowerer.coerceToExpected({ kind: "dynInvoke", recv: receiver, method: "join",
639
+ calleeName: access.getText(), args, type: DYN, loc }, STRING);
640
+ }
618
641
  // The ambient declares join on every Array<T> (a per-element-type
619
642
  // interface split isn't expressible there), so string-convertible
620
643
  // elements are enforced here: nested arrays would need JS's recursive
@@ -1686,6 +1709,9 @@ export function lowerTupleReadMethodCall(lowerer, call, access, tupleReceiver) {
1686
1709
  const ret = fnArg.type.ret;
1687
1710
  if (ret.kind === "void" || ret.kind === "func")
1688
1711
  lowerer.badType(call, lowerer.typeOf(call));
1712
+ if (method === "flatMap" && (ret.kind === "dyn" || ret.kind === "jsval" || (ret.kind === "record" && lowerer.shapes.get(ret.shapeId)?.tuple))) {
1713
+ return { kind: "dynInvoke", recv: { kind: "dynFrom", value: receiver, type: DYN, loc }, method: "flatMap", calleeName: access.getText(), args: [{ kind: "dynFrom", value: fnArg, type: DYN, loc }], type: DYN, loc };
1714
+ }
1689
1715
  if (method === "flatMap" && ret.kind === "union" && lowerer.unions.get(ret.unionId).arms.some(arm => arm.kind === "array")) {
1690
1716
  lowerer.noLowering("tuple .flatMap callback mixing array and scalar results", callback, "return an array from every path");
1691
1717
  }
@@ -1975,8 +2001,7 @@ function buildArrayHofFn(lowerer, name, method, elem, fnRet, arity, loc, outElem
1975
2001
  * undefined unit arm (for REF elements that arm is the unit instance, the
1976
2002
  * standard union machinery). The Last pair is the SAME loop walked
1977
2003
  * backwards (`i = n - 1; i >= 0; i--`), exactly the es2023 spec's
1978
- * descending index walk. All require a bool-returning callback
1979
- * (JS's ToBoolean of arbitrary predicate results has no lowering). */
2004
+ * descending index walk. Predicate results use JavaScript ToBoolean. */
1980
2005
  function lowerArrayFindLikeCall(lowerer, call, access, method, elem, bindUntyped = false) {
1981
2006
  const loc = locOf(call);
1982
2007
  const receiver = lowerer.lowerExpr(access.expression);
@@ -1991,7 +2016,7 @@ function lowerArrayFindLikeCall(lowerer, call, access, method, elem, bindUntyped
1991
2016
  // `packages.some((p) => p.scripts[name])` idiom, whose callback
1992
2017
  // returns the index read's `string | undefined`).
1993
2018
  const fnRet = fnArg.type.ret;
1994
- const truthyRet = fnRet.kind === "bool" || fnRet.kind === "f64" || fnRet.kind === "string" ||
2019
+ const truthyRet = fnRet.kind === "bool" || fnRet.kind === "f64" || fnRet.kind === "string" || fnRet.kind === "dyn" ||
1995
2020
  (fnRet.kind === "union" &&
1996
2021
  (lowerer.unions.get(fnRet.unionId)?.arms ?? []).every((a) => a.kind !== "dyn" && a.kind !== "caught" && a.kind !== "jsval"));
1997
2022
  if (!truthyRet)
@@ -2044,11 +2069,13 @@ function lowerArrayFindLikeCall(lowerer, call, access, method, elem, bindUntyped
2044
2069
  return { kind: "call", callee: helper, args: [receiver, fnArg], type: resultT, loc };
2045
2070
  }
2046
2071
  /** ToBoolean of a predicate result inside a synthesized HOF helper — the
2047
- * ensureBool subset the find-like path admits (bool through; f64/string/
2048
- * truthy-answerable unions via toBool). */
2072
+ * ensureBool subset the find-like path admits (bool through; checked
2073
+ * values via dynTest; f64/string/truthy-answerable unions via toBool). */
2049
2074
  function predToBool(e) {
2050
2075
  if (e.type.kind === "bool")
2051
2076
  return e;
2077
+ if (e.type.kind === "dyn")
2078
+ return { kind: "dynTest", test: "truthy", value: e, type: BOOL, loc: e.loc };
2052
2079
  return { kind: "toBool", operand: e, type: BOOL, loc: e.loc };
2053
2080
  }
2054
2081
  /** The find loop, from existing IR nodes:
@@ -2250,6 +2277,9 @@ function lowerArrayFlatMapCall(lowerer, call, access, elem) {
2250
2277
  lowerer.unsupported("SC1090", call, "this call form"); // tsc-guarded
2251
2278
  const { fnArg, arity } = hofCallbackArg(lowerer, argNode, [arrayValueType(lowerer, elem)], arrT);
2252
2279
  const fnRet = fnArg.type.ret;
2280
+ if (fnRet.kind === "dyn" || fnRet.kind === "jsval" || (fnRet.kind === "record" && lowerer.shapes.get(fnRet.shapeId)?.tuple)) {
2281
+ return { kind: "dynInvoke", recv: { kind: "dynFrom", value: receiver, liveRef: true, type: DYN, loc }, method: "flatMap", calleeName: access.getText(), args: [{ kind: "dynFrom", value: fnArg, type: DYN, loc }], type: DYN, loc };
2282
+ }
2253
2283
  if (fnRet.kind === "union") {
2254
2284
  const def = lowerer.unions.get(fnRet.unionId);
2255
2285
  if (def?.arms.some((a) => a.kind === "array")) {
@@ -2866,31 +2896,82 @@ export function lowerArrayOfCall(lowerer, call, access) {
2866
2896
  }
2867
2897
  /** Mapper-less checked Array.from: acquire once, then step through emitted
2868
2898
  * property and call dispatch so native class iterators retain their methods. */
2869
- function lowerCheckedArrayFrom(lowerer, source, loc) {
2899
+ export function lowerCheckedArrayFrom(lowerer, source, loc, mapper, receiver, numeric = false) {
2870
2900
  const iterator = lowerer.declareHiddenLocal("%fromIterator", DYN);
2871
2901
  const next = lowerer.declareHiddenLocal("%fromNext", DYN);
2872
2902
  const step = lowerer.declareHiddenLocal("%fromStep", DYN);
2873
2903
  const out = lowerer.declareHiddenLocal("%fromArray", DYN);
2874
2904
  const done = lowerer.declareHiddenLocal("%fromDone", BOOL);
2875
2905
  done.mutable = true;
2906
+ const index = mapper ? lowerer.declareHiddenLocal("%fromIndex", F64) : null;
2907
+ if (index)
2908
+ index.mutable = true;
2876
2909
  const get = (value, key) => ({ kind: "dynKeyGet", value, key: strLit(key, loc), type: DYN, loc });
2910
+ const item = get(varRef(step.id, DYN, loc), "value");
2911
+ const mapped = mapper && index ? { kind: "ternary", cond: { kind: "dynTest", test: "undefined", value: mapper, type: BOOL, loc },
2912
+ then: item, else_: { kind: "dynCall", callee: mapper, ...(receiver ? { receiver } : {}), calleeName: "Array.from mapper", args: [item, lowerer.coerceToExpected(varRef(index.id, F64, loc), DYN)], type: DYN, loc }, type: DYN, loc } : item;
2913
+ const element = numeric ? lowerer.coerceToExpected({ kind: "libCall", fn: "dyn.toNumberCoerce", args: [mapped], type: F64, loc }, DYN) : mapped;
2914
+ let append = { kind: "exprStmt", expr: { kind: "dynInvoke", recv: varRef(out.id, DYN, loc), method: "push", calleeName: "Array.from", args: [element], type: DYN, loc }, loc };
2915
+ if (mapper) {
2916
+ const error = lowerer.declareHiddenLocal("%fromError", CAUGHT);
2917
+ const close = lowerer.declareHiddenLocal("%fromReturn", DYN);
2918
+ append = { kind: "tryCatch", tryBody: [append], catchLocalId: error.id, finallyBody: null, loc, catchBody: [
2919
+ { kind: "tryCatch", catchLocalId: null, catchBody: [], finallyBody: null, loc, tryBody: [
2920
+ { kind: "varDecl", localId: close.id, init: get(varRef(iterator.id, DYN, loc), "return"), loc },
2921
+ { kind: "if", cond: { kind: "dynTest", test: "function", value: varRef(close.id, DYN, loc), type: BOOL, loc }, then: [
2922
+ { kind: "exprStmt", expr: { kind: "dynCall", callee: varRef(close.id, DYN, loc), receiver: varRef(iterator.id, DYN, loc), calleeName: "iterator.return", args: [], type: DYN, loc }, loc },
2923
+ ], else_: null, loc },
2924
+ ] },
2925
+ { kind: "rethrow", localId: error.id, loc },
2926
+ ] };
2927
+ }
2877
2928
  const stmts = [
2929
+ ...(mapper ? [{ kind: "if", cond: { kind: "dynTest", test: "undefined", value: mapper, type: BOOL, loc }, then: [], else_: [
2930
+ { kind: "if", cond: { kind: "dynTest", test: "function", value: mapper, type: BOOL, loc }, then: [], else_: [
2931
+ { kind: "exprStmt", expr: nodeThrowExpr(1, "", "Array.from mapper is not a function", DYN, loc), loc },
2932
+ ], loc },
2933
+ ], loc }] : []),
2878
2934
  { kind: "varDecl", localId: iterator.id, init: { kind: "libCall", fn: "dyn.iteratorResult", args: [{ kind: "libCall", fn: "dyn.arrayFromIterator", args: [source], type: DYN, loc }], type: DYN, loc }, loc },
2879
2935
  { kind: "varDecl", localId: next.id, init: get(varRef(iterator.id, DYN, loc), "next"), loc },
2880
2936
  { kind: "varDecl", localId: out.id, init: { kind: "dynArrLit", elems: [], type: DYN, loc }, loc },
2881
2937
  { kind: "varDecl", localId: done.id, init: boolLit(false, loc), loc },
2938
+ ...(index ? [{ kind: "varDecl", localId: index.id, init: numLit(0, loc), loc }] : []),
2882
2939
  { kind: "while", cond: { kind: "unary", op: "!", operand: varRef(done.id, BOOL, loc), type: BOOL, loc }, body: [
2883
2940
  { kind: "varDecl", localId: step.id, init: { kind: "libCall", fn: "dyn.iteratorResult", args: [{
2884
2941
  kind: "dynCall", callee: varRef(next.id, DYN, loc), receiver: varRef(iterator.id, DYN, loc), calleeName: "iterator.next", args: [], type: DYN, loc,
2885
2942
  }], type: DYN, loc }, loc },
2886
2943
  { kind: "assign", localId: done.id, value: { kind: "dynTest", test: "truthy", value: get(varRef(step.id, DYN, loc), "done"), type: BOOL, loc }, loc },
2887
2944
  { kind: "if", cond: { kind: "unary", op: "!", operand: varRef(done.id, BOOL, loc), type: BOOL, loc }, then: [
2888
- { kind: "exprStmt", expr: { kind: "dynInvoke", recv: varRef(out.id, DYN, loc), method: "push", calleeName: "Array.from", args: [get(varRef(step.id, DYN, loc), "value")], type: DYN, loc }, loc },
2945
+ append,
2946
+ ...(index ? [{ kind: "assign", localId: index.id, value: { kind: "bin", op: "+", left: varRef(index.id, F64, loc), right: numLit(1, loc), type: F64, loc }, loc }] : []),
2889
2947
  ], else_: null, loc },
2890
2948
  ], loc },
2891
2949
  ];
2892
2950
  return { kind: "seqExpr", stmts, result: varRef(out.id, DYN, loc), type: DYN, loc };
2893
2951
  }
2952
+ export function lowerArrayFromValue(lowerer, loc) {
2953
+ const name = "%builtin.Array.from";
2954
+ if (!lowerer.liftedFns.some((fn) => fn.name === name)) {
2955
+ const context = newFnCtx(false, null, null, DYN);
2956
+ lowerer.fnStack.push(context);
2957
+ try {
2958
+ const params = ["source", "options"].map((name) => {
2959
+ const local = lowerer.declareHiddenLocal(name, DYN);
2960
+ return { localId: local.id, name, type: DYN };
2961
+ });
2962
+ const [source, options] = params.map((p) => varRef(p.localId, DYN, loc));
2963
+ const argument = (index) => ({ kind: "dynKeyGet", value: options, key: strLit(index, loc), type: DYN, loc });
2964
+ const value = lowerCheckedArrayFrom(lowerer, source, loc, argument("0"), argument("1"));
2965
+ const constructorCheck = { kind: "if", cond: { kind: "dynTest", test: "function", value: { kind: "libCall", fn: "dyn.this", args: [], type: DYN, loc }, type: BOOL, loc },
2966
+ then: [{ kind: "runtimeFence", code: "SC2020", message: "Array.from with a custom constructor receiver is not supported", loc }], else_: null, loc };
2967
+ lowerer.liftedFns.push({ name, params, returnType: DYN, locals: context.locals, body: [constructorCheck, ...value.stmts, { kind: "return", value: value.result, loc }], loc });
2968
+ }
2969
+ finally {
2970
+ lowerer.fnStack.pop();
2971
+ }
2972
+ }
2973
+ return { kind: "dynFrom", value: { kind: "closure", fnName: name, captures: [], type: { kind: "func", params: [DYN], ret: DYN, rest: true }, loc }, fnName: "from", type: DYN, loc };
2974
+ }
2894
2975
  /** `Array.from({ length: n }, mapfn)` — the counted-generation idiom — on
2895
2976
  * THE stdlib Array global. The source must be an OBJECT LITERAL whose
2896
2977
  * single property is `length` (the shape the idiom always spells; the
@@ -2914,6 +2995,28 @@ export function lowerArrayFromCall(lowerer, call, access) {
2914
2995
  return null;
2915
2996
  const loc = locOf(call);
2916
2997
  const args = call.arguments;
2998
+ if (isJsSourceFile(call.getSourceFile()) && args.length >= 1 && args.length <= 3 && !args.some(ts.isSpreadElement)) {
2999
+ const name = "%builtin.Array.fromDirect";
3000
+ if (!lowerer.liftedFns.some((fn) => fn.name === name)) {
3001
+ const context = newFnCtx(false, null, null, DYN);
3002
+ lowerer.fnStack.push(context);
3003
+ try {
3004
+ const params = ["source", "mapper", "receiver"].map((name) => {
3005
+ const local = lowerer.declareHiddenLocal(name, DYN);
3006
+ return { localId: local.id, name, type: DYN };
3007
+ });
3008
+ const refs = params.map((param) => varRef(param.localId, DYN, loc));
3009
+ const value = lowerCheckedArrayFrom(lowerer, refs[0], loc, refs[1], refs[2]);
3010
+ lowerer.liftedFns.push({ name, params, returnType: DYN, locals: context.locals,
3011
+ body: [...value.stmts, { kind: "return", value: value.result, loc }], loc });
3012
+ }
3013
+ finally {
3014
+ lowerer.fnStack.pop();
3015
+ }
3016
+ }
3017
+ return { kind: "call", callee: name, args: [0, 1, 2].map((i) => args[i]
3018
+ ? lowerer.lowerExprExpecting(args[i], DYN) : dynUndefinedExpr(loc)), type: DYN, loc };
3019
+ }
2917
3020
  // MAPPER-LESS `Array.from({ length: n })` (usually with an explicit
2918
3021
  // type argument — the pMap results-array idiom): a length-n array of
2919
3022
  // ABSENT slots, filled by index before any read. Union elements with
@@ -3225,14 +3328,11 @@ export function lowerMapMethodCall(lowerer, call, access) {
3225
3328
  if (receiverIr?.kind !== "map")
3226
3329
  return null;
3227
3330
  // Collection views can refine has() while retaining its native ABI.
3228
- if (!lowerer.isStdlibMember(access) && name !== "has")
3331
+ if (!probedUntyped && !lowerer.isStdlibMember(access) && name !== "has")
3229
3332
  return null;
3230
3333
  const loc = locOf(call);
3231
3334
  const value = lowerer.lowerExpr(access.expression);
3232
3335
  const receiver = lowerer.runtimeOptionalPropertyReceiver(access.expression, value, receiverIr, name) ?? value;
3233
- // The lib's `set` returns the Map (chaining typechecks); the lowered
3234
- // set is a void statement, so a chained receiver has no value — fence
3235
- // it instead of emitting a void receiver.
3236
3336
  if (receiver.type.kind !== "map") {
3237
3337
  lowerer.noLowering("chained Map method calls", access.expression, "the lowered set() produces no value — call each set(k, v) as its own statement");
3238
3338
  }
@@ -3256,7 +3356,12 @@ export function lowerMapMethodCall(lowerer, call, access) {
3256
3356
  const v = receiverIr.value.kind === "dyn"
3257
3357
  ? lowerer.lowerCollectionKey(call.arguments[1], receiverIr.value)
3258
3358
  : lowerer.lowerExprExpecting(call.arguments[1], receiverIr.value);
3259
- return { kind: "mapIntrinsic", method: "set", receiver, args: [k, v], type: VOID, loc };
3359
+ const slot = lowerer.declareHiddenLocal("%mapSetReceiver", receiver.type);
3360
+ const ref = varRef(slot.id, receiver.type, loc);
3361
+ return { kind: "seqExpr", stmts: [
3362
+ { kind: "varDecl", localId: slot.id, init: receiver, loc },
3363
+ { kind: "exprStmt", expr: { kind: "mapIntrinsic", method: "set", receiver: ref, args: [k, v], type: VOID, loc }, loc },
3364
+ ], result: ref, type: receiver.type, loc };
3260
3365
  }
3261
3366
  if (name === "has" || name === "delete") {
3262
3367
  const k = lowerer.lowerCollectionKey(call.arguments[0], receiverIr.key);
@@ -3612,21 +3717,24 @@ export function lowerSetMethodCall(lowerer, call, access) {
3612
3717
  if (!SET_METHODS.has(name) && !SET_COMBINE_METHODS.has(name))
3613
3718
  return null;
3614
3719
  let receiverIr = lowerer.mapTypeOf(lowerer.typeOf(access.expression));
3720
+ let probedUntyped = false;
3615
3721
  // The identity-Set idiom (JS): the CHECKER type is an unmappable
3616
3722
  // Set<union-of-signatures>, but the VALUE lowered as a real Set of
3617
3723
  // identity tokens (the new-Set probe) — the lowered receiver's type
3618
3724
  // is the honest dispatch key.
3619
3725
  if (receiverIr?.kind !== "set" && isJsSourceFile(access.getSourceFile())) {
3620
3726
  const probed = tryLowerExpression(lowerer, access.expression);
3621
- if (probed?.type.kind === "set")
3727
+ if (probed?.type.kind === "set") {
3622
3728
  receiverIr = probed.type;
3729
+ probedUntyped = true;
3730
+ }
3623
3731
  }
3624
3732
  if (receiverIr?.kind !== "set")
3625
3733
  return null;
3626
3734
  // A collection interface may refine has() into a type predicate.
3627
3735
  // Type mapping checked that view's native ABI; the value check below
3628
3736
  // still rejects structural mocks and assertions over other objects.
3629
- if (!lowerer.isStdlibMember(access) && name !== "has")
3737
+ if (!probedUntyped && !lowerer.isStdlibMember(access) && name !== "has")
3630
3738
  return null;
3631
3739
  const loc = locOf(call);
3632
3740
  const value = lowerer.lowerExpr(access.expression);
@@ -5067,22 +5175,12 @@ function lowerForOfMapOrSet(lowerer, stmt, iterable, contT, proj) {
5067
5175
  }
5068
5176
  }
5069
5177
  else {
5070
- // Identifier heads and the remaining patterns bind through the
5071
- // checker's own element type — the [K, V] tuple for pair yields,
5072
- // T otherwise — built/read once into a hidden per-iteration
5073
- // local, the array for-of's exact desugar.
5074
- const elemT = lowerer.mapTypeOf(lowerer.checker.getTypeAtLocation(decl.name));
5075
- if (yieldsPair) {
5076
- const shape = elemT?.kind === "record" ? lowerer.shapes.get(elemT.shapeId) : null;
5077
- if (elemT?.kind !== "record" || !shape?.tuple || shape.fields.length !== 2 ||
5078
- !typeEquals(shape.fields.find((f) => f.name === "0").type, keyT) ||
5079
- !typeEquals(shape.fields.find((f) => f.name === "1").type, secondT)) {
5080
- lowerer.badType(decl.name, lowerer.checker.getTypeAtLocation(decl.name)); // defensive: the lib declares [K, V]
5081
- }
5082
- }
5083
- else if (!elemT || !typeEquals(elemT, singleT)) {
5084
- lowerer.badType(decl.name, lowerer.checker.getTypeAtLocation(decl.name)); // defensive: the lib declares T
5085
- }
5178
+ // Derive the yielded layout from the represented container. JS
5179
+ // inference can leave the pattern at any even when the Map's
5180
+ // native key/value types are known after specialization.
5181
+ const elemT = yieldsPair
5182
+ ? { kind: "record", shapeId: lowerer.shapes.intern([{ name: "0", type: keyT }, { name: "1", type: secondT }], true) }
5183
+ : singleT;
5086
5184
  const elemInit = yieldsPair
5087
5185
  ? {
5088
5186
  kind: "recordLit",
@@ -5447,7 +5545,8 @@ function mapFromSeedValue(lowerer, seed, mapT) {
5447
5545
  }
5448
5546
  return { kind: "call", callee: name, args: [seed], type: mapT, loc };
5449
5547
  }
5450
- if (seed.type.kind === "dyn" || seed.type.kind === "array" && seed.type.elem.kind === "dyn") {
5548
+ if (seed.type.kind === "dyn" || seed.type.kind === "array" &&
5549
+ (seed.type.elem.kind === "dyn" || seed.type.elem.kind === "array")) {
5451
5550
  const key = `checked-seed:${typeKey(mapT)}`;
5452
5551
  let name = lowerer.mapHofHelpers.get(key);
5453
5552
  if (!name) {