@scriptc/compiler 0.3.4 → 0.3.5

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 (219) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +131 -10
  2. package/dist/backend/llvm/array-search.js +1 -1
  3. package/dist/backend/llvm/array-search.js.map +1 -1
  4. package/dist/backend/llvm/call-lifetimes.d.ts +6 -0
  5. package/dist/backend/llvm/call-lifetimes.js +19 -0
  6. package/dist/backend/llvm/call-lifetimes.js.map +1 -1
  7. package/dist/backend/llvm/constant-callbacks.d.ts +2 -21
  8. package/dist/backend/llvm/constant-callbacks.js +36 -219
  9. package/dist/backend/llvm/constant-callbacks.js.map +1 -1
  10. package/dist/backend/llvm/constant-callbacks.test.js +22 -0
  11. package/dist/backend/llvm/constant-callbacks.test.js.map +1 -1
  12. package/dist/backend/llvm/dense-array-access.d.ts +9 -0
  13. package/dist/backend/llvm/dense-array-access.js +27 -1
  14. package/dist/backend/llvm/dense-array-access.js.map +1 -1
  15. package/dist/backend/llvm/dyn.d.ts +6 -0
  16. package/dist/backend/llvm/dyn.js +40 -6
  17. package/dist/backend/llvm/dyn.js.map +1 -1
  18. package/dist/backend/llvm/emitter.d.ts +75 -1
  19. package/dist/backend/llvm/emitter.js +408 -38
  20. package/dist/backend/llvm/emitter.js.map +1 -1
  21. package/dist/backend/llvm/expr-async.js +17 -7
  22. package/dist/backend/llvm/expr-async.js.map +1 -1
  23. package/dist/backend/llvm/expr-bytes.js +1 -1
  24. package/dist/backend/llvm/expr-callbacks.d.ts +11 -0
  25. package/dist/backend/llvm/expr-callbacks.js +53 -0
  26. package/dist/backend/llvm/expr-callbacks.js.map +1 -1
  27. package/dist/backend/llvm/expr-calls.js +88 -2
  28. package/dist/backend/llvm/expr-calls.js.map +1 -1
  29. package/dist/backend/llvm/expr-containers.js +50 -27
  30. package/dist/backend/llvm/expr-containers.js.map +1 -1
  31. package/dist/backend/llvm/expr-primitives.js +9 -1
  32. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  33. package/dist/backend/llvm/expr-stream-bridges.js +4 -0
  34. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  35. package/dist/backend/llvm/integer-clones.d.ts +103 -0
  36. package/dist/backend/llvm/integer-clones.js +1336 -0
  37. package/dist/backend/llvm/integer-clones.js.map +1 -0
  38. package/dist/backend/llvm/integer-clones.test.d.ts +1 -0
  39. package/dist/backend/llvm/integer-clones.test.js +219 -0
  40. package/dist/backend/llvm/integer-clones.test.js.map +1 -0
  41. package/dist/backend/llvm/lib-datagram.js +14 -0
  42. package/dist/backend/llvm/lib-datagram.js.map +1 -1
  43. package/dist/backend/llvm/lib-dispatch.js +4 -0
  44. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  45. package/dist/backend/llvm/lib-process.js +24 -0
  46. package/dist/backend/llvm/lib-process.js.map +1 -1
  47. package/dist/backend/llvm/lib-shared.js +34 -2
  48. package/dist/backend/llvm/lib-shared.js.map +1 -1
  49. package/dist/backend/llvm/lib-tls.js +6 -0
  50. package/dist/backend/llvm/lib-tls.js.map +1 -1
  51. package/dist/backend/llvm/local-array-reads.js +1 -1
  52. package/dist/backend/llvm/local-array-reads.js.map +1 -1
  53. package/dist/backend/llvm/map-entry-fusion.d.ts +28 -0
  54. package/dist/backend/llvm/map-entry-fusion.js +233 -0
  55. package/dist/backend/llvm/map-entry-fusion.js.map +1 -0
  56. package/dist/backend/llvm/map-entry-fusion.test.d.ts +1 -0
  57. package/dist/backend/llvm/map-entry-fusion.test.js +183 -0
  58. package/dist/backend/llvm/map-entry-fusion.test.js.map +1 -0
  59. package/dist/backend/llvm/map-number-lookup.d.ts +2 -0
  60. package/dist/backend/llvm/map-number-lookup.js +1 -1
  61. package/dist/backend/llvm/map-number-lookup.js.map +1 -1
  62. package/dist/backend/llvm/map-number-lookup.test.js +10 -11
  63. package/dist/backend/llvm/map-number-lookup.test.js.map +1 -1
  64. package/dist/backend/llvm/map-read-lifetimes.d.ts +2 -0
  65. package/dist/backend/llvm/map-read-lifetimes.js +3 -0
  66. package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
  67. package/dist/backend/llvm/map-read-lifetimes.test.js +2 -2
  68. package/dist/backend/llvm/publish.d.ts +16 -0
  69. package/dist/backend/llvm/publish.js +81 -10
  70. package/dist/backend/llvm/publish.js.map +1 -1
  71. package/dist/backend/llvm/publish.test.d.ts +1 -0
  72. package/dist/backend/llvm/publish.test.js +94 -0
  73. package/dist/backend/llvm/publish.test.js.map +1 -0
  74. package/dist/backend/llvm/record-results.js +76 -2
  75. package/dist/backend/llvm/record-results.js.map +1 -1
  76. package/dist/backend/llvm/record-sources.d.ts +7 -0
  77. package/dist/backend/llvm/record-sources.js +14 -0
  78. package/dist/backend/llvm/record-sources.js.map +1 -0
  79. package/dist/backend/llvm/shapes.d.ts +9 -3
  80. package/dist/backend/llvm/shapes.js +18 -14
  81. package/dist/backend/llvm/shapes.js.map +1 -1
  82. package/dist/backend/llvm/shapes.test.js +5 -3
  83. package/dist/backend/llvm/shapes.test.js.map +1 -1
  84. package/dist/backend/llvm/string-lifetimes.test.js +75 -1
  85. package/dist/backend/llvm/string-lifetimes.test.js.map +1 -1
  86. package/dist/backend/llvm/walkers.d.ts +17 -0
  87. package/dist/backend/llvm/walkers.js +123 -0
  88. package/dist/backend/llvm/walkers.js.map +1 -1
  89. package/dist/backend/native/contracts.d.ts +2 -1
  90. package/dist/backend/native/executable.js +3 -1
  91. package/dist/backend/native/executable.js.map +1 -1
  92. package/dist/backend/runtime-abi.d.ts +2 -2
  93. package/dist/backend/runtime-abi.js +2 -2
  94. package/dist/backend/runtime-pack-targets.test.js +1 -1
  95. package/dist/backend/runtime-pack.test.js +1 -1
  96. package/dist/frontend/lowering/builtin-calls.js +3 -0
  97. package/dist/frontend/lowering/builtin-calls.js.map +1 -1
  98. package/dist/frontend/lowering/builtins/callable-aliases.js +54 -8
  99. package/dist/frontend/lowering/builtins/callable-aliases.js.map +1 -1
  100. package/dist/frontend/lowering/builtins/child-process-async.d.ts +8 -6
  101. package/dist/frontend/lowering/builtins/child-process-async.js +45 -29
  102. package/dist/frontend/lowering/builtins/child-process-async.js.map +1 -1
  103. package/dist/frontend/lowering/builtins/filesystem-calls.d.ts +2 -0
  104. package/dist/frontend/lowering/builtins/filesystem-calls.js +5 -0
  105. package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -1
  106. package/dist/frontend/lowering/builtins/filesystem.js +60 -0
  107. package/dist/frontend/lowering/builtins/filesystem.js.map +1 -1
  108. package/dist/frontend/lowering/builtins/fs-streams.d.ts +26 -0
  109. package/dist/frontend/lowering/builtins/fs-streams.js +131 -0
  110. package/dist/frontend/lowering/builtins/fs-streams.js.map +1 -0
  111. package/dist/frontend/lowering/builtins/module-calls.js +5 -1
  112. package/dist/frontend/lowering/builtins/module-calls.js.map +1 -1
  113. package/dist/frontend/lowering/class-dynamic-dispatch.js +150 -8
  114. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  115. package/dist/frontend/lowering/containers/bytes.js +33 -12
  116. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  117. package/dist/frontend/lowering/devirtualize.js +20 -7
  118. package/dist/frontend/lowering/devirtualize.js.map +1 -1
  119. package/dist/frontend/lowering/lower-calls.js +58 -3
  120. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  121. package/dist/frontend/lowering/lower-classes.js +7 -0
  122. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  123. package/dist/frontend/lowering/lower-dgram.js +55 -15
  124. package/dist/frontend/lowering/lower-dgram.js.map +1 -1
  125. package/dist/frontend/lowering/lower-event-emitter.d.ts +9 -1
  126. package/dist/frontend/lowering/lower-event-emitter.js +78 -0
  127. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
  128. package/dist/frontend/lowering/lower-exprs.d.ts +4 -0
  129. package/dist/frontend/lowering/lower-exprs.js +132 -58
  130. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  131. package/dist/frontend/lowering/lower-inspect.js +26 -0
  132. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  133. package/dist/frontend/lowering/lower-server.d.ts +2 -1
  134. package/dist/frontend/lowering/lower-server.js +73 -5
  135. package/dist/frontend/lowering/lower-server.js.map +1 -1
  136. package/dist/frontend/lowering/lower-stmts.js +12 -6
  137. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  138. package/dist/frontend/lowering/lower-stream.js +8 -0
  139. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  140. package/dist/frontend/lowering/lowerer.d.ts +3 -1
  141. package/dist/frontend/lowering/lowerer.js +2 -2
  142. package/dist/frontend/lowering/lowerer.js.map +1 -1
  143. package/dist/frontend/lowering/record-sources.d.ts +15 -0
  144. package/dist/frontend/lowering/record-sources.js +46 -0
  145. package/dist/frontend/lowering/record-sources.js.map +1 -0
  146. package/dist/frontend/lowering/surfaces.js +33 -1
  147. package/dist/frontend/lowering/surfaces.js.map +1 -1
  148. package/dist/frontend/type-mapper.d.ts +3 -0
  149. package/dist/frontend/type-mapper.js +53 -0
  150. package/dist/frontend/type-mapper.js.map +1 -1
  151. package/dist/ir/analysis.d.ts +10 -0
  152. package/dist/ir/analysis.js +35 -0
  153. package/dist/ir/analysis.js.map +1 -1
  154. package/dist/ir/analysis.test.js +69 -1
  155. package/dist/ir/analysis.test.js.map +1 -1
  156. package/dist/ir/builtin-effects.js +36 -0
  157. package/dist/ir/builtin-effects.js.map +1 -1
  158. package/dist/ir/builtin-signatures.d.ts +1 -1
  159. package/dist/ir/builtin-signatures.js +91 -7
  160. package/dist/ir/builtin-signatures.js.map +1 -1
  161. package/dist/ir/capture-values.d.ts +107 -0
  162. package/dist/ir/capture-values.js +850 -0
  163. package/dist/ir/capture-values.js.map +1 -0
  164. package/dist/ir/capture-values.test.d.ts +1 -0
  165. package/dist/ir/capture-values.test.js +268 -0
  166. package/dist/ir/capture-values.test.js.map +1 -0
  167. package/dist/ir/field-values.d.ts +16 -0
  168. package/dist/ir/field-values.js +128 -0
  169. package/dist/ir/field-values.js.map +1 -0
  170. package/dist/ir/field-values.test.d.ts +1 -0
  171. package/dist/ir/field-values.test.js +160 -0
  172. package/dist/ir/field-values.test.js.map +1 -0
  173. package/dist/ir/final-fields.d.ts +4 -1
  174. package/dist/ir/final-fields.js +11 -3
  175. package/dist/ir/final-fields.js.map +1 -1
  176. package/dist/ir/function-references.test.js +1 -1
  177. package/dist/ir/function-references.test.js.map +1 -1
  178. package/dist/ir/init-only-globals.d.ts +16 -0
  179. package/dist/ir/init-only-globals.js +121 -0
  180. package/dist/ir/init-only-globals.js.map +1 -0
  181. package/dist/ir/init-only-globals.test.d.ts +1 -0
  182. package/dist/ir/init-only-globals.test.js +115 -0
  183. package/dist/ir/init-only-globals.test.js.map +1 -0
  184. package/dist/ir/initializer-bindings.d.ts +18 -1
  185. package/dist/ir/initializer-bindings.js +91 -1
  186. package/dist/ir/initializer-bindings.js.map +1 -1
  187. package/dist/ir/initializer-bindings.test.js +57 -2
  188. package/dist/ir/initializer-bindings.test.js.map +1 -1
  189. package/dist/ir/int32-slots.d.ts +22 -0
  190. package/dist/ir/int32-slots.js +376 -13
  191. package/dist/ir/int32-slots.js.map +1 -1
  192. package/dist/ir/int32-slots.test.js +91 -8
  193. package/dist/ir/int32-slots.test.js.map +1 -1
  194. package/dist/ir/integer-loop-facts.d.ts +19 -1
  195. package/dist/ir/integer-loop-facts.js +155 -7
  196. package/dist/ir/integer-loop-facts.js.map +1 -1
  197. package/dist/ir/integer-ranges.d.ts +8 -5
  198. package/dist/ir/integer-ranges.js +147 -55
  199. package/dist/ir/integer-ranges.js.map +1 -1
  200. package/dist/ir/integer-ranges.test.js +225 -7
  201. package/dist/ir/integer-ranges.test.js.map +1 -1
  202. package/dist/ir/ir.d.ts +9 -1
  203. package/dist/ir/ir.js.map +1 -1
  204. package/dist/ir/property-bags.d.ts +14 -0
  205. package/dist/ir/property-bags.js +121 -0
  206. package/dist/ir/property-bags.js.map +1 -0
  207. package/dist/ir/receiver-readers.d.ts +21 -0
  208. package/dist/ir/receiver-readers.js +217 -0
  209. package/dist/ir/receiver-readers.js.map +1 -0
  210. package/dist/ir/runtime-features.js +6 -1
  211. package/dist/ir/runtime-features.js.map +1 -1
  212. package/dist/ir/validate.js +26 -0
  213. package/dist/ir/validate.js.map +1 -1
  214. package/dist/ir/validate.test.js +21 -0
  215. package/dist/ir/validate.test.js.map +1 -1
  216. package/dist/library/int-infer.js +3 -0
  217. package/dist/library/int-infer.js.map +1 -1
  218. package/package.json +20 -20
  219. package/surface-manifest.json +28 -2
@@ -205,6 +205,10 @@ export declare function lowerAbsenceProbe(lowerer: Lowerer, node: ts.Expression)
205
205
  * change the target or the value used by the operator. The expression yields
206
206
  * the computed value before a typed array or Buffer coerces it for storage. */
207
207
  export declare function lowerElementCompound(lowerer: Lowerer, expr: ts.BinaryExpression, op: CompoundOp): IrExpr;
208
+ /** `a[i] op= rhs` in statement position: a string array append becomes the
209
+ * canonical `a[i] = a[i] + rhs` store (receiver and index saved first),
210
+ * which the backend appends in place; other forms keep the value path. */
211
+ export declare function lowerElementCompoundStatement(lowerer: Lowerer, expr: ts.BinaryExpression, op: CompoundOp): IrStmt;
208
212
  /** JavaScript callable members live on the closure, so aliases and chained
209
213
  * writes share the same storage as Object.defineProperties. */
210
214
  export declare function lowerNativeFunctionAssignment(lowerer: Lowerer, expr: ts.BinaryExpression): IrExpr | null;
@@ -22,6 +22,7 @@ import { literalUnionArm } from "../union-discriminants.js";
22
22
  * comparisons, nullish coalescing and optional chains, conditions and
23
23
  * ToBoolean/ToString coercion helpers, and field/element reads and writes
24
24
  * (FieldTarget). */
25
+ import { isFsStreamMember, lowerFsStreamProperty } from "./builtins/fs-streams.js";
25
26
  import * as ts from "../ts7/adapter.js";
26
27
  import { isZlibStreamMember, lowerZlibStreamBytesWritten } from "./builtins/compression.js";
27
28
  import { constituentTypes } from "../ts7/checker.js";
@@ -599,6 +600,7 @@ function lowerExprInner(lowerer, expr) {
599
600
  const sym = lowerer.resolveValueSymbol(expr);
600
601
  const projection = sym ? lowerer.staticCallables.get(sym) : undefined;
601
602
  if (projection?.kind === "promisified-exec-file" ||
603
+ projection?.kind === "promisified-exec" ||
602
604
  projection?.kind === "promisified-builtin") {
603
605
  lowerer.unsupported("SC1090", expr, `a promisified builtin as a value (call '${expr.text}' directly)`);
604
606
  }
@@ -4166,6 +4168,8 @@ export function lowerIntrinsicProperty(lowerer, expr) {
4166
4168
  const numberMember = lowerer.stdlibGlobalMember(expr, "Number");
4167
4169
  if (numberMember === "parseInt" || numberMember === "parseFloat")
4168
4170
  return lowerNumberParserValue(lowerer, numberMember, locOf(expr));
4171
+ if (lowerer.stdlibGlobalMember(expr, "Buffer") === "poolSize")
4172
+ return { kind: "libCall", fn: "buffer.poolSize", args: [], type: F64, loc: locOf(expr) };
4169
4173
  if (lowerer.stdlibGlobalMember(expr, "Buffer") === "isBuffer")
4170
4174
  return lowerCheckedPredicateValue(lowerer, "Buffer.isBuffer", "buffer", locOf(expr));
4171
4175
  if (lowerer.stdlibGlobalMember(expr, "Date") === "now")
@@ -6343,6 +6347,21 @@ function tupleLiteralIndex(node) {
6343
6347
  * change the target or the value used by the operator. The expression yields
6344
6348
  * the computed value before a typed array or Buffer coerces it for storage. */
6345
6349
  export function lowerElementCompound(lowerer, expr, op) {
6350
+ const lowered = lowerElementCompoundParts(lowerer, expr, op, false);
6351
+ if (!lowered.expr)
6352
+ throw new InternalCompilerError("a compound element value lowered to statements");
6353
+ return lowered.expr;
6354
+ }
6355
+ /** `a[i] op= rhs` in statement position: a string array append becomes the
6356
+ * canonical `a[i] = a[i] + rhs` store (receiver and index saved first),
6357
+ * which the backend appends in place; other forms keep the value path. */
6358
+ export function lowerElementCompoundStatement(lowerer, expr, op) {
6359
+ const lowered = lowerElementCompoundParts(lowerer, expr, op, true);
6360
+ if (lowered.stmts)
6361
+ return { kind: "block", body: lowered.stmts, loc: locOf(expr) };
6362
+ return { kind: "exprStmt", expr: lowered.expr, loc: locOf(expr) };
6363
+ }
6364
+ function lowerElementCompoundParts(lowerer, expr, op, statement) {
6346
6365
  const target = expr.left;
6347
6366
  fenceNodeModuleMutation(lowerer, target, "assignment");
6348
6367
  const loc = locOf(expr);
@@ -6377,7 +6396,7 @@ export function lowerElementCompound(lowerer, expr, op) {
6377
6396
  },
6378
6397
  loc,
6379
6398
  });
6380
- return { kind: "seqExpr", stmts, result: value, type: DYN, loc };
6399
+ return { expr: { kind: "seqExpr", stmts, result: value, type: DYN, loc }, stmts: null };
6381
6400
  }
6382
6401
  const receiverType = checked.type.kind === "array" || checked.type.kind === "bytes"
6383
6402
  ? checked.type
@@ -6435,6 +6454,27 @@ export function lowerElementCompound(lowerer, expr, op) {
6435
6454
  const valueType = elementType.kind === "union" && lowerer.armTag(elementType.unionId, UNDEFINED_T) >= 0
6436
6455
  ? lowerer.stripUndefinedArm(elementType)
6437
6456
  : elementType;
6457
+ if (statement &&
6458
+ op === "+" &&
6459
+ receiver.type.kind === "array" &&
6460
+ receiver.type.elem.kind === "string") {
6461
+ // Receiver, index, old element (read inside the concat), rhs, write.
6462
+ const appended = {
6463
+ kind: "strConcat",
6464
+ left: oldValue,
6465
+ right: lowerer.ensureString(rhs, expr.right),
6466
+ type: STRING,
6467
+ loc,
6468
+ };
6469
+ return {
6470
+ expr: null,
6471
+ stmts: [
6472
+ { kind: "varDecl", localId: receiverLocal.id, init: receiver, loc },
6473
+ { kind: "varDecl", localId: indexLocal.id, init: index, loc },
6474
+ { kind: "arraySet", arr: receiverRef(), index: indexRef(), value: appended, loc },
6475
+ ],
6476
+ };
6477
+ }
6438
6478
  let computed;
6439
6479
  if (op === "+" && valueType.kind === "string") {
6440
6480
  computed = {
@@ -6457,17 +6497,18 @@ export function lowerElementCompound(lowerer, expr, op) {
6457
6497
  }
6458
6498
  else if (valueType.kind === "dyn" && isJsSourceFile(expr.getSourceFile())) {
6459
6499
  const left = lowerer.coerceToExpected(oldRef(), DYN), right = lowerer.coerceToExpected(rhs, DYN);
6460
- const numeric = ["-", "*", "/", "%", "**"].includes(op);
6461
- computed = {
6462
- kind: "libCall",
6463
- fn: op === "+" ? "dyn.add" : numeric ? "dyn.arithmetic" : "dyn.bitwise",
6464
- args: op === "+" ? [left, right] : [left, right, strLit(op, loc)],
6465
- type: DYN,
6466
- loc,
6467
- };
6500
+ computed = dynCompoundValue(op, left, right, loc);
6501
+ }
6502
+ else if (rhs.type.kind === "dyn" &&
6503
+ receiver.type.kind === "array" &&
6504
+ lowerer.dynConvertible(oldValue.type) &&
6505
+ lowerer.dynConvertible(valueType)) {
6506
+ // An untyped right operand: the expanded `a[i] = a[i] op rhs`, checked
6507
+ // back into the element type.
6508
+ computed = lowerer.coerceInto(expr, dynCompoundValue(op, lowerer.coerceToExpected(oldRef(), DYN), lowerer.coerceToExpected(rhs, DYN), loc), valueType);
6468
6509
  }
6469
6510
  else {
6470
- lowerer.unsupported("SC1043", expr);
6511
+ compoundUnsupported(lowerer, expr, op, oldValue.type, rhs.type);
6471
6512
  }
6472
6513
  const resultLocal = lowerer.declareHiddenLocal("%compoundResult", computed.type);
6473
6514
  const resultRef = () => varRef(resultLocal.id, computed.type, loc);
@@ -6475,17 +6516,20 @@ export function lowerElementCompound(lowerer, expr, op) {
6475
6516
  ? arrayValueStore(lowerer, receiverRef(), indexRef(), resultRef(), receiver.type.elem, loc)
6476
6517
  : { kind: "bytesSet", arr: receiverRef(), index: indexRef(), value: resultRef(), loc };
6477
6518
  return {
6478
- kind: "seqExpr",
6479
- stmts: [
6480
- { kind: "varDecl", localId: receiverLocal.id, init: receiver, loc },
6481
- { kind: "varDecl", localId: indexLocal.id, init: index, loc },
6482
- { kind: "varDecl", localId: oldLocal.id, init: oldValue, loc },
6483
- { kind: "varDecl", localId: resultLocal.id, init: computed, loc },
6484
- write,
6485
- ],
6486
- result: resultRef(),
6487
- type: computed.type,
6488
- loc,
6519
+ expr: {
6520
+ kind: "seqExpr",
6521
+ stmts: [
6522
+ { kind: "varDecl", localId: receiverLocal.id, init: receiver, loc },
6523
+ { kind: "varDecl", localId: indexLocal.id, init: index, loc },
6524
+ { kind: "varDecl", localId: oldLocal.id, init: oldValue, loc },
6525
+ { kind: "varDecl", localId: resultLocal.id, init: computed, loc },
6526
+ write,
6527
+ ],
6528
+ result: resultRef(),
6529
+ type: computed.type,
6530
+ loc,
6531
+ },
6532
+ stmts: null,
6489
6533
  };
6490
6534
  }
6491
6535
  /** ToString of one stabilized `string[]` element read for `+=`: a missing
@@ -7477,7 +7521,7 @@ export function lowerPrefixUnary(lowerer, expr) {
7477
7521
  ? { kind: "dynCheck", value: raw, type: F64, loc }
7478
7522
  : lowerOptionalNumber(lowerer, raw, loc, expr.operand);
7479
7523
  if (operand.type.kind !== "f64")
7480
- lowerer.unsupported("SC1043", expr);
7524
+ operatorUnsupported(lowerer, expr, "-", [raw.type]);
7481
7525
  if (operand.kind === "numLit")
7482
7526
  return { ...operand, value: -operand.value, loc };
7483
7527
  return { kind: "unary", op: "-", operand, type: F64, loc };
@@ -7495,7 +7539,7 @@ export function lowerPrefixUnary(lowerer, expr) {
7495
7539
  }
7496
7540
  const operand = lowerOptionalNumber(lowerer, raw, loc, expr.operand);
7497
7541
  if (operand.type.kind !== "f64")
7498
- lowerer.unsupported("SC1043", expr);
7542
+ operatorUnsupported(lowerer, expr, "+", [raw.type]);
7499
7543
  return operand;
7500
7544
  }
7501
7545
  case ts.SyntaxKind.ExclamationToken: {
@@ -7524,7 +7568,7 @@ export function lowerPrefixUnary(lowerer, expr) {
7524
7568
  // otherwise numeric slot to the checked-dynamic tree.
7525
7569
  const operand = lowerOptionalNumber(lowerer, raw, loc, expr.operand);
7526
7570
  if (operand.type.kind !== "f64")
7527
- lowerer.unsupported("SC1043", expr);
7571
+ operatorUnsupported(lowerer, expr, "~", [raw.type]);
7528
7572
  return { kind: "unary", op: "~", operand, type: F64, loc };
7529
7573
  }
7530
7574
  case ts.SyntaxKind.PlusPlusToken:
@@ -7781,7 +7825,7 @@ export function lowerIncDecTarget(lowerer, expr, target, prefix) {
7781
7825
  };
7782
7826
  }
7783
7827
  if (target.type.kind !== "f64")
7784
- lowerer.unsupported("SC1043", expr);
7828
+ operatorUnsupported(lowerer, expr, op === "+" ? "++" : "--", [target.type]);
7785
7829
  return { kind: "incDec", op, prefix, localId: target.id, type: F64, loc };
7786
7830
  }
7787
7831
  /** Whether a lowered statement can live inside a seqExpr. These statements
@@ -7874,26 +7918,51 @@ export function lowerCompoundValueToTarget(lowerer, expr, compound, target) {
7874
7918
  if (numericRead.type.kind === "f64" && numericRhs.type.kind === "f64") {
7875
7919
  return lowerer.coerceInto(expr, { kind: "bin", op: compound, left: numericRead, right: numericRhs, type: F64, loc }, target.type);
7876
7920
  }
7921
+ // An untyped operand: exactly the expanded `x = x op rhs` — the runtime
7922
+ // operator on both values, then the checked conversion into the
7923
+ // target's declared type (a string result for a number target throws the
7924
+ // catchable TypeError, as the expanded assignment does).
7877
7925
  if ((target.type.kind === "dyn" || rhs.type.kind === "dyn") &&
7878
- isJsSourceFile(expr.getSourceFile())) {
7926
+ (isJsSourceFile(expr.getSourceFile()) ||
7927
+ (lowerer.dynConvertible(read.type) && lowerer.dynConvertible(rhs.type)))) {
7879
7928
  const left = lowerer.coerceInto(expr.left, read, DYN);
7880
7929
  const right = lowerer.coerceInto(expr.right, rhs, DYN);
7881
- const numeric = ["-", "*", "/", "%", "**"].includes(compound);
7882
- const computed = {
7883
- kind: "libCall",
7884
- fn: compound === "+" ? "dyn.add" : numeric ? "dyn.arithmetic" : "dyn.bitwise",
7885
- args: compound === "+"
7886
- ? [left, right]
7887
- : [left, right, { kind: "strLit", value: compound, type: STRING, loc }],
7888
- type: DYN,
7889
- loc,
7890
- };
7891
- return lowerer.coerceInto(expr, computed, target.type);
7930
+ return lowerer.coerceInto(expr, dynCompoundValue(compound, left, right, loc), target.type);
7892
7931
  }
7893
7932
  const bigint = bigintCompoundValue(compound, read, rhs, loc);
7894
7933
  if (bigint)
7895
7934
  return bigint;
7896
- lowerer.unsupported("SC1043", expr);
7935
+ compoundUnsupported(lowerer, expr, compound, read.type, rhs.type);
7936
+ }
7937
+ /** The runtime operator of a compound assignment over two checked-dynamic
7938
+ * operands (Node's ToPrimitive/ToNumeric order lives in the runtime). */
7939
+ function dynCompoundValue(op, left, right, loc) {
7940
+ const numeric = ["-", "*", "/", "%", "**"].includes(op);
7941
+ return {
7942
+ kind: "libCall",
7943
+ fn: op === "+" ? "dyn.add" : numeric ? "dyn.arithmetic" : "dyn.bitwise",
7944
+ args: op === "+" ? [left, right] : [left, right, strLit(op, loc)],
7945
+ type: DYN,
7946
+ loc,
7947
+ };
7948
+ }
7949
+ /** An operand type in an SC1043 message: checked-dynamic values (`any`,
7950
+ * `unknown`) are "untyped", everything else its quoted type. */
7951
+ function operandText(lowerer, t) {
7952
+ return t.kind === "dyn" ? "untyped" : `'${lowerer.fmt(t)}'`;
7953
+ }
7954
+ /** SC1043 for a compound assignment whose operand types have no lowering,
7955
+ * naming the operator and both types rather than the comparison wording. */
7956
+ function compoundUnsupported(lowerer, node, op, target, value) {
7957
+ lowerer.unsupported("SC1043", node, `compound '${op}=' assignments of ${operandText(lowerer, value)} values to ${operandText(lowerer, target)} targets`);
7958
+ }
7959
+ /** SC1043 for an arithmetic, unary or update operator whose operand types
7960
+ * have no lowering (comparisons keep the registry wording). */
7961
+ function operatorUnsupported(lowerer, node, op, operands) {
7962
+ const [first, second] = operands;
7963
+ lowerer.unsupported("SC1043", node, second === undefined
7964
+ ? `'${op}' operations on ${operandText(lowerer, first)} values`
7965
+ : `'${op}' operations on ${operandText(lowerer, first)} and ${operandText(lowerer, second)} values`);
7897
7966
  }
7898
7967
  /** Equality of two NaN-coded values (nan-coded-reads.ts), each of which may
7899
7968
  * stand for undefined and never holds a genuine NaN: Node's undefined equals
@@ -8782,7 +8851,7 @@ export function lowerBinary(lowerer, expr) {
8782
8851
  };
8783
8852
  }
8784
8853
  }
8785
- lowerer.unsupported("SC1043", expr);
8854
+ operatorUnsupported(lowerer, expr, "+", [left.type, right.type]);
8786
8855
  break;
8787
8856
  case ts.SyntaxKind.MinusToken:
8788
8857
  case ts.SyntaxKind.AsteriskToken:
@@ -8790,7 +8859,7 @@ export function lowerBinary(lowerer, expr) {
8790
8859
  case ts.SyntaxKind.PercentToken:
8791
8860
  case ts.SyntaxKind.AsteriskAsteriskToken: {
8792
8861
  if (!bothNum)
8793
- lowerer.unsupported("SC1043", expr);
8862
+ operatorUnsupported(lowerer, expr, ts.tokenToString(op) ?? "?", [left.type, right.type]);
8794
8863
  const binOp = op === ts.SyntaxKind.MinusToken
8795
8864
  ? "-"
8796
8865
  : op === ts.SyntaxKind.AsteriskToken
@@ -8820,7 +8889,7 @@ export function lowerBinary(lowerer, expr) {
8820
8889
  case ts.SyntaxKind.GreaterThanGreaterThanToken:
8821
8890
  case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken: {
8822
8891
  if (!bothNum)
8823
- lowerer.unsupported("SC1043", expr);
8892
+ operatorUnsupported(lowerer, expr, ts.tokenToString(op) ?? "?", [left.type, right.type]);
8824
8893
  const bitOp = op === ts.SyntaxKind.AmpersandToken
8825
8894
  ? "&"
8826
8895
  : op === ts.SyntaxKind.BarToken
@@ -10533,10 +10602,12 @@ export function lowerInstanceOf(lowerer, expr, loc) {
10533
10602
  if (left.type.kind === "union") {
10534
10603
  const unionId = left.type.unionId;
10535
10604
  const arms = lowerer.unions.get(unionId)?.arms;
10536
- // Ordinary records and scalar values do not carry a class prototype.
10537
- // Dynamic/opaque runtime objects keep their existing instanceof fences.
10605
+ // Ordinary records, arrays and scalar values do not carry a class
10606
+ // prototype (no program class extends Array). Dynamic/opaque runtime
10607
+ // objects keep their existing instanceof fences.
10538
10608
  if (arms?.every((arm) => arm.kind === "object" ||
10539
10609
  arm.kind === "record" ||
10610
+ arm.kind === "array" ||
10540
10611
  arm.kind === "f64" ||
10541
10612
  arm.kind === "string" ||
10542
10613
  arm.kind === "bool" ||
@@ -10595,6 +10666,10 @@ export function lowerInstanceOf(lowerer, expr, loc) {
10595
10666
  }
10596
10667
  return { kind: "call", callee: helper, args: [left], type: BOOL, loc };
10597
10668
  }
10669
+ // A class arm could hold an instance: the test cannot be decided
10670
+ // statically.
10671
+ if (arms?.some((arm) => arm.kind === "object"))
10672
+ lowerer.unsupported("SC1090", expr, "'instanceof' on a union of class instances and values without a class prototype test");
10598
10673
  }
10599
10674
  if (left.type.kind !== "object") {
10600
10675
  return readsClassAfter(lowerer, target, expr.right, [{ kind: "exprStmt", expr: left, loc }], {
@@ -13143,7 +13218,7 @@ function lowerFieldCompoundValue(lowerer, access, op, rhsNode, loc) {
13143
13218
  ? { kind: "dynCheck", value: rhs, type: F64, loc: rhs.loc }
13144
13219
  : lowerOptionalNumber(lowerer, rhs, loc);
13145
13220
  if (numericRhs.type.kind !== "f64")
13146
- lowerer.unsupported("SC1043", access);
13221
+ compoundUnsupported(lowerer, access, op, F64, numericRhs.type);
13147
13222
  const value = save({ kind: "bin", op, left: cur, right: numericRhs, type: F64, loc }, "%compoundResult");
13148
13223
  const boxed = { kind: "dynFrom", value, type: DYN, loc };
13149
13224
  body.push({
@@ -13204,22 +13279,16 @@ function lowerFieldCompoundValue(lowerer, access, op, rhsNode, loc) {
13204
13279
  else if (bigintValue) {
13205
13280
  value = bigintValue;
13206
13281
  }
13207
- else if (target.fieldType.kind === "dyn" && isJsSourceFile(access.getSourceFile())) {
13208
- const numeric = ["-", "*", "/", "%", "**"].includes(op);
13209
- const left = lowerer.coerceToExpected(read, DYN);
13210
- const right = lowerer.coerceToExpected(rhs, DYN);
13211
- value = {
13212
- kind: "libCall",
13213
- fn: op === "+" ? "dyn.add" : numeric ? "dyn.arithmetic" : "dyn.bitwise",
13214
- args: op === "+"
13215
- ? [left, right]
13216
- : [left, right, { kind: "strLit", value: op, type: STRING, loc }],
13217
- type: DYN,
13218
- loc,
13219
- };
13282
+ else if ((target.fieldType.kind === "dyn" && isJsSourceFile(access.getSourceFile())) ||
13283
+ // An untyped right operand: the expanded `o.f = o.f op rhs`; the field
13284
+ // write below checks the result into the declared field type.
13285
+ (rhs.type.kind === "dyn" &&
13286
+ lowerer.dynConvertible(read.type) &&
13287
+ lowerer.dynConvertible(target.fieldType))) {
13288
+ value = dynCompoundValue(op, lowerer.coerceToExpected(read, DYN), lowerer.coerceToExpected(rhs, DYN), loc);
13220
13289
  }
13221
13290
  else {
13222
- lowerer.unsupported("SC1043", access);
13291
+ compoundUnsupported(lowerer, access, op, read.type, rhs.type);
13223
13292
  }
13224
13293
  if (storedString && rhs.type.kind === "string" && read.kind === "varRef" && appended !== null) {
13225
13294
  // The field gives up its value before the concat (no code runs in
@@ -13260,6 +13329,11 @@ function lowerStreamObjectProperty(lowerer, expr) {
13260
13329
  if (expr.name.text === "bytesWritten" && isZlibStreamMember(lowerer, expr)) {
13261
13330
  return lowerZlibStreamBytesWritten(lowerer, expr);
13262
13331
  }
13332
+ if (isFsStreamMember(lowerer, expr)) {
13333
+ const member = lowerFsStreamProperty(lowerer, expr);
13334
+ if (member)
13335
+ return member;
13336
+ }
13263
13337
  return lowerStreamProperty(lowerer, expr, info);
13264
13338
  }
13265
13339
  /** The primitive-constructor closure (`String`/`Number`/`Boolean` as a