@scriptc/compiler 0.2.1 → 0.2.2

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 (193) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +59 -4
  2. package/dist/backend/llvm/dyn.d.ts +3 -0
  3. package/dist/backend/llvm/dyn.js +84 -12
  4. package/dist/backend/llvm/dyn.js.map +1 -1
  5. package/dist/backend/llvm/emitter.d.ts +4 -1
  6. package/dist/backend/llvm/emitter.js +20 -5
  7. package/dist/backend/llvm/emitter.js.map +1 -1
  8. package/dist/backend/llvm/emitter.test.js +9 -1
  9. package/dist/backend/llvm/emitter.test.js.map +1 -1
  10. package/dist/backend/llvm/expr-containers.js +5 -0
  11. package/dist/backend/llvm/expr-containers.js.map +1 -1
  12. package/dist/backend/llvm/expr-dynamic.js +30 -5
  13. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  14. package/dist/backend/llvm/expr-stream-bridges.js +70 -9
  15. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  16. package/dist/backend/llvm/expr-stream-callbacks.d.ts +2 -2
  17. package/dist/backend/llvm/expr-stream-callbacks.js +7 -57
  18. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  19. package/dist/backend/llvm/lib-dispatch.js +41 -3
  20. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  21. package/dist/backend/llvm/lib-filesystem.js +12 -9
  22. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  23. package/dist/backend/llvm/lib-shared.js +35 -1
  24. package/dist/backend/llvm/lib-shared.js.map +1 -1
  25. package/dist/backend/may-throw.js +4 -0
  26. package/dist/backend/may-throw.js.map +1 -1
  27. package/dist/backend/native-codegen.d.ts +1 -1
  28. package/dist/backend/native-codegen.js +4 -3
  29. package/dist/backend/native-codegen.js.map +1 -1
  30. package/dist/backend/native-codegen.test.js +11 -0
  31. package/dist/backend/native-codegen.test.js.map +1 -1
  32. package/dist/backend/target-diagnostics.d.ts +5 -0
  33. package/dist/backend/target-diagnostics.js +72 -1
  34. package/dist/backend/target-diagnostics.js.map +1 -1
  35. package/dist/backend/target-diagnostics.test.d.ts +1 -0
  36. package/dist/backend/target-diagnostics.test.js +68 -0
  37. package/dist/backend/target-diagnostics.test.js.map +1 -0
  38. package/dist/coverage/surface-manifest.js +5 -3
  39. package/dist/coverage/surface-manifest.js.map +1 -1
  40. package/dist/executable/executable-cache.d.ts +7 -3
  41. package/dist/executable/executable-cache.js +47 -11
  42. package/dist/executable/executable-cache.js.map +1 -1
  43. package/dist/executable/executable-cache.test.js +109 -2
  44. package/dist/executable/executable-cache.test.js.map +1 -1
  45. package/dist/executable/prepare.js +2 -1
  46. package/dist/executable/prepare.js.map +1 -1
  47. package/dist/frontend/builtin-modules.d.ts +1 -1
  48. package/dist/frontend/builtin-modules.js +1 -1
  49. package/dist/frontend/builtin-modules.js.map +1 -1
  50. package/dist/frontend/function-completion.d.ts +6 -0
  51. package/dist/frontend/function-completion.js +50 -0
  52. package/dist/frontend/function-completion.js.map +1 -0
  53. package/dist/frontend/lowering/abstract-equality.js +5 -1
  54. package/dist/frontend/lowering/abstract-equality.js.map +1 -1
  55. package/dist/frontend/lowering/checked-iterable-spread.d.ts +4 -0
  56. package/dist/frontend/lowering/checked-iterable-spread.js +30 -0
  57. package/dist/frontend/lowering/checked-iterable-spread.js.map +1 -0
  58. package/dist/frontend/lowering/checked-promise-all.d.ts +5 -0
  59. package/dist/frontend/lowering/checked-promise-all.js +31 -0
  60. package/dist/frontend/lowering/checked-promise-all.js.map +1 -0
  61. package/dist/frontend/lowering/class-callbacks.d.ts +1 -1
  62. package/dist/frontend/lowering/class-callbacks.js +7 -6
  63. package/dist/frontend/lowering/class-callbacks.js.map +1 -1
  64. package/dist/frontend/lowering/class-construction.d.ts +2 -0
  65. package/dist/frontend/lowering/class-construction.js +34 -5
  66. package/dist/frontend/lowering/class-construction.js.map +1 -1
  67. package/dist/frontend/lowering/class-descriptors.d.ts +1 -1
  68. package/dist/frontend/lowering/class-descriptors.js +12 -5
  69. package/dist/frontend/lowering/class-descriptors.js.map +1 -1
  70. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +25 -0
  71. package/dist/frontend/lowering/class-dynamic-dispatch.js +597 -78
  72. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  73. package/dist/frontend/lowering/class-dynamic-dispatch.test.js +64 -2
  74. package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
  75. package/dist/frontend/lowering/class-instance-constructor.d.ts +1 -1
  76. package/dist/frontend/lowering/class-instance-constructor.js +11 -41
  77. package/dist/frontend/lowering/class-instance-constructor.js.map +1 -1
  78. package/dist/frontend/lowering/class-method-values.d.ts +16 -0
  79. package/dist/frontend/lowering/class-method-values.js +60 -29
  80. package/dist/frontend/lowering/class-method-values.js.map +1 -1
  81. package/dist/frontend/lowering/class-prototypes.d.ts +5 -1
  82. package/dist/frontend/lowering/class-prototypes.js +69 -10
  83. package/dist/frontend/lowering/class-prototypes.js.map +1 -1
  84. package/dist/frontend/lowering/class-runtime-statics.d.ts +4 -4
  85. package/dist/frontend/lowering/class-runtime-statics.js +26 -8
  86. package/dist/frontend/lowering/class-runtime-statics.js.map +1 -1
  87. package/dist/frontend/lowering/class-static-data.d.ts +1 -0
  88. package/dist/frontend/lowering/class-static-data.js +4 -2
  89. package/dist/frontend/lowering/class-static-data.js.map +1 -1
  90. package/dist/frontend/lowering/containers/bytes.js +17 -4
  91. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  92. package/dist/frontend/lowering/containers/string-and-regexp.js +6 -1
  93. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  94. package/dist/frontend/lowering/deferred-module-initializers.d.ts +13 -0
  95. package/dist/frontend/lowering/deferred-module-initializers.js +410 -0
  96. package/dist/frontend/lowering/deferred-module-initializers.js.map +1 -0
  97. package/dist/frontend/lowering/deferred-module-initializers.test.d.ts +1 -0
  98. package/dist/frontend/lowering/deferred-module-initializers.test.js +92 -0
  99. package/dist/frontend/lowering/deferred-module-initializers.test.js.map +1 -0
  100. package/dist/frontend/lowering/expressions/object-literals.js +31 -1
  101. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  102. package/dist/frontend/lowering/expressions/optional-chains.js +3 -3
  103. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
  104. package/dist/frontend/lowering/lower-builtins.d.ts +4 -9
  105. package/dist/frontend/lowering/lower-builtins.js +291 -51
  106. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  107. package/dist/frontend/lowering/lower-calls.js +283 -73
  108. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  109. package/dist/frontend/lowering/lower-classes.d.ts +5 -0
  110. package/dist/frontend/lowering/lower-classes.js +439 -25
  111. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  112. package/dist/frontend/lowering/lower-containers.d.ts +1 -1
  113. package/dist/frontend/lowering/lower-containers.js +39 -17
  114. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  115. package/dist/frontend/lowering/lower-exprs.d.ts +10 -6
  116. package/dist/frontend/lowering/lower-exprs.js +294 -129
  117. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  118. package/dist/frontend/lowering/lower-generators.js +5 -1
  119. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  120. package/dist/frontend/lowering/lower-inspect.js +15 -1
  121. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  122. package/dist/frontend/lowering/lower-island.js +4 -0
  123. package/dist/frontend/lowering/lower-island.js.map +1 -1
  124. package/dist/frontend/lowering/lower-island.test.d.ts +1 -0
  125. package/dist/frontend/lowering/lower-island.test.js +51 -0
  126. package/dist/frontend/lowering/lower-island.test.js.map +1 -0
  127. package/dist/frontend/lowering/lower-modules.d.ts +1 -3
  128. package/dist/frontend/lowering/lower-modules.js +186 -82
  129. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  130. package/dist/frontend/lowering/lower-modules.test.js +69 -1
  131. package/dist/frontend/lowering/lower-modules.test.js.map +1 -1
  132. package/dist/frontend/lowering/lower-stmts.js +100 -35
  133. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  134. package/dist/frontend/lowering/lower-stmts.test.d.ts +1 -0
  135. package/dist/frontend/lowering/lower-stmts.test.js +77 -0
  136. package/dist/frontend/lowering/lower-stmts.test.js.map +1 -0
  137. package/dist/frontend/lowering/lower-stream.js +2 -0
  138. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  139. package/dist/frontend/lowering/lower-url.d.ts +2 -1
  140. package/dist/frontend/lowering/lower-url.js +32 -9
  141. package/dist/frontend/lowering/lower-url.js.map +1 -1
  142. package/dist/frontend/lowering/lowerer.d.ts +26 -9
  143. package/dist/frontend/lowering/lowerer.js +218 -27
  144. package/dist/frontend/lowering/lowerer.js.map +1 -1
  145. package/dist/frontend/lowering/lowerer.test.js +38 -0
  146. package/dist/frontend/lowering/lowerer.test.js.map +1 -1
  147. package/dist/frontend/lowering/module-namespace-elements.d.ts +7 -0
  148. package/dist/frontend/lowering/module-namespace-elements.js +54 -0
  149. package/dist/frontend/lowering/module-namespace-elements.js.map +1 -0
  150. package/dist/frontend/lowering/object-factory-new.d.ts +4 -3
  151. package/dist/frontend/lowering/object-factory-new.js +27 -14
  152. package/dist/frontend/lowering/object-factory-new.js.map +1 -1
  153. package/dist/frontend/lowering/surfaces.d.ts +1 -0
  154. package/dist/frontend/lowering/surfaces.js +24 -12
  155. package/dist/frontend/lowering/surfaces.js.map +1 -1
  156. package/dist/frontend/lowering/text-decoder-encoding.js +3 -0
  157. package/dist/frontend/lowering/text-decoder-encoding.js.map +1 -1
  158. package/dist/frontend/lowering/text-decoder-encoding.test.js +2 -1
  159. package/dist/frontend/lowering/text-decoder-encoding.test.js.map +1 -1
  160. package/dist/frontend/program.js +4 -2
  161. package/dist/frontend/program.js.map +1 -1
  162. package/dist/frontend/type-mapper.js +83 -14
  163. package/dist/frontend/type-mapper.js.map +1 -1
  164. package/dist/frontend/union-discriminants.js +22 -7
  165. package/dist/frontend/union-discriminants.js.map +1 -1
  166. package/dist/index.js +16 -10
  167. package/dist/index.js.map +1 -1
  168. package/dist/ir/ir.d.ts +27 -13
  169. package/dist/ir/ir.js +26 -2
  170. package/dist/ir/ir.js.map +1 -1
  171. package/dist/ir/serialize.js +21 -1
  172. package/dist/ir/serialize.js.map +1 -1
  173. package/dist/ir/serialize.test.js +21 -0
  174. package/dist/ir/serialize.test.js.map +1 -1
  175. package/dist/ir/traverse.d.ts +0 -3
  176. package/dist/ir/traverse.js +33 -20
  177. package/dist/ir/traverse.js.map +1 -1
  178. package/dist/ir/validate.js +56 -5
  179. package/dist/ir/validate.js.map +1 -1
  180. package/dist/ir/validate.test.js +17 -1
  181. package/dist/ir/validate.test.js.map +1 -1
  182. package/dist/library/compiler-self-identity.js +1 -1
  183. package/dist/library/compiler-self-identity.test.js +2 -2
  184. package/dist/library/compiler-self-identity.test.js.map +1 -1
  185. package/dist/library/int-infer.d.ts +2 -2
  186. package/dist/library/int-infer.js +10 -7
  187. package/dist/library/int-infer.js.map +1 -1
  188. package/dist/library/int-infer.test.js +44 -0
  189. package/dist/library/int-infer.test.js.map +1 -1
  190. package/dist/library/prepare.js +2 -1
  191. package/dist/library/prepare.js.map +1 -1
  192. package/package.json +20 -20
  193. package/surface-manifest.json +115 -13
@@ -1,4 +1,5 @@
1
1
  import { staticTextDecoderEncoding } from "./text-decoder-encoding.js";
2
+ import { checkedPromiseAll } from "./checked-promise-all.js";
2
3
  import { InternalCompilerError } from "../../errors.js";
3
4
  /* Builtin-surface lowering: node builtin-module calls (fs, path, os, url,
4
5
  * crypto, child_process spawn/spawnSync and child/stats/spawn-result
@@ -1414,12 +1415,36 @@ function lowerZlibModuleCall(lowerer, expr, bi, loc) {
1414
1415
  }
1415
1416
  export function lowerBuiltinModuleCall(lowerer, expr, bi, fn, loc) {
1416
1417
  const name = expr.expression.getText();
1418
+ if (bi.module === "process" && bi.member === "loadEnvFile")
1419
+ return lowerProcessLoadEnvFile(lowerer, expr);
1420
+ if (bi.module === "buffer" && ["isAscii", "isUtf8", "transcode"].includes(bi.member)) {
1421
+ if (expr.arguments.some(ts.isSpreadElement))
1422
+ lowerer.noLowering("buffer encoding call with spread arguments", expr);
1423
+ const arity = bi.member === "transcode" ? 3 : 1;
1424
+ const args = Array.from({ length: arity }, (_, index) => expr.arguments[index]
1425
+ ? lowerer.lowerExprExpecting(stripTypeCasts(expr.arguments[index]), DYN) : dynUndefinedExpr(loc));
1426
+ if (expr.arguments.length > arity)
1427
+ lowerer.noLowering("buffer encoding call with extra arguments", expr);
1428
+ return { kind: "libCall", fn: fn.fn, args, type: fn.result, loc };
1429
+ }
1417
1430
  if (fn.fn === "fs.callbackCall" && bi.member !== "rename") {
1418
1431
  if (expr.arguments.some(ts.isSpreadElement))
1419
1432
  lowerer.noLowering("filesystem callback call with spread arguments", expr);
1420
1433
  const args = { kind: "dynArrLit", elems: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
1421
1434
  return { kind: "libCall", fn: "fs.callbackCall", args: [{ kind: "strLit", value: bi.member, type: STRING, loc }, args], type: DYN, loc };
1422
1435
  }
1436
+ if (bi.module === "fs" && (bi.member === "readvSync" || bi.member === "writevSync" || bi.member === "ftruncateSync")) {
1437
+ const vector = bi.member !== "ftruncateSync";
1438
+ const required = vector ? 2 : 1;
1439
+ if (expr.arguments.length < required || expr.arguments.length > required + 1 || expr.arguments.some(ts.isSpreadElement))
1440
+ lowerer.noLowering(`${name} with this argument shape`, expr);
1441
+ const args = [lowerer.lowerExprExpecting(expr.arguments[0], F64)];
1442
+ if (vector)
1443
+ args.push(lowerer.lowerExprExpecting(expr.arguments[1], arrayOf(BYTES_U8)));
1444
+ const optional = expr.arguments[required];
1445
+ args.push(optional ? lowerBuiltinOptionalDefault(lowerer, optional, F64, numLit(vector ? -1 : 0, loc), vector) : numLit(vector ? -1 : 0, loc));
1446
+ return { kind: "libCall", fn: fn.fn, args, type: vector ? F64 : VOID, loc };
1447
+ }
1423
1448
  // Numeric open flags are interpreted symbolically at the call site. The
1424
1449
  // O_* bit values differ between Darwin and Linux, so emit a stable mask
1425
1450
  // and let the target runtime select its own native constants.
@@ -2344,6 +2369,19 @@ export function lowerReflectCall(lowerer, call, access) {
2344
2369
  }
2345
2370
  if (call.questionDotToken)
2346
2371
  return null;
2372
+ const reflectMember = lowerer.stdlibGlobalMember(access, "Reflect");
2373
+ if (reflectMember === "get" || reflectMember === "set") {
2374
+ const required = reflectMember === "get" ? 2 : 3;
2375
+ if (call.arguments.length < required || call.arguments.length > required + 1 || call.arguments.some(ts.isSpreadElement)) {
2376
+ lowerer.noLowering(`Reflect.${reflectMember} with this argument shape`, call, `use Reflect.${reflectMember}(target, key${reflectMember === "set" ? ", value" : ""}, receiver?)`);
2377
+ }
2378
+ const loc = locOf(call);
2379
+ const args = call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN));
2380
+ const target = call.arguments.length === required ? lowerer.declareHiddenLocal("%reflectTarget", DYN) : null;
2381
+ const operation = { kind: "libCall", fn: reflectMember === "get" ? "dyn.reflectGet" : "dyn.reflectSet",
2382
+ args: target ? [varRef(target.id, DYN, loc), ...args.slice(1), varRef(target.id, DYN, loc)] : args, type: reflectMember === "get" ? DYN : BOOL, loc };
2383
+ return target ? { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: target.id, init: args[0], loc }], result: operation, type: operation.type, loc } : operation;
2384
+ }
2347
2385
  if (lowerer.stdlibGlobalMember(access, "Reflect") !== "apply")
2348
2386
  return null;
2349
2387
  const loc = locOf(call);
@@ -4188,13 +4226,8 @@ function isStringDecoderTyped(lowerer, node) {
4188
4226
  return lowerer.checker.declarationsOf(sym).some((d) => (ts.isClassDeclaration(d) || ts.isInterfaceDeclaration(d)) &&
4189
4227
  lowerer.isStdlibFile(d.getSourceFile()));
4190
4228
  }
4191
- /** Method calls on StringDecoder receivers: `d.write(chunk)` decodes the
4192
- * complete prefix of pending+chunk and re-buffers the trailing partial
4193
- * sequence; `d.end()` flushes the buffered partial as its replacement
4194
- * chars — Node's utf8 StringDecoder exactly (SEMANTICS.md), through the
4195
- * interned %strdec helpers over the packed-f64 pending field. end(buf)
4196
- * and the rest of @types/node's surface fence per member. Null for
4197
- * non-decoder receivers. */
4229
+ /** StringDecoder writes preserve pending bytes; end(input) performs the
4230
+ * final write and flushes the state. String input passes through unchanged. */
4198
4231
  export function lowerStringDecoderMethodCall(lowerer, call, access) {
4199
4232
  if (call.questionDotToken || access.questionDotToken)
4200
4233
  return null;
@@ -4204,29 +4237,37 @@ export function lowerStringDecoderMethodCall(lowerer, call, access) {
4204
4237
  return null;
4205
4238
  const name = access.name.text;
4206
4239
  const loc = locOf(call);
4207
- if (name === "write" && call.arguments.length === 1) {
4208
- const receiver = lowerer.lowerExpr(access.expression);
4209
- if (receiver.type.kind !== "record")
4210
- lowerer.badType(access.expression, lowerer.typeOf(access.expression));
4211
- let chunk = lowerBuiltinValuePreservingUndefined(lowerer, call.arguments[0]);
4212
- chunk = checkedOptionalBuiltinArm(lowerer, chunk, BYTES_U8) ?? chunk;
4213
- if (!(chunk.type.kind === "bytes" && chunk.type.elem === "u8")) {
4214
- lowerer.noLowering(`StringDecoder.write of '${lowerer.fmt(chunk.type)}' data`, call.arguments[0], "Buffer/Uint8Array chunks decode (narrow unions first)");
4215
- }
4216
- const helper = lowerer.strdecHelper("write", receiver.type.shapeId, loc);
4217
- return { kind: "call", callee: helper, args: [receiver, chunk], type: STRING, loc };
4240
+ if ((name !== "write" && name !== "end") || call.arguments.length > 1 ||
4241
+ (name === "write" && call.arguments.length !== 1) || call.arguments.some(ts.isSpreadElement)) {
4242
+ lowerer.noLowering(`StringDecoder.${name}`, call, "use write(input) or end(input?)", lowerer.checker.getSymbolAtLocation(access.name));
4218
4243
  }
4219
- if (name === "end") {
4220
- if (call.arguments.length !== 0) {
4221
- lowerer.noLowering("StringDecoder.end with a buffer argument", call, "write the buffer, then end(): d.write(buf) + d.end() is Node's own equivalence");
4222
- }
4223
- const receiver = lowerer.lowerExpr(access.expression);
4224
- if (receiver.type.kind !== "record")
4225
- lowerer.badType(access.expression, lowerer.typeOf(access.expression));
4226
- const helper = lowerer.strdecHelper("end", receiver.type.shapeId, loc);
4227
- return { kind: "call", callee: helper, args: [receiver], type: STRING, loc };
4244
+ const receiver = lowerer.lowerExpr(access.expression);
4245
+ if (receiver.type.kind !== "record")
4246
+ lowerer.badType(access.expression, lowerer.typeOf(access.expression));
4247
+ if (call.arguments.length === 0) {
4248
+ return { kind: "call", callee: lowerer.strdecHelper("end", receiver.type.shapeId, loc), args: [receiver], type: STRING, loc };
4249
+ }
4250
+ const node = call.arguments[0];
4251
+ const undefinedArg = name === "end" ? lowerStaticallyUndefinedArgument(lowerer, node) : null;
4252
+ if (undefinedArg) {
4253
+ const saved = lowerer.declareHiddenLocal("%strdecRecv", receiver.type);
4254
+ const result = { kind: "call", callee: lowerer.strdecHelper("end", receiver.type.shapeId, loc), args: [varRef(saved.id, receiver.type, loc)], type: STRING, loc };
4255
+ return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: saved.id, init: receiver, loc }], result: defaultAfterUndefined(undefinedArg, result), type: STRING, loc };
4228
4256
  }
4229
- lowerer.noLowering(`StringDecoder.${name}`, call, "write(buffer) and end() are the supported StringDecoder members", lowerer.checker.getSymbolAtLocation(access.name));
4257
+ let chunk = lowerBuiltinValuePreservingUndefined(lowerer, node);
4258
+ if (chunk.type.kind === "string") {
4259
+ const op = name === "end" ? "endString" : "writeString";
4260
+ return { kind: "call", callee: lowerer.strdecHelper(op, receiver.type.shapeId, loc), args: [receiver, chunk], type: STRING, loc };
4261
+ }
4262
+ chunk = checkedOptionalBuiltinArm(lowerer, chunk, BYTES_U8) ?? chunk;
4263
+ if (chunk.type.kind === "bytes" && chunk.type.elem !== "u8") {
4264
+ chunk = { kind: "libCall", fn: "bytes.bufferSource", args: [lowerer.coerceInto(node, chunk, DYN)], type: BYTES_U8, loc };
4265
+ }
4266
+ if (!(chunk.type.kind === "bytes" && chunk.type.elem === "u8")) {
4267
+ lowerer.noLowering(`StringDecoder.${name} of '${lowerer.fmt(chunk.type)}' data`, node, "pass a string or typed-array view (narrow unions first)");
4268
+ }
4269
+ const helper = lowerer.strdecHelper(name === "end" ? "endChunk" : "write", receiver.type.shapeId, loc);
4270
+ return { kind: "call", callee: helper, args: [receiver, chunk], type: STRING, loc };
4230
4271
  }
4231
4272
  /** The interned %strdec helpers: write(d, chunk) returns the decoded
4232
4273
  * complete prefix and re-buffers the trailing partial into the pending
@@ -4264,7 +4305,7 @@ export function strdecHelper(lowerer, op, shapeId, loc) {
4264
4305
  { id: "s.0", name: "s", type: STRING, mutable: false },
4265
4306
  ];
4266
4307
  let body;
4267
- if (op === "write") {
4308
+ if (op === "write" || op === "endChunk") {
4268
4309
  params.push({ localId: "chunk.0", name: "chunk", type: BYTES_U8 });
4269
4310
  locals.splice(1, 0, { id: "chunk.0", name: "chunk", type: BYTES_U8, mutable: false });
4270
4311
  body = [
@@ -4304,6 +4345,24 @@ export function strdecHelper(lowerer, op, shapeId, loc) {
4304
4345
  { kind: "return", value: varRef("s.0", STRING, loc), loc },
4305
4346
  ];
4306
4347
  }
4348
+ if (op === "endString" || op === "writeString") {
4349
+ const inputT = STRING;
4350
+ params.push({ localId: "chunk.0", name: "chunk", type: inputT });
4351
+ locals.push({ id: "chunk.0", name: "chunk", type: inputT, mutable: false });
4352
+ if (op === "writeString")
4353
+ body = [{ kind: "return", value: varRef("chunk.0", STRING, loc), loc }];
4354
+ if (op === "endString")
4355
+ body[body.length - 1] = { kind: "return", value: {
4356
+ kind: "strConcat", left: varRef("chunk.0", STRING, loc), right: varRef("s.0", STRING, loc), type: STRING, loc,
4357
+ }, loc };
4358
+ }
4359
+ if (op === "endChunk") {
4360
+ locals.push({ id: "tail.0", name: "tail", type: STRING, mutable: false });
4361
+ body.splice(body.length - 1, 0, { kind: "varDecl", localId: "tail.0", init: { kind: "libCall", fn: "strdec.end", args: [encRead(), pendingRead()], type: STRING, loc }, loc }, { kind: "recordSet", obj: varRef("d.0", recT, loc), shapeId, field: "%pending", value: { kind: "numLit", value: 0, type: F64, loc }, loc });
4362
+ body[body.length - 1] = { kind: "return", value: {
4363
+ kind: "strConcat", left: varRef("s.0", STRING, loc), right: varRef("tail.0", STRING, loc), type: STRING, loc,
4364
+ }, loc };
4365
+ }
4307
4366
  lowerer.liftedFns.push({ name, params, returnType: STRING, locals, body, loc });
4308
4367
  return name;
4309
4368
  }
@@ -4400,11 +4459,11 @@ export function lowerJsonMethodCall(lowerer, call, access) {
4400
4459
  const optionalString = lowerOptionalStringifyRoot(lowerer, value, indent, loc);
4401
4460
  if (optionalString)
4402
4461
  return optionalString;
4403
- if (value.type.kind === "dyn" || isJsonStringifyDynamicType(value.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
4462
+ if (value.type.kind === "url" || value.type.kind === "dyn" || isJsonStringifyDynamicType(value.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
4404
4463
  // Keep the original containers live while the runtime visits them:
4405
4464
  // a toJSON callback can mutate a later field, and shared/cyclic
4406
4465
  // references must retain their identities throughout traversal.
4407
- const boxed = value.type.kind === "dyn" ? value : { kind: "dynFrom", value, liveRef: true, type: DYN, loc };
4466
+ const boxed = value.type.kind === "dyn" ? value : { kind: "dynFrom", value, ...(value.type.kind === "url" ? {} : { liveRef: true }), type: DYN, loc };
4408
4467
  const raw = {
4409
4468
  kind: "libCall", fn: "json.stringifyReplacer",
4410
4469
  args: [boxed, dynUndefinedExpr(loc), { kind: "strLit", value: indent, type: STRING, loc }],
@@ -4742,8 +4801,8 @@ function cryptoEncoding(lowerer, node, use) {
4742
4801
  }
4743
4802
  function cryptoAlgorithm(lowerer, node, use) {
4744
4803
  const type = lowerer.typeOf(node);
4745
- if (type.isStringLiteralType() && !["md5", "sha1", "sha256"].includes(type.value.toLowerCase())) {
4746
- lowerer.noLowering(`${use} with algorithm '${type.value}'`, node, "md5, sha1, and sha256 are the lowered digest algorithms");
4804
+ if (type.isStringLiteralType() && !["md5", "sha1", "sha224", "sha256", "sha384", "sha512"].includes(type.value.toLowerCase())) {
4805
+ lowerer.noLowering(`${use} with algorithm '${type.value}'`, node, "md5, sha1, sha224, sha256, sha384, and sha512 are the lowered digest algorithms");
4747
4806
  }
4748
4807
  return lowerer.lowerExprExpecting(node, STRING);
4749
4808
  }
@@ -4762,7 +4821,19 @@ function cryptoInputBytes(lowerer, node, loc) {
4762
4821
  }
4763
4822
  lowerer.noLowering(`crypto byte input of '${lowerer.fmt(value.type)}' values`, node, "string and Buffer/Uint8Array values are supported");
4764
4823
  }
4765
- function errorFirstBytesCallback(lowerer, node, api) {
4824
+ function cryptoKdfInput(lowerer, node) {
4825
+ const loc = locOf(node);
4826
+ const type = lowerer.mapTypeOf(lowerer.typeOf(node));
4827
+ if (type?.kind === "string" || (type?.kind === "bytes" && type.elem === "u8"))
4828
+ return cryptoInputBytes(lowerer, node, loc);
4829
+ const symbol = lowerer.typeOf(node).getSymbol();
4830
+ if (type?.kind === "bytes" || (symbol?.name === "ArrayBuffer" && lowerer.isStdlibSymbol(symbol))) {
4831
+ const value = lowerer.coerceInto(node, lowerer.lowerExpr(node), DYN);
4832
+ return { kind: "libCall", fn: "bytes.bufferSource", args: [value], type: BYTES_U8, loc };
4833
+ }
4834
+ lowerer.noLowering("crypto key derivation with this input", node, "strings, Buffers, numeric typed arrays, DataViews, and fixed-length ArrayBuffers are supported; KeyObjects are not yet lowered");
4835
+ }
4836
+ function errorFirstBytesCallback(lowerer, node, api, arrayBuffer = false) {
4766
4837
  let callback = lowerer.lowerExpr(node);
4767
4838
  if (callback.type.kind === "dyn") {
4768
4839
  callback = { kind: "dynCheck", value: callback, type: funcOf([DYN, DYN], VOID), loc: locOf(node) };
@@ -4784,8 +4855,8 @@ function errorFirstBytesCallback(lowerer, node, api) {
4784
4855
  lowerer.unsupported("SC1090", node, `${api} callback error parameters must be Error | null`);
4785
4856
  }
4786
4857
  const value = callback.type.params[1];
4787
- if (value !== undefined && value.kind !== "dyn" && !(value.kind === "bytes" && value.elem === "u8")) {
4788
- lowerer.unsupported("SC1090", node, `${api} callback result parameters must be Buffer/Uint8Array values`);
4858
+ if (value !== undefined && value.kind !== "dyn" && (arrayBuffer || !(value.kind === "bytes" && value.elem === "u8"))) {
4859
+ lowerer.unsupported("SC1090", node, `${api} callback result parameters must be ${arrayBuffer ? "ArrayBuffer" : "Buffer/Uint8Array"} values`);
4789
4860
  }
4790
4861
  return voidizedCallback(lowerer, callback, locOf(node));
4791
4862
  }
@@ -4833,6 +4904,31 @@ export function lowerCryptoModuleCall(lowerer, expr, bi, loc) {
4833
4904
  loc,
4834
4905
  };
4835
4906
  }
4907
+ if (bi.member === "hkdf" || bi.member === "hkdfSync") {
4908
+ const async = bi.member === "hkdf";
4909
+ if (args.length !== (async ? 6 : 5))
4910
+ lowerer.noLowering(`crypto.${bi.member} with ${args.length} arguments`, expr);
4911
+ const values = [
4912
+ cryptoAlgorithm(lowerer, args[0], `crypto.${bi.member}`),
4913
+ cryptoKdfInput(lowerer, args[1]), cryptoKdfInput(lowerer, args[2]), cryptoKdfInput(lowerer, args[3]),
4914
+ lowerer.lowerExprExpecting(args[4], F64),
4915
+ ];
4916
+ if (async)
4917
+ values.push(errorFirstBytesCallback(lowerer, args[5], "crypto.hkdf", true));
4918
+ return { kind: "libCall", fn: async ? "crypto.hkdfCb" : "crypto.hkdf", args: values, type: async ? VOID : DYN, loc };
4919
+ }
4920
+ if (bi.member === "scrypt" || bi.member === "scryptSync") {
4921
+ const async = bi.member === "scrypt";
4922
+ const minimum = async ? 4 : 3;
4923
+ if (args.length < minimum || args.length > minimum + 1)
4924
+ lowerer.noLowering(`crypto.${bi.member} with ${args.length} arguments`, expr);
4925
+ const values = [cryptoKdfInput(lowerer, args[0]), cryptoKdfInput(lowerer, args[1]), lowerer.lowerExprExpecting(args[2], F64)];
4926
+ const options = args.length > minimum ? args[3] : undefined;
4927
+ values.push(options ? lowerer.coerceInto(options, lowerer.lowerExpr(options), DYN) : dynUndefinedExpr(loc));
4928
+ if (async)
4929
+ values.push(errorFirstBytesCallback(lowerer, args[args.length - 1], "crypto.scrypt"));
4930
+ return { kind: "libCall", fn: async ? "crypto.scryptCb" : "crypto.scrypt", args: values, type: async ? VOID : BYTES_U8, loc };
4931
+ }
4836
4932
  if (bi.member === "createHash") {
4837
4933
  if (args.length !== 1) {
4838
4934
  lowerer.noLowering(`crypto.createHash with ${args.length} arguments`, expr, "createHash(algorithm) is supported; options are not yet lowered");
@@ -4940,7 +5036,7 @@ export function lowerCryptoModuleCall(lowerer, expr, bi, loc) {
4940
5036
  loc,
4941
5037
  };
4942
5038
  }
4943
- /** Method calls on URL-typed receivers: `u.toString()` is Node's href
5039
+ /** Method calls on URL-typed receivers: `u.toString()` and `u.toJSON()` are Node's href
4944
5040
  * serialization (the href getter's libCall). Everything else the lib
4945
5041
  * declares fences member-qualified. Null for non-URL receivers. */
4946
5042
  export function lowerUrlMethodCall(lowerer, call, access) {
@@ -4951,11 +5047,11 @@ export function lowerUrlMethodCall(lowerer, call, access) {
4951
5047
  if (!lowerer.isStdlibMember(access))
4952
5048
  return null;
4953
5049
  const name = access.name.text;
4954
- if (name === "toString" && call.arguments.length === 0) {
5050
+ if ((name === "toString" || name === "toJSON") && call.arguments.length === 0) {
4955
5051
  const receiver = lowerer.lowerExpr(access.expression);
4956
5052
  return { kind: "libCall", fn: "url.href", args: [receiver], type: STRING, loc: locOf(call) };
4957
5053
  }
4958
- lowerer.noLowering(`URL.${name}`, call, "protocol, origin, username, password, pathname, href, host, hostname, port, search, hash, searchParams, and toString() are the supported URL members", lowerer.checker.getSymbolAtLocation(access.name));
5054
+ lowerer.noLowering(`URL.${name}`, call, "protocol, origin, username, password, pathname, href, host, hostname, port, search, hash, searchParams, toString(), and toJSON() are the supported URL members", lowerer.checker.getSymbolAtLocation(access.name));
4959
5055
  }
4960
5056
  /** `new URLSearchParams(init?)` — the WHATWG constructor's lowered init
4961
5057
  * shapes: omitted / literal `undefined` (empty list), a string (parsed,
@@ -5329,18 +5425,21 @@ export function lowerFileHandleMethodCall(lowerer, call, access) {
5329
5425
  const loc = locOf(call);
5330
5426
  const receiver = () => lowerer.lowerExprExpecting(access.expression, FILEHANDLE_T);
5331
5427
  const promise = (inner) => ({ kind: "promise", inner });
5332
- const num = (node, dflt) => {
5428
+ const num = (node, dflt, lowered) => {
5333
5429
  const defaultValue = { kind: "numLit", value: dflt, type: F64, loc };
5334
- if (!node)
5430
+ if (!node && !lowered)
5335
5431
  return { value: defaultValue, defaulted: boolLit(true, loc) };
5336
- const undefinedArg = lowerStaticallyUndefinedArgument(lowerer, node);
5432
+ if (lowered && isUnitType(lowered.type)) {
5433
+ return { value: defaultAfterUndefined(lowered, defaultValue), defaulted: boolLit(true, loc) };
5434
+ }
5435
+ const undefinedArg = !lowered && node ? lowerStaticallyUndefinedArgument(lowerer, node) : null;
5337
5436
  if (undefinedArg) {
5338
5437
  return { value: defaultAfterUndefined(undefinedArg, defaultValue), defaulted: boolLit(true, loc) };
5339
5438
  }
5340
- if ((lowerer.typeOf(node).flags & ts.TypeFlags.Null) !== 0) {
5439
+ if (!lowered && node && (lowerer.typeOf(node).flags & ts.TypeFlags.Null) !== 0) {
5341
5440
  return { value: defaultAfterUndefined(lowerer.lowerExpr(node), defaultValue), defaulted: boolLit(true, loc) };
5342
5441
  }
5343
- const value = lowerer.lowerExpr(node);
5442
+ const value = lowered ?? lowerer.lowerExpr(node);
5344
5443
  if (value.type.kind === "union") {
5345
5444
  const def = lowerer.unions.get(value.type.unionId);
5346
5445
  const units = def?.arms.filter(isUnitType) ?? [];
@@ -5386,7 +5485,7 @@ export function lowerFileHandleMethodCall(lowerer, call, access) {
5386
5485
  };
5387
5486
  }
5388
5487
  }
5389
- return { value: lowerer.coerceInto(node, value, F64), defaulted: boolLit(false, loc) };
5488
+ return { value: lowerer.coerceInto(node ?? call, value, F64), defaulted: boolLit(false, loc) };
5390
5489
  };
5391
5490
  const utf8 = (node) => {
5392
5491
  const dflt = { kind: "strLit", value: "utf8", type: STRING, loc };
@@ -5401,6 +5500,30 @@ export function lowerFileHandleMethodCall(lowerer, call, access) {
5401
5500
  }
5402
5501
  return lowerBuiltinOptionalDefault(lowerer, node, STRING, dflt, true);
5403
5502
  };
5503
+ if (name === "sync" || name === "datasync") {
5504
+ if (call.arguments.length !== 0)
5505
+ lowerer.noLowering(`FileHandle.${name} with arguments`, call);
5506
+ return { kind: "libCall", fn: name === "sync" ? "fileHandle.sync" : "fileHandle.datasync", args: [receiver()], type: promise(VOID), loc };
5507
+ }
5508
+ if (name === "truncate" || name === "chmod") {
5509
+ if (call.arguments.length > 1 || (name === "chmod" && call.arguments.length !== 1))
5510
+ lowerer.noLowering(`FileHandle.${name} with ${call.arguments.length} arguments`, call);
5511
+ return {
5512
+ kind: "libCall", fn: name === "truncate" ? "fileHandle.truncate" : "fileHandle.chmod",
5513
+ args: [receiver(), num(call.arguments[0], 0).value], type: promise(VOID), loc,
5514
+ };
5515
+ }
5516
+ if (name === "readv" || name === "writev") {
5517
+ if (call.arguments.length < 1 || call.arguments.length > 2)
5518
+ lowerer.noLowering(`FileHandle.${name} with ${call.arguments.length} arguments`, call);
5519
+ const type = lowerer.mapTypeOf(lowerer.typeOf(call));
5520
+ if (type?.kind !== "promise" || type.inner.kind !== "record")
5521
+ lowerer.badType(call, lowerer.typeOf(call));
5522
+ return {
5523
+ kind: "libCall", fn: name === "readv" ? "fileHandle.readv" : "fileHandle.writev",
5524
+ args: [receiver(), lowerer.lowerExprExpecting(call.arguments[0], arrayOf(BYTES_U8)), num(call.arguments[1], -1).value], type, loc,
5525
+ };
5526
+ }
5404
5527
  if (name === "close" || name === "stat") {
5405
5528
  if (call.arguments.length !== 0)
5406
5529
  lowerer.noLowering(`FileHandle.${name} with arguments`, call);
@@ -5458,6 +5581,65 @@ export function lowerFileHandleMethodCall(lowerer, call, access) {
5458
5581
  }
5459
5582
  lowerer.noLowering(`FileHandle.${name} of '${dataT ? lowerer.fmt(dataT) : lowerer.checker.typeToString(lowerer.typeOf(dataNode))}' data`, dataNode, "string and Uint8Array data are supported");
5460
5583
  }
5584
+ if (name === "read" || name === "write") {
5585
+ const firstNode = call.arguments[0];
5586
+ const firstT = firstNode ? lowerer.mapTypeOf(lowerer.typeOf(firstNode)) : undefined;
5587
+ const secondT = call.arguments[1] ? lowerer.mapTypeOf(lowerer.typeOf(call.arguments[1])) : undefined;
5588
+ const readOptions = name === "read" && (!firstNode || firstT?.kind === "record" || (firstT && isUnitType(firstT)));
5589
+ const bufferOptions = firstT?.kind === "bytes" && firstT.elem === "u8" && secondT?.kind === "record";
5590
+ if (readOptions || bufferOptions) {
5591
+ if (call.arguments.length > (bufferOptions ? 2 : 1))
5592
+ lowerer.noLowering(`FileHandle.${name} options with extra arguments`, call);
5593
+ const type = lowerer.mapTypeOf(lowerer.typeOf(call));
5594
+ if (type?.kind !== "promise" || type.inner.kind !== "record")
5595
+ lowerer.badType(call, lowerer.typeOf(call));
5596
+ const stmts = [];
5597
+ const stage = (value, label) => {
5598
+ const local = lowerer.declareHiddenLocal(label, value.type);
5599
+ stmts.push({ kind: "varDecl", localId: local.id, init: value, loc: value.loc });
5600
+ return varRef(local.id, local.type, loc);
5601
+ };
5602
+ const handle = stage(receiver(), "%fhWindowReceiver");
5603
+ let buffer = bufferOptions ? stage(lowerer.lowerExprExpecting(firstNode, BYTES_U8), "%fhWindowBuffer") : undefined;
5604
+ const optionsNode = bufferOptions ? call.arguments[1] : firstNode;
5605
+ const options = optionsNode ? stage(lowerer.lowerExpr(optionsNode), "%fhWindowOptions") : undefined;
5606
+ const field = (key) => {
5607
+ if (options?.type.kind !== "record")
5608
+ return undefined;
5609
+ const fields = lowerer.shapes.get(options.type.shapeId)?.fields;
5610
+ const getter = fields?.find((f) => f.name === `%get:${key}`);
5611
+ if (getter?.type.kind === "func") {
5612
+ const callee = { kind: "recordGet", obj: options, shapeId: options.type.shapeId, field: getter.name, type: getter.type, loc };
5613
+ return { kind: "callValue", callee, args: [], type: getter.type.ret, loc };
5614
+ }
5615
+ const member = fields?.find((f) => f.name === key);
5616
+ return member ? { kind: "recordGet", obj: options, shapeId: options.type.shapeId, field: key, type: member.type, loc } : undefined;
5617
+ };
5618
+ if (!buffer) {
5619
+ const supplied = field("buffer");
5620
+ const fresh = { kind: "bytesNew", source: numLit(16384, loc), type: BYTES_U8, loc };
5621
+ if (!supplied || isUnitType(supplied.type))
5622
+ buffer = supplied ? defaultAfterUndefined(supplied, fresh) : fresh;
5623
+ else if (supplied.type.kind === "union") {
5624
+ const arms = lowerer.unions.get(supplied.type.unionId)?.arms;
5625
+ if (!arms?.every((arm) => typeEquals(arm, BYTES_U8) || isUnitType(arm)))
5626
+ lowerer.noLowering("FileHandle.read with this buffer type", call);
5627
+ buffer = { kind: "nullish", left: supplied, right: fresh, type: BYTES_U8, loc };
5628
+ }
5629
+ else
5630
+ buffer = lowerer.coerceInto(call, supplied, BYTES_U8);
5631
+ buffer = stage(buffer, "%fhWindowBuffer");
5632
+ }
5633
+ const offset = num(undefined, 0, field("offset"));
5634
+ const length = num(undefined, -1, field("length"));
5635
+ const position = num(undefined, -1, field("position"));
5636
+ const result = {
5637
+ kind: "libCall", fn: name === "read" ? "fileHandle.read" : "fileHandle.writeBytes",
5638
+ args: [handle, buffer, offset.value, length.value, position.value, length.defaulted], type, loc,
5639
+ };
5640
+ return { kind: "seqExpr", stmts, result, type, loc };
5641
+ }
5642
+ }
5461
5643
  if (name === "read") {
5462
5644
  if (call.arguments.length < 1 || call.arguments.length > 4) {
5463
5645
  lowerer.noLowering(`FileHandle.read with ${call.arguments.length} arguments`, call, "use read(buffer[, offset[, length[, position]]])");
@@ -5516,7 +5698,7 @@ export function lowerFileHandleMethodCall(lowerer, call, access) {
5516
5698
  }
5517
5699
  lowerer.noLowering(`FileHandle.write of '${dataT ? lowerer.fmt(dataT) : lowerer.checker.typeToString(lowerer.typeOf(dataNode))}' data`, dataNode, "string and Uint8Array data are supported");
5518
5700
  }
5519
- lowerer.noLowering(`FileHandle.${name}`, call, "fd, close(), read(), write(), readFile(), writeFile(), appendFile(), and stat() are the supported FileHandle members", lowerer.checker.getSymbolAtLocation(access.name));
5701
+ lowerer.noLowering(`FileHandle.${name}`, call, "fd, close(), read(), write(), readv(), writev(), readFile(), writeFile(), appendFile(), stat(), sync(), datasync(), truncate(), and chmod() are the supported FileHandle members", lowerer.checker.getSymbolAtLocation(access.name));
5520
5702
  }
5521
5703
  /** Method calls on Stats-typed receivers: isFile()/isDirectory()/
5522
5704
  * isSymbolicLink() are pure reads on the stat snapshot (a followed
@@ -5670,6 +5852,21 @@ export function lowerAtomicsCall(lowerer, call, access) {
5670
5852
  export function lowerBuiltinExtraProperty(lowerer, expr) {
5671
5853
  if (expr.questionDotToken && !lowerer.chainHandled.has(expr))
5672
5854
  return null;
5855
+ const codec = storedTextCodecClassOf(lowerer, expr.expression);
5856
+ if (codec && lowerer.isStdlibMember(expr) && ["encoding", "fatal", "ignoreBOM"].includes(expr.name.text)) {
5857
+ const receiver = lowerer.lowerExpr(expr.expression);
5858
+ if (receiver.type.kind !== "record")
5859
+ lowerer.badType(expr.expression, lowerer.typeOf(expr.expression));
5860
+ const loc = locOf(expr);
5861
+ if (codec === "TextEncoder" && expr.name.text === "encoding") {
5862
+ return { kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: receiver, loc }], result: strLit("utf-8", loc), type: STRING, loc };
5863
+ }
5864
+ if (codec === "TextDecoder") {
5865
+ const field = expr.name.text === "encoding" ? "%TextDecoder" : `%${expr.name.text}`;
5866
+ const value = { kind: "recordGet", obj: receiver, shapeId: receiver.type.shapeId, field, type: expr.name.text === "encoding" ? F64 : BOOL, loc };
5867
+ return expr.name.text === "encoding" ? { kind: "libCall", fn: "text.decoderName", args: [value], type: STRING, loc } : value;
5868
+ }
5869
+ }
5673
5870
  // decoder.encoding on a StringDecoder-typed receiver: the record's
5674
5871
  // hidden canonical-name field (construction folded the aliases —
5675
5872
  // exactly what Node's normalized `.encoding` answers).
@@ -5680,6 +5877,15 @@ export function lowerBuiltinExtraProperty(lowerer, expr) {
5680
5877
  return { kind: "recordGet", obj: receiver, shapeId: receiver.type.shapeId, field: "%enc", type: STRING, loc: locOf(expr) };
5681
5878
  }
5682
5879
  const kind = lowerer.mapTypeOf(lowerer.typeOf(expr.expression))?.kind;
5880
+ if (kind === "record" && ["read", "written"].includes(expr.name.text) && lowerer.isStdlibMember(expr)) {
5881
+ const receiver = lowerer.lowerExpr(expr.expression);
5882
+ if (receiver.type.kind === "record") {
5883
+ const fields = lowerer.shapes.get(receiver.type.shapeId)?.fields;
5884
+ if (fields?.length === 2 && fields.every((field) => ["read", "written"].includes(field.name) && field.type.kind === "f64")) {
5885
+ return { kind: "recordGet", obj: receiver, shapeId: receiver.type.shapeId, field: expr.name.text, type: F64, loc: locOf(expr) };
5886
+ }
5887
+ }
5888
+ }
5683
5889
  if (kind !== "stats" && kind !== "fileHandle" && kind !== "spawnRes" && kind !== "child" && kind !== "childWriter")
5684
5890
  return null;
5685
5891
  if (kind === "child" ? !isChildSurfaceMember(lowerer, expr) : !lowerer.isStdlibMember(expr))
@@ -5896,14 +6102,15 @@ export function lowerChildMethodCall(lowerer, call, access) {
5896
6102
  lowerer.checkedCallbackParams.add(param);
5897
6103
  }
5898
6104
  const cb = lowerer.lowerExpr(call.arguments[1]);
5899
- if (cb.type.kind === "func" && cb.type.rest) {
5900
- if (!canBoxFuncIntoDyn(cb.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
5901
- lowerer.noLowering("child event rest listeners with non-representable parameters", call.arguments[1]);
6105
+ if (isJsSourceFile(listenerNode.getSourceFile()) && cb.type.kind === "dyn" ||
6106
+ cb.type.kind === "func" && (cb.type.rest || isJsSourceFile(listenerNode.getSourceFile()) && cb.type.params.some((param) => param.kind === "dyn"))) {
6107
+ if (cb.type.kind !== "dyn" && !canBoxFuncIntoDyn(cb.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
6108
+ lowerer.noLowering("child event listeners with non-representable parameters", call.arguments[1]);
5902
6109
  }
5903
6110
  return {
5904
6111
  kind: "libCall", fn: "child.onDyn",
5905
6112
  args: [receiver, { kind: "strLit", value: event, type: STRING, loc },
5906
- { kind: "dynFrom", value: cb, type: DYN, loc }],
6113
+ cb.type.kind === "dyn" ? cb : { kind: "dynFrom", value: cb, type: DYN, loc }],
5907
6114
  type: VOID, loc,
5908
6115
  };
5909
6116
  }
@@ -6286,7 +6493,8 @@ export function lowerErrorCodeProperty(lowerer, expr) {
6286
6493
  return null;
6287
6494
  if (!lowerer.isStdlibMember(expr))
6288
6495
  return null;
6289
- const receiver = lowerer.lowerExpr(expr.expression);
6496
+ const rawReceiver = lowerer.lowerExpr(expr.expression);
6497
+ const receiver = rawReceiver.type.kind === "dyn" ? lowerer.coerceInto(expr.expression, rawReceiver, recvT) : rawReceiver;
6290
6498
  return {
6291
6499
  kind: "libCall",
6292
6500
  fn: expr.name.text === "stack" ? "error.stack" : expr.name.text === "cause" ? "error.cause" : "error.code",
@@ -6986,6 +7194,19 @@ export function lowerProcessEnvGet(lowerer, expr) {
6986
7194
  const key = { kind: "strLit", value: expr.name.text, type: STRING, loc: locOf(expr.name) };
6987
7195
  return { kind: "libCall", fn: "process.envGet", args: [key], type: lowerer.envValueType(), loc };
6988
7196
  }
7197
+ function lowerProcessLoadEnvFile(lowerer, call) {
7198
+ if (call.arguments.length > 1 || call.arguments.some(ts.isSpreadElement)) {
7199
+ lowerer.noLowering("process.loadEnvFile with spread or extra arguments", call);
7200
+ }
7201
+ const loc = locOf(call);
7202
+ const path = call.arguments[0] ? lowerer.lowerExprExpecting(call.arguments[0], DYN)
7203
+ : { kind: "dynFrom", value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, type: DYN, loc };
7204
+ const load = { kind: "libCall", fn: "process.loadEnvFile", args: [path], type: VOID, loc };
7205
+ if (ts.isExpressionStatement(call.parent))
7206
+ return load;
7207
+ return { kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: load, loc }],
7208
+ result: { kind: "dynFrom", value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, type: DYN, loc }, type: DYN, loc };
7209
+ }
6989
7210
  /** `process.exit(code)` / `process.cwd()` → libCall. The fallback
6990
7211
  * declaration makes exit's code required; @types/node declares it
6991
7212
  * optional. A bare `process.exit()` uses the current exitCode, or zero
@@ -7003,6 +7224,8 @@ export function lowerProcessMethodCall(lowerer, call, access) {
7003
7224
  }
7004
7225
  }
7005
7226
  const directProcessMember = lowerer.stdlibGlobalMember(access, "process");
7227
+ if (directProcessMember === "loadEnvFile")
7228
+ return lowerProcessLoadEnvFile(lowerer, call);
7006
7229
  if (directProcessMember === "hrtime") {
7007
7230
  if (call.arguments.some(ts.isSpreadElement))
7008
7231
  lowerer.noLowering("process.hrtime with spread arguments", call);
@@ -7991,6 +8214,18 @@ export function lowerTextCodecCall(lowerer, call, access) {
7991
8214
  if (call.questionDotToken || access.questionDotToken)
7992
8215
  return null;
7993
8216
  const member = access.name.text;
8217
+ if (member === "encodeInto" && storedTextCodecClassOf(lowerer, access.expression) === "TextEncoder" && lowerer.isStdlibMember(access)) {
8218
+ if (call.arguments.length !== 2 || call.arguments.some(ts.isSpreadElement))
8219
+ lowerer.noLowering("TextEncoder.encodeInto with this argument shape", call);
8220
+ const loc = locOf(call);
8221
+ const receiver = lowerer.lowerExpr(access.expression);
8222
+ const result = { kind: "libCall", fn: "text.encodeInto", args: call.arguments.map((arg) => lowerer.lowerExprExpecting(stripTypeCasts(arg), DYN)), type: DYN, loc };
8223
+ const type = lowerer.mapTypeOf(lowerer.typeOf(call));
8224
+ if (!type)
8225
+ lowerer.badType(call, lowerer.typeOf(call));
8226
+ const checked = lowerer.coerceInto(call, result, type);
8227
+ return { kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: receiver, loc }], result: checked, type, loc };
8228
+ }
7994
8229
  if (member !== "decode" && member !== "encode")
7995
8230
  return null;
7996
8231
  const info = directTextCodecCtorOf(lowerer, access.expression);
@@ -8294,9 +8529,14 @@ export function lowerPromiseStaticCall(lowerer, call, access) {
8294
8529
  lowerer.diags.splice(diagsBefore);
8295
8530
  }
8296
8531
  }
8532
+ if (!lowerer.dynamic && isJsSourceFile(call.getSourceFile()) && elems.every((entry) => lowerer.dynConvertible(entry.type))) {
8533
+ return checkedPromiseAll(lowerer, { kind: "arrayLit", elems: elems.map((entry) => lowerer.coerceToExpected(entry, DYN)), type: arrayOf(DYN), loc }, loc);
8534
+ }
8297
8535
  lowerer.noLowering("Promise.all over this argument shape", argNode, "the entries must share ONE promise type — Promise.all([p, q]) lowers when p and q are the same Promise<T>");
8298
8536
  }
8299
8537
  const entries = lowerer.lowerExpr(argNode);
8538
+ if (!lowerer.dynamic && isJsSourceFile(call.getSourceFile()) && entries.type.kind === "dyn")
8539
+ return checkedPromiseAll(lowerer, entries, loc);
8300
8540
  // A NON-literal island argument (`Promise.all(plugins.map((p) =>
8301
8541
  // loadPlugin(p)))` — the loadPlugins shape, where the checker
8302
8542
  // spells `any[]`): the ENGINE's own Promise.all runs over the