@scriptc/compiler 0.0.11 → 0.0.13

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 (97) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +153 -24
  2. package/ambient/scriptc.d.ts +2 -2
  3. package/dist/backend/cc.d.ts +10 -2
  4. package/dist/backend/cc.js +12 -0
  5. package/dist/backend/cc.js.map +1 -1
  6. package/dist/backend/emission/emit-async.js +1 -1
  7. package/dist/backend/emission/emit-exprs.js +235 -64
  8. package/dist/backend/emission/emit-exprs.js.map +1 -1
  9. package/dist/backend/emission/emit-island.js +1 -1
  10. package/dist/backend/emission/emit-shapes.js +1 -1
  11. package/dist/backend/emission/emit-walkers.d.ts +14 -14
  12. package/dist/backend/emission/emit-walkers.js +44 -44
  13. package/dist/backend/emission/emit-walkers.js.map +1 -1
  14. package/dist/backend/emission/emitter.d.ts +3 -3
  15. package/dist/backend/emission/emitter.js +8 -8
  16. package/dist/backend/emission/may-throw.js +1 -1
  17. package/dist/backend/llvm/dyn.d.ts +10 -10
  18. package/dist/backend/llvm/dyn.js +26 -26
  19. package/dist/backend/llvm/dyn.js.map +1 -1
  20. package/dist/backend/llvm/emitter.js +140 -49
  21. package/dist/backend/llvm/emitter.js.map +1 -1
  22. package/dist/backend/llvm/shapes.js +1 -1
  23. package/dist/backend/llvm/walkers.js +2 -2
  24. package/dist/backend/llvm/walkers.js.map +1 -1
  25. package/dist/diagnostics/diagnostic.d.ts +1 -1
  26. package/dist/diagnostics/diagnostic.js +4 -3
  27. package/dist/diagnostics/diagnostic.js.map +1 -1
  28. package/dist/frontend/lowering/crypto-tables.d.ts +7 -0
  29. package/dist/frontend/lowering/crypto-tables.js +139 -0
  30. package/dist/frontend/lowering/crypto-tables.js.map +1 -0
  31. package/dist/frontend/lowering/lib-boundary.js +5 -5
  32. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  33. package/dist/frontend/lowering/lower-assert.js +12 -12
  34. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  35. package/dist/frontend/lowering/lower-builtins.d.ts +45 -27
  36. package/dist/frontend/lowering/lower-builtins.js +203 -70
  37. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  38. package/dist/frontend/lowering/lower-calls.d.ts +4 -4
  39. package/dist/frontend/lowering/lower-calls.js +74 -66
  40. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  41. package/dist/frontend/lowering/lower-classes.js +41 -7
  42. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  43. package/dist/frontend/lowering/lower-containers.d.ts +5 -5
  44. package/dist/frontend/lowering/lower-containers.js +19 -19
  45. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  46. package/dist/frontend/lowering/lower-emitter.js +2 -2
  47. package/dist/frontend/lowering/lower-emitter.js.map +1 -1
  48. package/dist/frontend/lowering/lower-exprs.d.ts +7 -7
  49. package/dist/frontend/lowering/lower-exprs.js +227 -119
  50. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  51. package/dist/frontend/lowering/lower-inspect.js +5 -5
  52. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  53. package/dist/frontend/lowering/lower-island.js +12 -3
  54. package/dist/frontend/lowering/lower-island.js.map +1 -1
  55. package/dist/frontend/lowering/lower-modules.js +17 -17
  56. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  57. package/dist/frontend/lowering/lower-namespaces.d.ts +11 -1
  58. package/dist/frontend/lowering/lower-namespaces.js +41 -6
  59. package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
  60. package/dist/frontend/lowering/lower-server.d.ts +21 -0
  61. package/dist/frontend/lowering/lower-server.js +278 -23
  62. package/dist/frontend/lowering/lower-server.js.map +1 -1
  63. package/dist/frontend/lowering/lower-stmts.d.ts +1 -1
  64. package/dist/frontend/lowering/lower-stmts.js +195 -34
  65. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  66. package/dist/frontend/lowering/lower-stream.js +67 -23
  67. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  68. package/dist/frontend/lowering/lowerer.d.ts +31 -13
  69. package/dist/frontend/lowering/lowerer.js +99 -45
  70. package/dist/frontend/lowering/lowerer.js.map +1 -1
  71. package/dist/frontend/lowering/surfaces.d.ts +6 -0
  72. package/dist/frontend/lowering/surfaces.js +78 -2
  73. package/dist/frontend/lowering/surfaces.js.map +1 -1
  74. package/dist/frontend/program.js +1 -1
  75. package/dist/frontend/shared.js +7 -7
  76. package/dist/frontend/shared.js.map +1 -1
  77. package/dist/frontend/types.d.ts +2 -2
  78. package/dist/frontend/types.js +27 -15
  79. package/dist/frontend/types.js.map +1 -1
  80. package/dist/index.js +44 -8
  81. package/dist/index.js.map +1 -1
  82. package/dist/ir/nodes.d.ts +208 -106
  83. package/dist/ir/nodes.js +100 -22
  84. package/dist/ir/nodes.js.map +1 -1
  85. package/dist/ir/validate.js +96 -38
  86. package/dist/ir/validate.js.map +1 -1
  87. package/dist/library/int-infer.js +13 -0
  88. package/dist/library/int-infer.js.map +1 -1
  89. package/dist/library/profile.d.ts +8 -6
  90. package/dist/library/profile.js.map +1 -1
  91. package/dist/library/sidecar-validate.js +1 -1
  92. package/dist/library/sidecar-validate.js.map +1 -1
  93. package/dist/library/sidecar.d.ts +1 -1
  94. package/dist/library/sidecar.js +20 -7
  95. package/dist/library/sidecar.js.map +1 -1
  96. package/package.json +2 -2
  97. package/surface-manifest.json +289 -4
@@ -98,7 +98,7 @@ export declare function hoistVarBinding(L: Lowerer, symbol: ts.Symbol, nameNode:
98
98
  * such reads `undefined`, never a TDZ error, so the hoisted slot must
99
99
  * hold `undefined` from function entry — which is only honest for
100
100
  * undefined-armed union types (the interned arm) and checked-dynamic
101
- * bindings (the DOM undefined). Everything else returns false
101
+ * bindings (the dyn undefined). Everything else returns false
102
102
  * and the reference lands on the named fence in rejectUnresolvedSymbol:
103
103
  * a slot of a narrower type has no bit pattern for the `undefined` Node
104
104
  * would yield if the capture ran early, and guessing "it won't" is the
@@ -486,7 +486,7 @@ export function hoistVarBinding(L, symbol, nameNode) {
486
486
  const local = { id: `${name}.${count}`, name, type, mutable: true };
487
487
  L.ctx.locals.push(local);
488
488
  L.ctx.scopes[0].set(symbol, local);
489
- // A checked-dynamic slot holds the DOM undefined (a NULL dyn is a
489
+ // A checked-dynamic slot holds the dyn undefined (a NULL dyn is a
490
490
  // trap); everything else rides unassignedSlotInit (interned union arm,
491
491
  // engine undefined for jsval).
492
492
  const wrapped = type.kind === "dyn" ? dynUndefinedExpr(locOf(nameNode)) : L.unassignedSlotInit(type, locOf(nameNode));
@@ -502,7 +502,7 @@ export function hoistVarBinding(L, symbol, nameNode) {
502
502
  * such reads `undefined`, never a TDZ error, so the hoisted slot must
503
503
  * hold `undefined` from function entry — which is only honest for
504
504
  * undefined-armed union types (the interned arm) and checked-dynamic
505
- * bindings (the DOM undefined). Everything else returns false
505
+ * bindings (the dyn undefined). Everything else returns false
506
506
  * and the reference lands on the named fence in rejectUnresolvedSymbol:
507
507
  * a slot of a narrower type has no bit pattern for the `undefined` Node
508
508
  * would yield if the capture ran early, and guessing "it won't" is the
@@ -536,7 +536,7 @@ export function predeclareForwardVar(L, symbol) {
536
536
  const ctx = owner.ctx;
537
537
  // Only a slot that can hold `undefined` can carry the pre-
538
538
  // initialization reads: an undefined-armed union (the interned arm),
539
- // a checked-dynamic binding (the DOM undefined), or a jsval 'any'
539
+ // a checked-dynamic binding (the dyn undefined), or a jsval 'any'
540
540
  // binding (the engine's undefined).
541
541
  const type = varBindingType(L, nameNode);
542
542
  if (!type)
@@ -757,7 +757,7 @@ export function lowerStmt(L, stmt) {
757
757
  // A bare `return;` in a union-returning function yields undefined
758
758
  // (JS), which the undefined arm carries — tsc only allows the bare
759
759
  // form when the return type includes undefined/void. A CHECKED-
760
- // DYNAMIC return slot holds the DOM undefined directly (the
760
+ // DYNAMIC return slot holds the dyn undefined directly (the
761
761
  // appendImplicitUndefinedReturn rule). What remains is JS-only —
762
762
  // a JSDoc return claim the body contradicts (ms's parse: `@return
763
763
  // {Number}` with a bare early `return;`): no undefined fits the
@@ -819,11 +819,11 @@ export function lowerStmt(L, stmt) {
819
819
  const value = L.lowerExpr(stmt.expression);
820
820
  if (value.type.kind === "void")
821
821
  L.badType(stmt.expression, L.typeOf(stmt.expression));
822
- // A dyn throw rides the REF cell arm (scr_throw_ref over the DOM
822
+ // A dyn throw rides the REF cell arm (scr_throw_ref over the checked-dynamic tree
823
823
  // node — identity preserved through catch bindings, caughtToDyn
824
824
  // passes it back by reference). The JS-lane traced-call shape:
825
- // `throw err` where err arrived as a DOM argument. instanceof
826
- // narrowing over the payload stays false (the DOM's %error encoding
825
+ // `throw err` where err arrived as a dyn argument. instanceof
826
+ // narrowing over the payload stays false (the checked-dynamic tree's %error encoding
827
827
  // is not a hierarchy object — SEMANTICS.md).
828
828
  return { kind: "throw", value, loc: locOf(stmt) };
829
829
  }
@@ -919,9 +919,9 @@ export function lowerVarStatement(L, stmt) {
919
919
  }
920
920
  // `const { NGHTTP2_CANCEL } = http2.constants` — a destructure over
921
921
  // the baked constants table: alias plumbing, no storage (uses read
922
- // their literals via http2ConstantBindingOf; collectGlobals skipped
922
+ // their literals via builtinConstantBindingOf; collectGlobals skipped
923
923
  // the globals by the same test).
924
- if (L.http2ConstantsDestructureDecl(decl.name, decl.initializer))
924
+ if (L.builtinConstantsDestructureDecl(decl.name, decl.initializer))
925
925
  return [];
926
926
  if (ts.isArrayBindingPattern(decl.name) || ts.isObjectBindingPattern(decl.name)) {
927
927
  // `const { createSign } = crypto` over a builtin NAMESPACE binding:
@@ -1018,7 +1018,7 @@ export function lowerDestructuringDecl(L, decl, isLet) {
1018
1018
  let init = L.lowerExpr(decl.initializer);
1019
1019
  // A TS `any`-origin source whose lowered value is NOT a destructurable
1020
1020
  // shape (`var { x } = <any>0` — the cast erases to the f64; a dyn
1021
- // value — the DOM has no destructure): JS reads the properties off
1021
+ // value — the checked-dynamic tree has no destructure): JS reads the properties off
1022
1022
  // whatever the value is (a number answers undefined) — engine
1023
1023
  // semantics, the dynamic-family fence. Record and array sources fall
1024
1024
  // through to their lowerings, island handles to theirs (--dynamic
@@ -1276,16 +1276,16 @@ export function lowerBindingPattern(L, pattern, srcRef, srcType, isLet, out, dyn
1276
1276
  L.lowerBindingPattern(pattern, () => ({ kind: "varRef", localId: chars.id, type: charsT, loc }), charsT, isLet, out);
1277
1277
  return;
1278
1278
  }
1279
- // DYN sources (`const [a, b] = d` over a DOM value, `([_, code]) =>`
1279
+ // DYN sources (`const [a, b] = d` over a dyn value, `([_, code]) =>`
1280
1280
  // params destructuring dyn callback arguments — the suite harness's
1281
1281
  // _expectWarning shapes): the source packs ONCE through the spread
1282
1282
  // walk (dyn.iterPack — arrays element-by-element, strings by code
1283
1283
  // point, bytes by byte; every other kind throws V8's destructuring
1284
1284
  // TypeError, the compile-time spelling when the source has one),
1285
1285
  // then positions bind the pack's index keys as dyn values — reads
1286
- // past the end bind undefined, exactly JS. Defaults fire on the DOM
1286
+ // past the end bind undefined, exactly JS. Defaults fire on the checked-dynamic tree
1287
1287
  // undefined (JS's rule); rest elements keep the fence (surplus
1288
- // packing over the DOM needs a slice the IR does not spell yet).
1288
+ // packing over the checked-dynamic tree needs a slice the IR does not spell yet).
1289
1289
  if (srcType.kind === "dyn") {
1290
1290
  const loc = locOf(pattern);
1291
1291
  const pack = L.declareHiddenLocal("%dpack", DYN);
@@ -1316,14 +1316,14 @@ export function lowerBindingPattern(L, pattern, srcRef, srcType, isLet, out, dyn
1316
1316
  loc: elLoc,
1317
1317
  };
1318
1318
  if (el.initializer) {
1319
- // The default fires exactly on the DOM undefined (JS's rule),
1320
- // its value converting into the DOM like any dyn-slot value.
1319
+ // The default fires exactly on the dyn undefined (JS's rule),
1320
+ // its value converting into the checked-dynamic tree like any dyn-slot value.
1321
1321
  const rl = L.declareHiddenLocal("%delem", DYN);
1322
1322
  out.push({ kind: "varDecl", localId: rl.id, init: value, loc: elLoc });
1323
1323
  const ref = () => ({ kind: "varRef", localId: rl.id, type: DYN, loc: elLoc });
1324
1324
  const dflt = L.coerceToExpected(L.lowerExpr(el.initializer), DYN);
1325
1325
  if (dflt.type.kind !== "dyn") {
1326
- L.unsupported("SC1031", el.initializer, `defaults of '${L.fmt(dflt.type)}' type over checked-dynamic sources (the value cannot convert into the DOM)`);
1326
+ L.unsupported("SC1031", el.initializer, `defaults of '${L.fmt(dflt.type)}' type over checked-dynamic sources (the value cannot convert into the checked-dynamic tree)`);
1327
1327
  }
1328
1328
  value = {
1329
1329
  kind: "ternary",
@@ -2537,7 +2537,7 @@ export function bindPatternTarget(L, name, value, isLet, out) {
2537
2537
  // a pattern binding whose VALUE lowered checked-dynamic stays dyn
2538
2538
  // where the checker spells an island-world type (`function f({
2539
2539
  // plugins = [] } = {})` over a JSDoc '(string | object)[]=' member —
2540
- // the read is a DOM keyed read whose members may be wrapped island
2540
+ // the read is a dyn keyed read whose members may be wrapped island
2541
2541
  // values) or a type with no mapping at all (the varDecl rule's
2542
2542
  // unmappable-declared-type stance, `string | object` bindings
2543
2543
  // included). Marshaling here would fence or deep-copy; the value's
@@ -2702,9 +2702,9 @@ export function lowerVarDecl(L, decl, isLet) {
2702
2702
  return null;
2703
2703
  // `const { NGHTTP2_CANCEL } = http2.constants` — a destructure over
2704
2704
  // the baked constants table: alias plumbing, no storage (uses read
2705
- // their literals via http2ConstantBindingOf; collectGlobals skipped
2705
+ // their literals via builtinConstantBindingOf; collectGlobals skipped
2706
2706
  // the globals by the same test).
2707
- if (L.http2ConstantsDestructureDecl(decl.name, decl.initializer))
2707
+ if (L.builtinConstantsDestructureDecl(decl.name, decl.initializer))
2708
2708
  return null;
2709
2709
  // `const Writable = stream.Writable` — a stream class through the
2710
2710
  // namespace binding: alias plumbing, no storage (uses resolve through
@@ -2790,7 +2790,7 @@ export function lowerVarDecl(L, decl, isLet) {
2790
2790
  // a loop — must NOT reset the persisting binding.
2791
2791
  if (isVarDeclared(decl))
2792
2792
  return null;
2793
- // Checked-dynamic globals hold the DOM undefined from their
2793
+ // Checked-dynamic globals hold the dyn undefined from their
2794
2794
  // declaration statement on; unions and jsval ride
2795
2795
  // unassignedSlotInit's arms.
2796
2796
  const wrapped = g.type.kind === "dyn" ? dynUndefinedExpr(locOf(decl)) : L.unassignedSlotInit(g.type, locOf(decl));
@@ -2845,7 +2845,7 @@ export function lowerVarDecl(L, decl, isLet) {
2845
2845
  const local = L.declareLocal(decl.name, decl.name.text, type, isLet);
2846
2846
  // tsc's definite-assignment analysis never guards `any` reads, so
2847
2847
  // uninitialized bindings must hold their world's undefined, never
2848
- // NULL: unions the interned arm, dyn the DOM undefined, jsval the
2848
+ // NULL: unions the interned arm, dyn the dyn undefined, jsval the
2849
2849
  // engine's — all readable immediately, exactly Node.
2850
2850
  const init = type.kind === "dyn" ? dynUndefinedExpr(locOf(decl)) : L.unassignedSlotInit(type, locOf(decl));
2851
2851
  return { kind: "varDecl", localId: local.id, init, loc: locOf(decl) };
@@ -2869,7 +2869,7 @@ export function lowerVarDecl(L, decl, isLet) {
2869
2869
  }
2870
2870
  // A dyn initializer under an unmappable declared type (`const ws =
2871
2871
  // pkg.workspaces` — the lowering world types the unknown-receiver read
2872
- // `any`, which a static build cannot hold): the VALUE is a DOM
2872
+ // `any`, which a static build cannot hold): the VALUE is a dyn
2873
2873
  // subtree, so the local stays dyn — later narrowing tests and checked
2874
2874
  // casts read it like any JSON.parse result.
2875
2875
  // `const p = import("./m")` / `const ns = await import("./m")`: the
@@ -2894,7 +2894,7 @@ export function lowerVarDecl(L, decl, isLet) {
2894
2894
  // the island-HANDLE local rule's mirror): a binding whose
2895
2895
  // INITIALIZER lowered checked-dynamic stays dyn even where the
2896
2896
  // checker spells 'any' (`const parsers = options.parsers ?? {}` over
2897
- // an 'object'-typed bag — the read is a DOM keyed read). Marshaling
2897
+ // an 'object'-typed bag — the read is a dyn keyed read). Marshaling
2898
2898
  // into the engine here would deep-copy data and sever aliasing; the
2899
2899
  // value's world is the honest dispatch, and every use site already
2900
2900
  // handles dyn (validated exits, routed engine ops for wrapped
@@ -2921,7 +2921,7 @@ export function lowerVarDecl(L, decl, isLet) {
2921
2921
  // pushes of anything non-numeric would fence and typed exits would
2922
2922
  // mismatch the checker's evolved reads downstream. The binding is
2923
2923
  // checked-dynamic instead (the `let x = {}` stance, and lower-modules'
2924
- // file-scope evolving-array rule): pushes ride the DOM array, typed
2924
+ // file-scope evolving-array rule): pushes ride the dyn array, typed
2925
2925
  // exits dynCheck.
2926
2926
  if ((type === null || type.kind === "array") && isJsSourceFile(decl.getSourceFile())) {
2927
2927
  let initExpr = decl.initializer;
@@ -3000,6 +3000,15 @@ export function lowerVarDecl(L, decl, isLet) {
3000
3000
  // bridge is an independent observer of the same settlement).
3001
3001
  if (init.type.kind === "jsval" && type.kind === "promise")
3002
3002
  type = JSVAL;
3003
+ // An island value under an `any[]`-declared LOCAL spelling stays an
3004
+ // island HANDLE too (the runtime-world rule): the jsval-element-array
3005
+ // exit is a CALL-boundary conversion (the loadPlugins param ABI) —
3006
+ // converting a local would strand the engine's own prototypes
3007
+ // (join/map/... on a native handle-element array), where the handle
3008
+ // routes every use engine-side.
3009
+ if (init.type.kind === "jsval" && type.kind === "array" && type.elem.kind === "jsval") {
3010
+ type = JSVAL;
3011
+ }
3003
3012
  // A STATIC array of island HANDLES under an unannotated declared type
3004
3013
  // spelling evolved elements (`const kept = fns.filter(...)` over an
3005
3014
  // evolving-`any` receiver — the handle-element lowering keeps the
@@ -3847,7 +3856,7 @@ export function lowerExprStatement(L, expr) {
3847
3856
  const loc = locOf(expr);
3848
3857
  // Dispatch follows the RUNTIME world (383(d)): a checker-'any'
3849
3858
  // receiver whose value LOWERED checked-dynamic (`bag.nested.x
3850
- // = v` behind an 'object'-typed bag) takes the DOM keyed
3859
+ // = v` behind an 'object'-typed bag) takes the dyn keyed
3851
3860
  // write — the routed JSVAL arm lands it on the real engine
3852
3861
  // object.
3853
3862
  if (obj.type.kind === "dyn") {
@@ -3944,7 +3953,7 @@ export function lowerExprStatement(L, expr) {
3944
3953
  }
3945
3954
  // `h.onDone = cb` on a CHECKED-DYNAMIC receiver (a JS `let h =
3946
3955
  // {}` evolving object, an implicit-any param, a dyn member
3947
- // chain): the DOM keyed write — the value converts INTO dyn
3956
+ // chain): the dyn keyed write — the value converts INTO dyn
3948
3957
  // (closures box), the runtime sets the member on OBJ receivers
3949
3958
  // and throws Node's TypeErrors on the rest. The receiver is
3950
3959
  // PROBED (probeLower) and claimed exactly when it lowers to
@@ -3964,7 +3973,7 @@ export function lowerExprStatement(L, expr) {
3964
3973
  }
3965
3974
  // `events.defaultMaxListeners = v` in STATEMENT position — the
3966
3975
  // module-property write Node validates (the lowerBinary
3967
- // expression twin): the value crosses into the DOM, the runtime
3976
+ // expression twin): the value crosses into the checked-dynamic tree, the runtime
3968
3977
  // ladder throws Node's exact errors, valid numbers apply.
3969
3978
  if (!expr.left.questionDotToken && expr.left.name.text === "defaultMaxListeners") {
3970
3979
  const bi = L.builtinMemberOf(expr.left);
@@ -4268,7 +4277,7 @@ function lowerCompoundToTarget(L, expr, compound, target) {
4268
4277
  isJsSourceFile(expr.getSourceFile())) {
4269
4278
  // JS any-origin operands: check to number and compute natively
4270
4279
  // (the binary-operator stance) — the dyn target takes the result
4271
- // back through the usual DOM conversion.
4280
+ // back through the usual dyn conversion.
4272
4281
  const checkNum = (e) => e.type.kind === "dyn" ? { kind: "dynCheck", value: e, type: F64, loc: e.loc } : e;
4273
4282
  const computed = { kind: "bin", op: compound, left: checkNum(read), right: checkNum(rhs), type: F64, loc };
4274
4283
  value = target.type.kind === "dyn" ? { kind: "dynFrom", value: computed, type: DYN, loc } : computed;
@@ -5100,7 +5109,7 @@ function destructAssignPiece(L, prop, islandSource) {
5100
5109
  // keys resolve statically (the record path's rule) — the keyed read
5101
5110
  // below takes the folded name. A RUNTIME-valued key over an ISLAND
5102
5111
  // source reads through the engine's own indexing at the element's
5103
- // pattern position (`({ [key]: w } = src)`); over the DOM the fence
5112
+ // pattern position (`({ [key]: w } = src)`); over the checked-dynamic tree the fence
5104
5113
  // stays.
5105
5114
  const folded = patternKeyNameOf(L, prop.name);
5106
5115
  if (folded === null) {
@@ -5550,12 +5559,12 @@ export function lowerForOf(L, stmt) {
5550
5559
  if (iterable.type.kind === "jsval") {
5551
5560
  return lowerForOfIsland(L, stmt, iterable, labels);
5552
5561
  }
5553
- // A CHECKED-DYNAMIC iterable (`unknown[]` and the collapsed
5554
- // `(string | object)[]` are DOM values now, so the TYPE maps —
5555
- // badType would tell a stale component story): the OPERATION is
5556
- // the gap — name it, with the validated-cast escape hatch.
5562
+ // A CHECKED-DYNAMIC iterable (`unknown[]`, the collapsed
5563
+ // `(string | object)[]`, JSON-parsed values, wrapped engine
5564
+ // values): the source packs ONCE through the spread walk and a
5565
+ // hidden index loop binds each element as a dyn value.
5557
5566
  if (iterable.type.kind === "dyn") {
5558
- L.unsupported("SC1090", stmt.expression, "for-of over checked-dynamic ('unknown') values (validate into a typed array first — `u as string[]` — or index with a counted loop: length and element reads compile)");
5567
+ return lowerForOfDyn(L, stmt, iterable, labels);
5559
5568
  }
5560
5569
  if (iterable.type.kind !== "array") {
5561
5570
  L.badType(stmt.expression, L.typeOf(stmt.expression));
@@ -5928,6 +5937,158 @@ function lowerForOfClassIterator(L, stmt, iterable, cit, labels) {
5928
5937
  * (break/return out of a partial iteration calling it.return()) is NOT
5929
5938
  * run — a divergence only a custom island iterator with a return()
5930
5939
  * method can observe. */
5940
+ /** For-of over a CHECKED-DYNAMIC iterable: the source packs ONCE
5941
+ * through the spread walk (dyn.iterPack — dyn arrays element-by-
5942
+ * element, strings by code point, bytes by byte; a WRAPPED engine
5943
+ * value drains through the ENGINE's own iterator protocol via the
5944
+ * iter_drain arm; every other kind throws V8's not-iterable
5945
+ * TypeError, the identifier spelling when the head has one), then a
5946
+ * hidden index loop binds each element as a dyn value. The pack is an
5947
+ * eager SNAPSHOT (the matchAll stance): body mutations of a dyn-array
5948
+ * source don't extend the iteration where JS's live array iterator
5949
+ * would — documented divergence; engine sources drain through their
5950
+ * own protocol, so generators/Maps/Sets step exactly once like Node. */
5951
+ function lowerForOfDyn(L, stmt, iterable, labels) {
5952
+ const loc = locOf(stmt);
5953
+ const head = stmt.expression;
5954
+ // V8's for-of CallPrinter spellings: named sources (identifiers and
5955
+ // plain property chains) read "<src> is not iterable", call heads
5956
+ // with a nameable callee "<callee> is not a function or its return
5957
+ // value is not iterable"; everything else keeps the runtime kind
5958
+ // wording. The runtime uses the spelling VERBATIM when non-empty.
5959
+ const headText = (e) => {
5960
+ if (ts.isIdentifier(e))
5961
+ return e.text;
5962
+ if (ts.isPropertyAccessExpression(e) && !e.questionDotToken && ts.isIdentifier(e.name)) {
5963
+ const base = headText(e.expression);
5964
+ return base !== null ? `${base}.${e.name.text}` : null;
5965
+ }
5966
+ return null;
5967
+ };
5968
+ const headName = headText(head);
5969
+ const calleeName = ts.isCallExpression(head) ? headText(head.expression) : null;
5970
+ const spell = headName !== null
5971
+ ? `${headName} is not iterable`
5972
+ : calleeName !== null
5973
+ ? `${calleeName} is not a function or its return value is not iterable`
5974
+ : "";
5975
+ const pack = L.declareHiddenLocal("%dofpack", DYN);
5976
+ const idx = L.declareHiddenLocal("%dofi", F64);
5977
+ idx.mutable = true;
5978
+ const packRef = () => ({ kind: "varRef", localId: pack.id, type: DYN, loc });
5979
+ const iRef = () => ({ kind: "varRef", localId: idx.id, type: F64, loc });
5980
+ const elemInit = () => ({ kind: "libCall", fn: "dyn.arrAt", args: [packRef(), iRef()], type: DYN, loc });
5981
+ L.scopes.push(new Map());
5982
+ try {
5983
+ const binds = [];
5984
+ if (!ts.isVariableDeclarationList(stmt.initializer)) {
5985
+ // Pre-declared heads: identifier targets assign the existing
5986
+ // binding once per pass (JS's shared-binding rule); literal
5987
+ // patterns run the destructuring-assignment machinery over the
5988
+ // dyn element; member targets keep the fence.
5989
+ let target = stmt.initializer;
5990
+ while (ts.isParenthesizedExpression(target))
5991
+ target = target.expression;
5992
+ const tmp = L.declareHiddenLocal("%vof", DYN);
5993
+ binds.push({ kind: "varDecl", localId: tmp.id, init: elemInit(), loc });
5994
+ const elemRef = { kind: "varRef", localId: tmp.id, type: DYN, loc };
5995
+ if (ts.isArrayLiteralExpression(target) || ts.isObjectLiteralExpression(target)) {
5996
+ binds.push(lowerDestructuringAssign(L, target, elemRef, target, loc));
5997
+ }
5998
+ else if (ts.isIdentifier(target) && L.resolveWritable(target)) {
5999
+ const writable = L.resolveWritable(target);
6000
+ binds.push({
6001
+ kind: "assign",
6002
+ localId: writable.id,
6003
+ value: L.coerceInto(target, elemRef, writable.type),
6004
+ loc,
6005
+ });
6006
+ }
6007
+ else {
6008
+ L.unsupported("SC1090", stmt.initializer, "for-of over a pre-declared variable (declare the loop variable in the loop: for (const x of ...))");
6009
+ }
6010
+ }
6011
+ else {
6012
+ const list = stmt.initializer;
6013
+ if ((list.flags & ts.NodeFlags.Using) !== 0) {
6014
+ L.unsupported("SC1090", list, "'using' declarations (dispose-at-scope-exit semantics)");
6015
+ }
6016
+ const isLet = (list.flags & ts.NodeFlags.Let) !== 0 || (list.flags & ts.NodeFlags.BlockScoped) === 0;
6017
+ const decl = list.declarations[0];
6018
+ if (ts.isArrayBindingPattern(decl.name) || ts.isObjectBindingPattern(decl.name)) {
6019
+ const tmp = L.declareHiddenLocal("%destr", DYN);
6020
+ binds.push({ kind: "varDecl", localId: tmp.id, init: elemInit(), loc });
6021
+ L.lowerBindingPattern(decl.name, () => ({ kind: "varRef", localId: tmp.id, type: DYN, loc }), DYN, isLet, binds);
6022
+ }
6023
+ else if (ts.isIdentifier(decl.name)) {
6024
+ const varTarget = forOfVarTarget(L, decl);
6025
+ if (varTarget) {
6026
+ // `for (var x of d)`: the element mechanics stay on a hidden
6027
+ // per-iteration local; the body opens by assigning the ONE
6028
+ // hoisted var binding (the array head's rule).
6029
+ const tmp = L.declareHiddenLocal("%vof", DYN);
6030
+ binds.push({ kind: "varDecl", localId: tmp.id, init: elemInit(), loc });
6031
+ binds.push({
6032
+ kind: "assign",
6033
+ localId: varTarget.id,
6034
+ value: L.coerceInto(decl.name, { kind: "varRef", localId: tmp.id, type: DYN, loc }, varTarget.type),
6035
+ loc,
6036
+ });
6037
+ }
6038
+ else {
6039
+ const local = L.declareLocal(decl.name, decl.name.text, DYN, isLet);
6040
+ binds.push({ kind: "varDecl", localId: local.id, init: elemInit(), loc });
6041
+ }
6042
+ }
6043
+ else {
6044
+ L.unsupported("SC1031", decl.name);
6045
+ }
6046
+ }
6047
+ const body = L.inCtl("loop", () => L.lowerScopedBlock(stmt.statement), labels);
6048
+ return {
6049
+ kind: "block",
6050
+ body: [
6051
+ {
6052
+ kind: "varDecl",
6053
+ localId: pack.id,
6054
+ init: {
6055
+ kind: "libCall",
6056
+ fn: "dyn.iterPack",
6057
+ args: [iterable, { kind: "strLit", value: spell, type: STRING, loc }],
6058
+ type: DYN,
6059
+ loc,
6060
+ },
6061
+ loc,
6062
+ },
6063
+ {
6064
+ kind: "for",
6065
+ init: { kind: "varDecl", localId: idx.id, init: { kind: "numLit", value: 0, type: F64, loc }, loc },
6066
+ cond: {
6067
+ kind: "bin",
6068
+ op: "<",
6069
+ left: iRef(),
6070
+ right: { kind: "libCall", fn: "dyn.arrLen", args: [packRef()], type: F64, loc },
6071
+ type: BOOL,
6072
+ loc,
6073
+ },
6074
+ update: {
6075
+ kind: "assign",
6076
+ localId: idx.id,
6077
+ value: { kind: "bin", op: "+", left: iRef(), right: { kind: "numLit", value: 1, type: F64, loc }, type: F64, loc },
6078
+ loc,
6079
+ },
6080
+ body: [...binds, ...body],
6081
+ ...(labels && { labels }),
6082
+ loc,
6083
+ },
6084
+ ],
6085
+ loc,
6086
+ };
6087
+ }
6088
+ finally {
6089
+ L.scopes.pop();
6090
+ }
6091
+ }
5931
6092
  function lowerForOfIsland(L, stmt, iterable, labels) {
5932
6093
  const loc = locOf(stmt);
5933
6094
  if (!ts.isVariableDeclarationList(stmt.initializer)) {