@scriptc/compiler 0.0.35 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (439) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +14 -11
  2. package/ambient/scriptc-overrides.d.ts +0 -7
  3. package/ambient/scriptc.d.ts +1 -1
  4. package/dist/backend/build-cache.d.ts +44 -0
  5. package/dist/backend/build-cache.js +241 -0
  6. package/dist/backend/build-cache.js.map +1 -0
  7. package/dist/backend/{emission/emit-async.d.ts → c/async.d.ts} +21 -30
  8. package/dist/backend/{emission/emit-async.js → c/async.js} +270 -286
  9. package/dist/backend/c/async.js.map +1 -0
  10. package/dist/backend/{emission/emitter.d.ts → c/c-emitter.d.ts} +6 -23
  11. package/dist/backend/{emission/emitter.js → c/c-emitter.js} +53 -107
  12. package/dist/backend/c/c-emitter.js.map +1 -0
  13. package/dist/backend/c/exprs.d.ts +8 -0
  14. package/dist/backend/c/exprs.js +7937 -0
  15. package/dist/backend/c/exprs.js.map +1 -0
  16. package/dist/backend/{emission/emit-island.d.ts → c/island.d.ts} +5 -5
  17. package/dist/backend/{emission/emit-island.js → c/island.js} +24 -22
  18. package/dist/backend/c/island.js.map +1 -0
  19. package/dist/backend/{emission → c}/may-throw.d.ts +1 -1
  20. package/dist/backend/{emission → c}/may-throw.js +4 -1
  21. package/dist/backend/c/may-throw.js.map +1 -0
  22. package/dist/backend/{emission/emit-shapes.d.ts → c/shapes.d.ts} +19 -19
  23. package/dist/backend/{emission/emit-shapes.js → c/shapes.js} +78 -87
  24. package/dist/backend/c/shapes.js.map +1 -0
  25. package/dist/backend/{emission/emit-stmts.d.ts → c/stmts.d.ts} +12 -12
  26. package/dist/backend/{emission/emit-stmts.js → c/stmts.js} +395 -343
  27. package/dist/backend/c/stmts.js.map +1 -0
  28. package/dist/backend/{emission/emit-types.d.ts → c/types.d.ts} +1 -1
  29. package/dist/backend/{emission/emit-types.js → c/types.js} +42 -286
  30. package/dist/backend/c/types.js.map +1 -0
  31. package/dist/backend/c/types.test.js +25 -0
  32. package/dist/backend/c/types.test.js.map +1 -0
  33. package/dist/backend/{emission/emit-walkers.d.ts → c/walkers.d.ts} +19 -41
  34. package/dist/backend/{emission/emit-walkers.js → c/walkers.js} +242 -304
  35. package/dist/backend/c/walkers.js.map +1 -0
  36. package/dist/backend/external-c.d.ts +33 -0
  37. package/dist/backend/external-c.js +51 -0
  38. package/dist/backend/external-c.js.map +1 -0
  39. package/dist/backend/ffi-callbacks.d.ts +1 -1
  40. package/dist/backend/ffi-callbacks.js +4 -3
  41. package/dist/backend/ffi-callbacks.js.map +1 -1
  42. package/dist/backend/{library-identity.d.ts → library-identity-markers.d.ts} +0 -4
  43. package/dist/backend/{library-identity.js → library-identity-markers.js} +10 -9
  44. package/dist/backend/library-identity-markers.js.map +1 -0
  45. package/dist/backend/link-plan.d.ts +37 -0
  46. package/dist/backend/link-plan.js +26 -0
  47. package/dist/backend/link-plan.js.map +1 -0
  48. package/dist/backend/linker.d.ts +22 -0
  49. package/dist/backend/linker.js +236 -0
  50. package/dist/backend/linker.js.map +1 -0
  51. package/dist/backend/llvm/blocks.d.ts +4 -0
  52. package/dist/backend/llvm/blocks.js +29 -0
  53. package/dist/backend/llvm/blocks.js.map +1 -1
  54. package/dist/backend/llvm/classes.d.ts +2 -19
  55. package/dist/backend/llvm/classes.js +20 -52
  56. package/dist/backend/llvm/classes.js.map +1 -1
  57. package/dist/backend/llvm/common.d.ts +4 -0
  58. package/dist/backend/llvm/common.js +27 -0
  59. package/dist/backend/llvm/common.js.map +1 -0
  60. package/dist/backend/llvm/dyn.d.ts +3 -8
  61. package/dist/backend/llvm/dyn.js +159 -224
  62. package/dist/backend/llvm/dyn.js.map +1 -1
  63. package/dist/backend/llvm/emitter.d.ts +4 -1
  64. package/dist/backend/llvm/emitter.js +548 -9988
  65. package/dist/backend/llvm/emitter.js.map +1 -1
  66. package/dist/backend/llvm/expr-async.d.ts +4 -0
  67. package/dist/backend/llvm/expr-async.js +726 -0
  68. package/dist/backend/llvm/expr-async.js.map +1 -0
  69. package/dist/backend/llvm/expr-bytes.d.ts +13 -0
  70. package/dist/backend/llvm/expr-bytes.js +456 -0
  71. package/dist/backend/llvm/expr-bytes.js.map +1 -0
  72. package/dist/backend/llvm/expr-callbacks.d.ts +22 -0
  73. package/dist/backend/llvm/expr-callbacks.js +520 -0
  74. package/dist/backend/llvm/expr-callbacks.js.map +1 -0
  75. package/dist/backend/llvm/expr-calls.d.ts +2 -0
  76. package/dist/backend/llvm/expr-calls.js +618 -0
  77. package/dist/backend/llvm/expr-calls.js.map +1 -0
  78. package/dist/backend/llvm/expr-containers.d.ts +25 -0
  79. package/dist/backend/llvm/expr-containers.js +637 -0
  80. package/dist/backend/llvm/expr-containers.js.map +1 -0
  81. package/dist/backend/llvm/expr-context.d.ts +255 -0
  82. package/dist/backend/llvm/expr-context.js +2 -0
  83. package/dist/backend/llvm/expr-context.js.map +1 -0
  84. package/dist/backend/llvm/expr-control.d.ts +2 -0
  85. package/dist/backend/llvm/expr-control.js +473 -0
  86. package/dist/backend/llvm/expr-control.js.map +1 -0
  87. package/dist/backend/llvm/expr-dispatch.d.ts +4 -0
  88. package/dist/backend/llvm/expr-dispatch.js +153 -0
  89. package/dist/backend/llvm/expr-dispatch.js.map +1 -0
  90. package/dist/backend/llvm/expr-dynamic.d.ts +2 -0
  91. package/dist/backend/llvm/expr-dynamic.js +810 -0
  92. package/dist/backend/llvm/expr-dynamic.js.map +1 -0
  93. package/dist/backend/llvm/expr-island.d.ts +15 -0
  94. package/dist/backend/llvm/expr-island.js +690 -0
  95. package/dist/backend/llvm/expr-island.js.map +1 -0
  96. package/dist/backend/llvm/expr-primitives.d.ts +6 -0
  97. package/dist/backend/llvm/expr-primitives.js +642 -0
  98. package/dist/backend/llvm/expr-primitives.js.map +1 -0
  99. package/dist/backend/llvm/expr-records.d.ts +9 -0
  100. package/dist/backend/llvm/expr-records.js +299 -0
  101. package/dist/backend/llvm/expr-records.js.map +1 -0
  102. package/dist/backend/llvm/expr-stream-bridges.d.ts +13 -0
  103. package/dist/backend/llvm/expr-stream-bridges.js +420 -0
  104. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -0
  105. package/dist/backend/llvm/expr-stream-callbacks.d.ts +12 -0
  106. package/dist/backend/llvm/expr-stream-callbacks.js +360 -0
  107. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -0
  108. package/dist/backend/llvm/lib-dispatch.d.ts +5 -0
  109. package/dist/backend/llvm/lib-dispatch.js +267 -0
  110. package/dist/backend/llvm/lib-dispatch.js.map +1 -0
  111. package/dist/backend/llvm/lib-filesystem.d.ts +6 -0
  112. package/dist/backend/llvm/lib-filesystem.js +594 -0
  113. package/dist/backend/llvm/lib-filesystem.js.map +1 -0
  114. package/dist/backend/llvm/lib-network.d.ts +2 -0
  115. package/dist/backend/llvm/lib-network.js +429 -0
  116. package/dist/backend/llvm/lib-network.js.map +1 -0
  117. package/dist/backend/llvm/lib-process.d.ts +5 -0
  118. package/dist/backend/llvm/lib-process.js +585 -0
  119. package/dist/backend/llvm/lib-process.js.map +1 -0
  120. package/dist/backend/llvm/lib-shared.d.ts +6 -0
  121. package/dist/backend/llvm/lib-shared.js +687 -0
  122. package/dist/backend/llvm/lib-shared.js.map +1 -0
  123. package/dist/backend/llvm/lib-stream.d.ts +2 -0
  124. package/dist/backend/llvm/lib-stream.js +470 -0
  125. package/dist/backend/llvm/lib-stream.js.map +1 -0
  126. package/dist/backend/llvm/shapes.d.ts +12 -2
  127. package/dist/backend/llvm/shapes.js +66 -307
  128. package/dist/backend/llvm/shapes.js.map +1 -1
  129. package/dist/backend/llvm/shapes.test.js +52 -0
  130. package/dist/backend/llvm/shapes.test.js.map +1 -0
  131. package/dist/backend/llvm/unsupported.d.ts +1 -1
  132. package/dist/backend/llvm/walkers.d.ts +2 -3
  133. package/dist/backend/llvm/walkers.js +195 -222
  134. package/dist/backend/llvm/walkers.js.map +1 -1
  135. package/dist/backend/native-codegen.d.ts +45 -0
  136. package/dist/backend/native-codegen.js +275 -0
  137. package/dist/backend/native-codegen.js.map +1 -0
  138. package/dist/backend/native-codegen.test.js +226 -0
  139. package/dist/backend/native-codegen.test.js.map +1 -0
  140. package/dist/backend/native-link-info.d.ts +96 -0
  141. package/dist/backend/native-link-info.js +243 -0
  142. package/dist/backend/native-link-info.js.map +1 -0
  143. package/dist/backend/native-link-info.test.d.ts +1 -0
  144. package/dist/backend/native-link-info.test.js +134 -0
  145. package/dist/backend/native-link-info.test.js.map +1 -0
  146. package/dist/backend/{cc.d.ts → native-toolchain.d.ts} +54 -34
  147. package/dist/backend/{cc.js → native-toolchain.js} +231 -810
  148. package/dist/backend/native-toolchain.js.map +1 -0
  149. package/dist/backend/native-toolchain.test.d.ts +1 -0
  150. package/dist/backend/{cc-cache.test.js → native-toolchain.test.js} +219 -7
  151. package/dist/backend/native-toolchain.test.js.map +1 -0
  152. package/dist/backend/object-localize.js +1 -1
  153. package/dist/backend/runtime-abi.d.ts +10 -0
  154. package/dist/backend/runtime-abi.js +11 -0
  155. package/dist/backend/runtime-abi.js.map +1 -0
  156. package/dist/backend/runtime-pack-targets.test.d.ts +1 -0
  157. package/dist/backend/runtime-pack-targets.test.js +54 -0
  158. package/dist/backend/runtime-pack-targets.test.js.map +1 -0
  159. package/dist/backend/runtime-pack.d.ts +112 -0
  160. package/dist/backend/runtime-pack.js +305 -0
  161. package/dist/backend/runtime-pack.js.map +1 -0
  162. package/dist/backend/runtime-pack.test.d.ts +1 -0
  163. package/dist/backend/runtime-pack.test.js +473 -0
  164. package/dist/backend/runtime-pack.test.js.map +1 -0
  165. package/dist/backend/targets.d.ts +76 -0
  166. package/dist/backend/targets.js +262 -0
  167. package/dist/backend/targets.js.map +1 -0
  168. package/dist/backend/targets.test.d.ts +1 -0
  169. package/dist/backend/targets.test.js +41 -0
  170. package/dist/backend/targets.test.js.map +1 -0
  171. package/dist/backend/vendor-archives.d.ts +41 -0
  172. package/dist/backend/vendor-archives.js +462 -0
  173. package/dist/backend/vendor-archives.js.map +1 -0
  174. package/dist/compat/fetch-profile.d.ts +0 -1
  175. package/dist/compat/fetch-profile.js +0 -1
  176. package/dist/compat/fetch-profile.js.map +1 -1
  177. package/dist/coverage/report.js +3 -3
  178. package/dist/coverage/report.js.map +1 -1
  179. package/dist/coverage/surface-manifest.js +35 -33
  180. package/dist/coverage/surface-manifest.js.map +1 -1
  181. package/dist/diagnostics/diagnostic.d.ts +11 -12
  182. package/dist/diagnostics/diagnostic.js +19 -17
  183. package/dist/diagnostics/diagnostic.js.map +1 -1
  184. package/dist/diagnostics/render.d.ts +1 -1
  185. package/dist/diagnostics/render.js +1 -1
  186. package/dist/diagnostics/render.js.map +1 -1
  187. package/dist/errors.d.ts +5 -0
  188. package/dist/errors.js +9 -0
  189. package/dist/errors.js.map +1 -0
  190. package/dist/executable/{early-cache.d.ts → executable-cache.d.ts} +2 -2
  191. package/dist/executable/{early-cache.js → executable-cache.js} +36 -98
  192. package/dist/executable/executable-cache.js.map +1 -0
  193. package/dist/executable/executable-cache.test.d.ts +1 -0
  194. package/dist/executable/{early-cache.test.js → executable-cache.test.js} +3 -3
  195. package/dist/executable/executable-cache.test.js.map +1 -0
  196. package/dist/ffi/{profile.js → ffi-manifest.js} +1 -1
  197. package/dist/ffi/ffi-manifest.js.map +1 -0
  198. package/dist/frontend/builtin-modules.d.ts +21 -0
  199. package/dist/frontend/builtin-modules.js +82 -0
  200. package/dist/frontend/builtin-modules.js.map +1 -0
  201. package/dist/frontend/cjs-lexer.d.ts +7 -0
  202. package/dist/frontend/cjs-lexer.js +15 -17
  203. package/dist/frontend/cjs-lexer.js.map +1 -1
  204. package/dist/frontend/dts-paths.d.ts +26 -0
  205. package/dist/frontend/dts-paths.js +41 -0
  206. package/dist/frontend/dts-paths.js.map +1 -0
  207. package/dist/frontend/input-tracker.d.ts +0 -2
  208. package/dist/frontend/input-tracker.js +1 -4
  209. package/dist/frontend/input-tracker.js.map +1 -1
  210. package/dist/frontend/lib-contract.d.ts +1 -5
  211. package/dist/frontend/lib-contract.js +1 -1
  212. package/dist/frontend/lib-contract.js.map +1 -1
  213. package/dist/frontend/lib-exports.d.ts +1 -1
  214. package/dist/frontend/lowering/array-values.d.ts +8 -0
  215. package/dist/frontend/lowering/array-values.js +60 -0
  216. package/dist/frontend/lowering/array-values.js.map +1 -0
  217. package/dist/frontend/lowering/call-position.d.ts +4 -0
  218. package/dist/frontend/lowering/call-position.js +7 -0
  219. package/dist/frontend/lowering/call-position.js.map +1 -0
  220. package/dist/frontend/lowering/callback-arg.d.ts +20 -0
  221. package/dist/frontend/lowering/callback-arg.js +44 -0
  222. package/dist/frontend/lowering/callback-arg.js.map +1 -0
  223. package/dist/frontend/lowering/lib-boundary.d.ts +1 -1
  224. package/dist/frontend/lowering/lib-boundary.js +34 -34
  225. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  226. package/dist/frontend/lowering/lower-array-sort.d.ts +22 -0
  227. package/dist/frontend/lowering/lower-array-sort.js +619 -0
  228. package/dist/frontend/lowering/lower-array-sort.js.map +1 -0
  229. package/dist/frontend/lowering/lower-assert.d.ts +3 -3
  230. package/dist/frontend/lowering/lower-assert.js +214 -241
  231. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  232. package/dist/frontend/lowering/lower-builtins.d.ts +74 -146
  233. package/dist/frontend/lowering/lower-builtins.js +1285 -1233
  234. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  235. package/dist/frontend/lowering/lower-calls.d.ts +59 -192
  236. package/dist/frontend/lowering/lower-calls.js +1644 -1506
  237. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  238. package/dist/frontend/lowering/lower-classes.d.ts +62 -125
  239. package/dist/frontend/lowering/lower-classes.js +832 -866
  240. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  241. package/dist/frontend/lowering/lower-comptime.d.ts +5 -12
  242. package/dist/frontend/lowering/lower-comptime.js +32 -31
  243. package/dist/frontend/lowering/lower-comptime.js.map +1 -1
  244. package/dist/frontend/lowering/lower-containers.d.ts +35 -135
  245. package/dist/frontend/lowering/lower-containers.js +1984 -2227
  246. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  247. package/dist/frontend/lowering/lower-dgram.d.ts +3 -7
  248. package/dist/frontend/lowering/lower-dgram.js +97 -111
  249. package/dist/frontend/lowering/lower-dgram.js.map +1 -1
  250. package/dist/frontend/lowering/lower-enums.d.ts +4 -4
  251. package/dist/frontend/lowering/lower-enums.js +30 -30
  252. package/dist/frontend/lowering/lower-enums.js.map +1 -1
  253. package/dist/frontend/lowering/{lower-emitter.d.ts → lower-event-emitter.d.ts} +7 -18
  254. package/dist/frontend/lowering/{lower-emitter.js → lower-event-emitter.js} +172 -174
  255. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -0
  256. package/dist/frontend/lowering/lower-expando.d.ts +5 -5
  257. package/dist/frontend/lowering/lower-expando.js +40 -40
  258. package/dist/frontend/lowering/lower-expando.js.map +1 -1
  259. package/dist/frontend/lowering/lower-exprs.d.ts +60 -264
  260. package/dist/frontend/lowering/lower-exprs.js +2361 -1765
  261. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  262. package/dist/frontend/lowering/lower-generators.d.ts +6 -6
  263. package/dist/frontend/lowering/lower-generators.js +73 -72
  264. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  265. package/dist/frontend/lowering/lower-inspect.d.ts +5 -17
  266. package/dist/frontend/lowering/lower-inspect.js +273 -261
  267. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  268. package/dist/frontend/lowering/lower-island.d.ts +39 -49
  269. package/dist/frontend/lowering/lower-island.js +447 -513
  270. package/dist/frontend/lowering/lower-island.js.map +1 -1
  271. package/dist/frontend/lowering/lower-mixins.d.ts +7 -10
  272. package/dist/frontend/lowering/lower-mixins.js +85 -85
  273. package/dist/frontend/lowering/lower-mixins.js.map +1 -1
  274. package/dist/frontend/lowering/lower-modules.d.ts +12 -18
  275. package/dist/frontend/lowering/lower-modules.js +284 -283
  276. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  277. package/dist/frontend/lowering/lower-namespaces.d.ts +23 -49
  278. package/dist/frontend/lowering/lower-namespaces.js +123 -115
  279. package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
  280. package/dist/frontend/lowering/lower-server.d.ts +18 -25
  281. package/dist/frontend/lowering/lower-server.js +909 -899
  282. package/dist/frontend/lowering/lower-server.js.map +1 -1
  283. package/dist/frontend/lowering/lower-stmts.d.ts +30 -149
  284. package/dist/frontend/lowering/lower-stmts.js +1463 -1285
  285. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  286. package/dist/frontend/lowering/lower-stream.d.ts +12 -12
  287. package/dist/frontend/lowering/lower-stream.js +300 -301
  288. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  289. package/dist/frontend/lowering/lower-test.d.ts +5 -5
  290. package/dist/frontend/lowering/lower-test.js +82 -82
  291. package/dist/frontend/lowering/lower-test.js.map +1 -1
  292. package/dist/frontend/lowering/lowerer.d.ts +134 -22
  293. package/dist/frontend/lowering/lowerer.js +1277 -126
  294. package/dist/frontend/lowering/lowerer.js.map +1 -1
  295. package/dist/frontend/lowering/pairs-snapshot.d.ts +11 -0
  296. package/dist/frontend/lowering/pairs-snapshot.js +85 -0
  297. package/dist/frontend/lowering/pairs-snapshot.js.map +1 -0
  298. package/dist/frontend/lowering/static-this.d.ts +6 -0
  299. package/dist/frontend/lowering/static-this.js +24 -0
  300. package/dist/frontend/lowering/static-this.js.map +1 -0
  301. package/dist/frontend/lowering/surfaces.d.ts +24 -35
  302. package/dist/frontend/lowering/surfaces.js +78 -66
  303. package/dist/frontend/lowering/surfaces.js.map +1 -1
  304. package/dist/frontend/npm-static-rewrite.js +6 -28
  305. package/dist/frontend/npm-static-rewrite.js.map +1 -1
  306. package/dist/frontend/npm-static.d.ts +0 -10
  307. package/dist/frontend/npm-static.js +4 -7
  308. package/dist/frontend/npm-static.js.map +1 -1
  309. package/dist/frontend/npm.d.ts +0 -24
  310. package/dist/frontend/npm.js +11 -85
  311. package/dist/frontend/npm.js.map +1 -1
  312. package/dist/frontend/program.d.ts +3 -1
  313. package/dist/frontend/program.js +9 -4
  314. package/dist/frontend/program.js.map +1 -1
  315. package/dist/frontend/provenance-registry.d.ts +0 -2
  316. package/dist/frontend/provenance-registry.js +0 -10
  317. package/dist/frontend/provenance-registry.js.map +1 -1
  318. package/dist/frontend/provenance.js +4 -7
  319. package/dist/frontend/provenance.js.map +1 -1
  320. package/dist/frontend/resolve.d.ts +7 -2
  321. package/dist/frontend/resolve.js +12 -17
  322. package/dist/frontend/resolve.js.map +1 -1
  323. package/dist/frontend/resolve.test.d.ts +1 -0
  324. package/dist/frontend/resolve.test.js +29 -0
  325. package/dist/frontend/resolve.test.js.map +1 -0
  326. package/dist/frontend/ts7/adapter.d.ts +2 -2
  327. package/dist/frontend/ts7/adapter.js +1 -1
  328. package/dist/frontend/ts7/adapter.js.map +1 -1
  329. package/dist/frontend/ts7/checker.js +2 -36
  330. package/dist/frontend/ts7/checker.js.map +1 -1
  331. package/dist/frontend/ts7/enums.js +2 -1
  332. package/dist/frontend/ts7/enums.js.map +1 -1
  333. package/dist/frontend/ts7/{program.js → program-adapter.js} +7 -6
  334. package/dist/frontend/ts7/program-adapter.js.map +1 -0
  335. package/dist/frontend/ts7/world-check.d.ts +1 -3
  336. package/dist/frontend/ts7/world-check.js +3 -1
  337. package/dist/frontend/ts7/world-check.js.map +1 -1
  338. package/dist/frontend/tsc-codes.d.ts +8 -0
  339. package/dist/frontend/tsc-codes.js +109 -0
  340. package/dist/frontend/tsc-codes.js.map +1 -0
  341. package/dist/frontend/{types.d.ts → type-mapper.d.ts} +2 -25
  342. package/dist/frontend/{types.js → type-mapper.js} +12 -11
  343. package/dist/frontend/type-mapper.js.map +1 -0
  344. package/dist/frontend/workspace-registry.d.ts +26 -0
  345. package/dist/frontend/workspace-registry.js +71 -0
  346. package/dist/frontend/workspace-registry.js.map +1 -0
  347. package/dist/index.d.ts +113 -31
  348. package/dist/index.js +536 -128
  349. package/dist/index.js.map +1 -1
  350. package/dist/ir/analysis.d.ts +37 -0
  351. package/dist/ir/analysis.js +118 -0
  352. package/dist/ir/analysis.js.map +1 -0
  353. package/dist/ir/analysis.test.d.ts +1 -0
  354. package/dist/ir/analysis.test.js +21 -0
  355. package/dist/ir/analysis.test.js.map +1 -0
  356. package/dist/ir/build.d.ts +9 -0
  357. package/dist/ir/build.js +33 -0
  358. package/dist/ir/build.js.map +1 -0
  359. package/dist/ir/integer-loops.d.ts +1 -1
  360. package/dist/ir/{nodes.d.ts → ir.d.ts} +119 -37
  361. package/dist/ir/{nodes.js → ir.js} +170 -166
  362. package/dist/ir/ir.js.map +1 -0
  363. package/dist/ir/ir.test.d.ts +1 -0
  364. package/dist/ir/ir.test.js +17 -0
  365. package/dist/ir/ir.test.js.map +1 -0
  366. package/dist/ir/serialize.d.ts +2 -2
  367. package/dist/ir/serialize.js +3 -2
  368. package/dist/ir/serialize.js.map +1 -1
  369. package/dist/ir/validate.d.ts +1 -1
  370. package/dist/ir/validate.js +93 -41
  371. package/dist/ir/validate.js.map +1 -1
  372. package/dist/library/cache-primitives.d.ts +24 -0
  373. package/dist/library/cache-primitives.js +83 -0
  374. package/dist/library/cache-primitives.js.map +1 -0
  375. package/dist/library/cache-reset.test.d.ts +1 -0
  376. package/dist/library/cache-reset.test.js +47 -0
  377. package/dist/library/cache-reset.test.js.map +1 -0
  378. package/dist/library/{implementation-identity.js → compiler-self-identity.js} +1 -1
  379. package/dist/library/compiler-self-identity.js.map +1 -0
  380. package/dist/library/fence-eval.d.ts +3 -1
  381. package/dist/library/fence-eval.js +8 -2
  382. package/dist/library/fence-eval.js.map +1 -1
  383. package/dist/library/int-infer.d.ts +1 -36
  384. package/dist/library/int-infer.js +29 -18
  385. package/dist/library/int-infer.js.map +1 -1
  386. package/dist/library/int-infer.test.js +4 -4
  387. package/dist/library/{early-cache.d.ts → library-cache.d.ts} +1 -1
  388. package/dist/library/{early-cache.js → library-cache.js} +34 -89
  389. package/dist/library/library-cache.js.map +1 -0
  390. package/dist/library/library-cache.test.d.ts +1 -0
  391. package/dist/library/{early-cache.test.js → library-cache.test.js} +7 -7
  392. package/dist/library/library-cache.test.js.map +1 -0
  393. package/dist/library/{profile.d.ts → library-profile.d.ts} +4 -7
  394. package/dist/library/{profile.js → library-profile.js} +18 -11
  395. package/dist/library/library-profile.js.map +1 -0
  396. package/dist/library/semantic-source.js +2 -1
  397. package/dist/library/semantic-source.js.map +1 -1
  398. package/dist/library/sidecar.d.ts +5 -2
  399. package/dist/library/sidecar.js +11 -5
  400. package/dist/library/sidecar.js.map +1 -1
  401. package/dist/startup-cache.d.ts +11 -3
  402. package/dist/startup-cache.js +17 -2
  403. package/dist/startup-cache.js.map +1 -1
  404. package/package.json +19 -2
  405. package/surface-manifest.json +5 -5
  406. package/dist/backend/cc-cache.test.js.map +0 -1
  407. package/dist/backend/cc.js.map +0 -1
  408. package/dist/backend/emission/emit-async.js.map +0 -1
  409. package/dist/backend/emission/emit-exprs.d.ts +0 -13
  410. package/dist/backend/emission/emit-exprs.js +0 -7407
  411. package/dist/backend/emission/emit-exprs.js.map +0 -1
  412. package/dist/backend/emission/emit-island.js.map +0 -1
  413. package/dist/backend/emission/emit-shapes.js.map +0 -1
  414. package/dist/backend/emission/emit-stmts.js.map +0 -1
  415. package/dist/backend/emission/emit-types.js.map +0 -1
  416. package/dist/backend/emission/emit-walkers.js.map +0 -1
  417. package/dist/backend/emission/emitter.js.map +0 -1
  418. package/dist/backend/emission/may-throw.js.map +0 -1
  419. package/dist/backend/library-identity.js.map +0 -1
  420. package/dist/executable/early-cache.js.map +0 -1
  421. package/dist/executable/early-cache.test.js.map +0 -1
  422. package/dist/ffi/profile.js.map +0 -1
  423. package/dist/frontend/lowering/lower-emitter.js.map +0 -1
  424. package/dist/frontend/shared.d.ts +0 -82
  425. package/dist/frontend/shared.js +0 -308
  426. package/dist/frontend/shared.js.map +0 -1
  427. package/dist/frontend/ts7/program.js.map +0 -1
  428. package/dist/frontend/types.js.map +0 -1
  429. package/dist/ir/nodes.js.map +0 -1
  430. package/dist/library/early-cache.js.map +0 -1
  431. package/dist/library/early-cache.test.js.map +0 -1
  432. package/dist/library/implementation-identity.js.map +0 -1
  433. package/dist/library/profile.js.map +0 -1
  434. /package/dist/backend/{cc-cache.test.d.ts → c/types.test.d.ts} +0 -0
  435. /package/dist/{executable/early-cache.test.d.ts → backend/llvm/shapes.test.d.ts} +0 -0
  436. /package/dist/{library/early-cache.test.d.ts → backend/native-codegen.test.d.ts} +0 -0
  437. /package/dist/ffi/{profile.d.ts → ffi-manifest.d.ts} +0 -0
  438. /package/dist/frontend/ts7/{program.d.ts → program-adapter.d.ts} +0 -0
  439. /package/dist/library/{implementation-identity.d.ts → compiler-self-identity.d.ts} +0 -0
@@ -11,17 +11,13 @@
11
11
  import * as ts from "../ts7/adapter.js";
12
12
  import { ladderFenceExpr, nodeThrowExpr } from "./lowerer.js";
13
13
  import { isJsSourceFile, locOf } from "../program.js";
14
- import { arrayOf, BOOL, BYTES_U8, canBoxFuncIntoDyn, canConvertToDyn, DYN, DYN_HANDLE_KINDS, F64, funcOf, HTTP2SESSION_T, HTTP2STREAM_T, HTTPCLIENTREQ_T, HTTPREQ_T, HTTPRES_T, NETSERVER_T, NETSOCKET_T, NULL_T, SECURECTX_T, STRING, UNDEFINED_T, typeKey, VOID } from "../../ir/nodes.js";
14
+ import { arrayOf, BOOL, BYTES_U8, canBoxFuncIntoDyn, canConvertToDyn, DYN, DYN_HANDLE_KINDS, F64, funcOf, HTTP2SESSION_T, HTTP2STREAM_T, HTTPCLIENTREQ_T, HTTPREQ_T, HTTPRES_T, NETSERVER_T, NETSOCKET_T, NULL_T, SECURECTX_T, STRING, UNDEFINED_T, typeKey, VOID } from "../../ir/ir.js";
15
15
  import { AGENT_DOCUMENTED_OPTIONS, builtinFenceHintOf, builtinModuleFnOf, fenceOrDropOptionKey, HTTP_CLIENT_DOCUMENTED_OPTIONS, HTTP_SERVER_DOCUMENTED_OPTIONS, HTTP2_SECURE_SERVER_DOCUMENTED_OPTIONS, HTTPS_CLIENT_DOCUMENTED_OPTIONS, sideEffectFreeOptionValue, TLS_SERVER_DOCUMENTED_OPTIONS, } from "./surfaces.js";
16
16
  import { conditionalSpreadOf } from "./lower-exprs.js";
17
- /** The lowered value members of the net module — the surfaces.ts table's
18
- * spoke-side twin (the call SHAPES are all special-cased here, so the
19
- * entries carry no param/result rows). */
20
- export const NET_MODULE_FNS = new Set([
21
- "createServer",
22
- "connect",
23
- "createConnection",
24
- ]);
17
+ import { boolLit, numLit, strLit, varRef } from "../../ir/build.js";
18
+ import { resultIsDiscarded } from "./call-position.js";
19
+ import { lowerCallbackArg as lowerCallbackArgShared } from "./callback-arg.js";
20
+ import { pairsSnapshotHelper } from "./pairs-snapshot.js";
25
21
  const NARROW_DATA_HINT = 'write/end take one string or one Uint8Array/Buffer value (narrow unions first)';
26
22
  /** The writable numeric http.Server timeout fields. The selector is an
27
23
  * internal runtime ABI shared by the get/set libCalls (kept here beside
@@ -40,10 +36,104 @@ function httpServerTimeoutField(name) {
40
36
  * arrow bodies (`socket.on("error", () => socket.destroy())` — the shape
41
37
  * portless is made of); anything that would CONSUME the result (Node
42
38
  * returns `this`/a boolean where this surface returns void) is fenced. */
43
- function requireStatementPosition(L, call, what) {
44
- if (ts.isExpressionStatement(call.parent) || ts.isArrowFunction(call.parent))
39
+ function requireStatementPosition(lowerer, call, what) {
40
+ if (resultIsDiscarded(call))
45
41
  return;
46
- L.unsupported("SC1090", call, `using the result of ${what} (the result is void here — call it as its own statement)`);
42
+ lowerer.unsupported("SC1090", call, `using the result of ${what} (the result is void here — call it as its own statement)`);
43
+ }
44
+ /** Node enables net.Server's reusePort socket option only for the exact
45
+ * boolean value true. This is intentionally different from the ordinary
46
+ * condition lowering used by ipv6Only: JavaScript values such as 1 and
47
+ * "true" are truthy, but Node leaves reusePort disabled for them.
48
+ *
49
+ * Typed boolean-or-undefined option bindings are represented by the normal
50
+ * tagged union. Initializers narrow that union to its boolean arm; shorthand
51
+ * properties are required to have the concrete BOOL shape below, matching
52
+ * ipv6Only's static option-record fence. Other static values still evaluate
53
+ * once, then produce false; checked-dynamic and island values use strict
54
+ * equality against the boolean true. */
55
+ function lowerExactReusePort(lowerer, value, node) {
56
+ const loc = locOf(node);
57
+ const falseValue = () => boolLit(false, loc);
58
+ if (value.type.kind === "bool")
59
+ return value;
60
+ if (value.type.kind === "dyn") {
61
+ return {
62
+ kind: "dynScalarEq",
63
+ left: value,
64
+ right: boolLit(true, loc),
65
+ type: BOOL,
66
+ loc,
67
+ };
68
+ }
69
+ if (value.type.kind === "jsval") {
70
+ return {
71
+ kind: "jsOp",
72
+ op: "eq",
73
+ args: [value, lowerer.jsvalIn(boolLit(true, loc), node)],
74
+ type: BOOL,
75
+ loc,
76
+ };
77
+ }
78
+ if (value.type.kind === "union") {
79
+ const def = lowerer.unions.get(value.type.unionId);
80
+ const boolTag = def?.arms.findIndex((arm) => arm.kind === "bool") ?? -1;
81
+ if (boolTag >= 0) {
82
+ const local = lowerer.declareHiddenLocal("%listenReusePort", value.type);
83
+ const ref = () => ({ kind: "varRef", localId: local.id, type: value.type, loc });
84
+ return {
85
+ kind: "seqExpr",
86
+ stmts: [{ kind: "varDecl", localId: local.id, init: value, loc }],
87
+ result: {
88
+ kind: "ternary",
89
+ cond: {
90
+ kind: "unionIsTag",
91
+ unionId: value.type.unionId,
92
+ tag: boolTag,
93
+ negated: false,
94
+ value: ref(),
95
+ type: BOOL,
96
+ loc,
97
+ },
98
+ then: {
99
+ kind: "unionNarrow",
100
+ unionId: value.type.unionId,
101
+ tag: boolTag,
102
+ value: ref(),
103
+ type: BOOL,
104
+ loc,
105
+ },
106
+ else_: falseValue(),
107
+ type: BOOL,
108
+ loc,
109
+ },
110
+ type: BOOL,
111
+ loc,
112
+ };
113
+ }
114
+ }
115
+ // Static non-boolean values cannot equal true, but their initializer may
116
+ // have observable effects (for example, a getter-backed expression).
117
+ // Keep that evaluation in the IR while disabling the kernel option.
118
+ if (value.type.kind === "void") {
119
+ return {
120
+ kind: "seqExpr",
121
+ stmts: [{ kind: "exprStmt", expr: value, loc }],
122
+ result: falseValue(),
123
+ type: BOOL,
124
+ loc,
125
+ };
126
+ }
127
+ if (value.kind === "unitLit")
128
+ return falseValue();
129
+ const local = lowerer.declareHiddenLocal("%listenReusePort", value.type);
130
+ return {
131
+ kind: "seqExpr",
132
+ stmts: [{ kind: "varDecl", localId: local.id, init: value, loc }],
133
+ result: falseValue(),
134
+ type: BOOL,
135
+ loc,
136
+ };
47
137
  }
48
138
  /** The %Error param shape the error-listener slots carry. */
49
139
  const ERROR_T = { kind: "object", className: "%Error" };
@@ -51,19 +141,19 @@ const ERROR_T = { kind: "object", className: "%Error" };
51
141
  * callback rides an interned cast-and-discard adapter (the stream lane's
52
142
  * bare-expression-body discard, generalized to closure VALUES): same
53
143
  * parameters, void return, the underlying result discarded unread. */
54
- export function voidizedCallback(L, cb, loc) {
144
+ export function voidizedCallback(lowerer, cb, loc) {
55
145
  if (cb.type.kind !== "func" || cb.type.ret.kind === "void")
56
146
  return cb;
57
147
  const fromT = cb.type;
58
148
  const toT = funcOf([...fromT.params], VOID);
59
149
  const key = `server.voidcb:${typeKey(fromT)}`;
60
- const existing = L.arrHofHelpers.get(key);
61
- const name = existing ?? `%server.voidcb.${L.arrHofHelpers.size}`;
150
+ const existing = lowerer.arrHofHelpers.get(key);
151
+ const name = existing ?? `%server.voidcb.${lowerer.arrHofHelpers.size}`;
62
152
  if (!existing) {
63
- L.arrHofHelpers.set(key, name);
153
+ lowerer.arrHofHelpers.set(key, name);
64
154
  const impl = `${name}.impl`;
65
155
  const params = fromT.params.map((p, i) => ({ localId: `p${i}.0`, name: `p${i}`, type: p }));
66
- L.liftedFns.push({
156
+ lowerer.liftedFns.push({
67
157
  name: impl,
68
158
  params,
69
159
  returnType: VOID,
@@ -87,7 +177,7 @@ export function voidizedCallback(L, cb, loc) {
87
177
  ],
88
178
  loc,
89
179
  });
90
- L.liftedFns.push({
180
+ lowerer.liftedFns.push({
91
181
  name,
92
182
  params: [{ localId: "f.0", name: "f", type: fromT }],
93
183
  returnType: toT,
@@ -103,30 +193,41 @@ export function voidizedCallback(L, cb, loc) {
103
193
  * an interned helper runs the void call and returns its first argument.
104
194
  * `prefix` calls (the writeHead statusMessage form's resStatusMsgSet)
105
195
  * run first, sharing the same parameter refs. */
106
- function receiverReturningCall(L, fn, callArgs, recvT, loc, opts) {
196
+ function receiverReturningCall(lowerer, fn, callArgs, recvT, loc, opts) {
107
197
  const key = `server.recvret:${fn}:${opts?.prefix?.fn ?? ""}:${(opts?.mainArgIndices ?? []).join(".")}:${callArgs.map((a) => typeKey(a.type)).join(",")}`;
108
- const existing = L.arrHofHelpers.get(key);
109
- const name = existing ?? `%server.recvret.${L.arrHofHelpers.size}`;
198
+ const existing = lowerer.arrHofHelpers.get(key);
199
+ const name = existing ?? `%server.recvret.${lowerer.arrHofHelpers.size}`;
110
200
  if (!existing) {
111
- L.arrHofHelpers.set(key, name);
201
+ lowerer.arrHofHelpers.set(key, name);
112
202
  const params = callArgs.map((a, i) => ({ localId: `p${i}.0`, name: `p${i}`, type: a.type }));
113
- const ref = (i) => ({ kind: "varRef", localId: params[i].localId, type: params[i].type, loc });
114
203
  const body = [];
115
204
  if (opts?.prefix) {
116
205
  body.push({
117
206
  kind: "exprStmt",
118
- expr: { kind: "libCall", fn: opts.prefix.fn, args: opts.prefix.argIndices.map(ref), type: VOID, loc },
207
+ expr: {
208
+ kind: "libCall",
209
+ fn: opts.prefix.fn,
210
+ args: opts.prefix.argIndices.map((i) => varRef(params[i].localId, params[i].type, loc)),
211
+ type: VOID,
212
+ loc,
213
+ },
119
214
  loc,
120
215
  });
121
216
  }
122
217
  const mainIdx = opts?.mainArgIndices ?? params.map((_, i) => i);
123
218
  body.push({
124
219
  kind: "exprStmt",
125
- expr: { kind: "libCall", fn, args: mainIdx.map(ref), type: VOID, loc },
220
+ expr: {
221
+ kind: "libCall",
222
+ fn,
223
+ args: mainIdx.map((i) => varRef(params[i].localId, params[i].type, loc)),
224
+ type: VOID,
225
+ loc,
226
+ },
126
227
  loc,
127
228
  });
128
- body.push({ kind: "return", value: ref(0), loc });
129
- L.liftedFns.push({
229
+ body.push({ kind: "return", value: varRef(params[0].localId, params[0].type, loc), loc });
230
+ lowerer.liftedFns.push({
130
231
  name,
131
232
  params,
132
233
  returnType: recvT,
@@ -146,45 +247,12 @@ function receiverReturningCall(L, fn, callArgs, recvT, loc, opts) {
146
247
  * test/common's mustCall result — adapts through the dynCheck function
147
248
  * boundary instead of fencing; handle-carrying events pass no tuple and
148
249
  * keep their fences. Returns the lowered closure and its param count. */
149
- function lowerCallbackArg(L, node, what, maxParams, paramOk, paramHint, dynTuple) {
150
- const cb = L.lowerExpr(node);
151
- if (cb.type.kind === "dyn" && dynTuple !== undefined) {
152
- const toT = funcOf([...dynTuple], VOID);
153
- return {
154
- cb: { kind: "dynCheck", value: cb, type: toT, loc: locOf(node) },
155
- nparams: dynTuple.length,
156
- };
157
- }
158
- if (dynTuple !== undefined &&
159
- cb.type.kind === "func" &&
160
- (cb.type.rest === true ||
161
- (cb.type.params.length > 0 && cb.type.params.some((p) => !paramOk(p)))) &&
162
- cb.type.params.every((p) => p.kind === "dyn") &&
163
- canBoxFuncIntoDyn(cb.type, (id) => L.shapes.get(id), (id) => L.unions.get(id))) {
164
- // A plain-JS listener whose params carry no contextual type (a
165
- // hoisted `function onConn(socket)` — dyn params), or an
166
- // arguments-reading rest function: box it and adapt through the
167
- // dynCheck function boundary like the dyn flavor above — the event
168
- // payloads box into the checked-dynamic tree (handles by reference) and the body's
169
- // member uses dispatch at runtime.
170
- const boxed = { kind: "dynFrom", value: cb, type: DYN, loc: locOf(node) };
171
- const toT = funcOf([...dynTuple], VOID);
172
- return {
173
- cb: { kind: "dynCheck", value: boxed, type: toT, loc: locOf(node) },
174
- nparams: dynTuple.length,
175
- };
176
- }
177
- if (cb.type.kind !== "func" || cb.type.params.length > maxParams) {
178
- L.unsupported("SC1090", node, `${what} with more than ${maxParams} parameter${maxParams === 1 ? "" : "s"} (${paramHint})`);
179
- }
180
- const param = cb.type.params[0];
181
- if (param !== undefined && !paramOk(param)) {
182
- L.unsupported("SC1090", node, `${what} whose parameter is not supported (${paramHint})`);
183
- }
184
- const adapted = voidizedCallback(L, cb, locOf(node));
185
- return { cb: adapted, nparams: cb.type.params.length };
250
+ function lowerCallbackArg(lowerer, node, what, maxParams, paramOk, paramHint, dynTuple) {
251
+ return lowerCallbackArgShared(lowerer, node, what, maxParams, paramOk, paramHint, {
252
+ ...(dynTuple !== undefined ? { dynTuple } : {}),
253
+ adapt: (cb) => voidizedCallback(lowerer, cb, locOf(node)),
254
+ });
186
255
  }
187
- const boolLit = (value, loc) => ({ kind: "boolLit", value, type: BOOL, loc });
188
256
  /** Lowers a handle-kind method receiver. The checker's control flow can
189
257
  * narrow an untyped binding to the handle class (`let server; server =
190
258
  * createServer(...)` — the keep-alive shape) so the STATIC lowering
@@ -194,17 +262,17 @@ const boolLit = (value, loc) => ({ kind: "boolLit", value, type: BOOL, loc });
194
262
  /** True iff `t` is the {address: string, family: string, port: number}
195
263
  * record — server.address()'s materialized shape (lower-dgram's
196
264
  * AddressInfo check, another receiver). */
197
- function isAddressInfoRecord(L, t) {
265
+ function isAddressInfoRecord(lowerer, t) {
198
266
  if (t.kind !== "record")
199
267
  return false;
200
- const shape = L.shapes.get(t.shapeId);
268
+ const shape = lowerer.shapes.get(t.shapeId);
201
269
  if (!shape || shape.tuple || shape.indexValue || shape.fields.length !== 3)
202
270
  return false;
203
271
  const want = [["address", "string"], ["family", "string"], ["port", "f64"]];
204
272
  return shape.fields.every((f, i) => f.name === want[i][0] && f.type.kind === want[i][1]);
205
273
  }
206
- function handleReceiver(L, node, want) {
207
- const recv = L.lowerExpr(node);
274
+ function coerceToHandle(lowerer, node, want) {
275
+ const recv = lowerer.lowerExpr(node);
208
276
  if (recv.type.kind === "dyn" && DYN_HANDLE_KINDS.has(want.kind)) {
209
277
  return { kind: "dynCheck", value: recv, type: want, loc: locOf(node) };
210
278
  }
@@ -218,24 +286,22 @@ function handleReceiver(L, node, want) {
218
286
  * target). Mirrors headersSnapshotHelper's loop, sourced from a pairs
219
287
  * array instead of reqHeaderPairs. Null when the shape is not a
220
288
  * string-armed pure-index record. */
221
- function h2HeaderRecordStmts(L, shapeId, pairsLocal, outLocal, statusLocal, loc) {
222
- const shape = L.shapes.get(shapeId);
289
+ function h2HeaderRecordStmts(lowerer, shapeId, pairsLocal, outLocal, statusLocal, loc) {
290
+ const shape = lowerer.shapes.get(shapeId);
223
291
  if (!shape || shape.tuple || shape.fields.length > 0 || !shape.indexValue)
224
292
  return null;
225
293
  const iv = shape.indexValue;
226
294
  if (iv.kind !== "union")
227
295
  return null;
228
- const strTag = L.armTag(iv.unionId, STRING);
296
+ const strTag = lowerer.armTag(iv.unionId, STRING);
229
297
  if (strTag < 0)
230
298
  return null;
231
299
  const recT = { kind: "record", shapeId };
232
300
  const pairsT = arrayOf(STRING);
233
- const ref = (localId, type) => ({ kind: "varRef", localId, type, loc });
234
- const num = (value) => ({ kind: "numLit", value, type: F64, loc });
235
301
  const pairAt = (offset) => ({
236
302
  kind: "arrayGet",
237
- arr: ref(pairsLocal, pairsT),
238
- index: offset === 0 ? ref("i.0", F64) : { kind: "bin", op: "+", left: ref("i.0", F64), right: num(offset), type: F64, loc },
303
+ arr: varRef(pairsLocal, pairsT, loc),
304
+ index: offset === 0 ? varRef("i.0", F64, loc) : { kind: "bin", op: "+", left: varRef("i.0", F64, loc), right: numLit(offset, loc), type: F64, loc },
239
305
  type: STRING,
240
306
  loc,
241
307
  });
@@ -243,28 +309,28 @@ function h2HeaderRecordStmts(L, shapeId, pairsLocal, outLocal, statusLocal, loc)
243
309
  { kind: "varDecl", localId: outLocal, init: { kind: "recordLit", fields: [], type: recT, loc }, loc },
244
310
  {
245
311
  kind: "for",
246
- init: { kind: "varDecl", localId: "i.0", init: num(0), loc },
312
+ init: { kind: "varDecl", localId: "i.0", init: numLit(0, loc), loc },
247
313
  cond: {
248
- kind: "bin", op: "<", left: ref("i.0", F64),
249
- right: { kind: "arrIntrinsic", method: "length", receiver: ref(pairsLocal, pairsT), args: [], type: F64, loc },
314
+ kind: "bin", op: "<", left: varRef("i.0", F64, loc),
315
+ right: { kind: "arrIntrinsic", method: "length", receiver: varRef(pairsLocal, pairsT, loc), args: [], type: F64, loc },
250
316
  type: BOOL, loc,
251
317
  },
252
- update: { kind: "assign", localId: "i.0", value: { kind: "bin", op: "+", left: ref("i.0", F64), right: num(2), type: F64, loc }, loc },
318
+ update: { kind: "assign", localId: "i.0", value: { kind: "bin", op: "+", left: varRef("i.0", F64, loc), right: numLit(2, loc), type: F64, loc }, loc },
253
319
  body: [{
254
- kind: "recordKeySet", obj: ref(outLocal, recT), shapeId, key: pairAt(0),
320
+ kind: "recordKeySet", obj: varRef(outLocal, recT, loc), shapeId, key: pairAt(0),
255
321
  value: { kind: "unionWrap", unionId: iv.unionId, tag: strTag, value: pairAt(1), type: iv, loc }, loc,
256
322
  }],
257
323
  loc,
258
324
  },
259
325
  ];
260
326
  if (statusLocal !== null) {
261
- const f64Tag = L.armTag(iv.unionId, F64);
327
+ const f64Tag = lowerer.armTag(iv.unionId, F64);
262
328
  if (f64Tag < 0)
263
329
  return null;
264
330
  stmts.push({
265
- kind: "recordKeySet", obj: ref(outLocal, recT), shapeId,
331
+ kind: "recordKeySet", obj: varRef(outLocal, recT, loc), shapeId,
266
332
  key: { kind: "strLit", value: ":status", type: STRING, loc },
267
- value: { kind: "unionWrap", unionId: iv.unionId, tag: f64Tag, value: ref(statusLocal, F64), type: iv, loc }, loc,
333
+ value: { kind: "unionWrap", unionId: iv.unionId, tag: f64Tag, value: varRef(statusLocal, F64, loc), type: iv, loc }, loc,
268
334
  });
269
335
  }
270
336
  return stmts;
@@ -287,18 +353,18 @@ function headerParamShapeId(cbT, idx) {
287
353
  * :status when `withStatus`. Returns the adapter closure (VOID-returning,
288
354
  * runtime ABI) to pass into the libCall. */
289
355
  /** The canonical header record type — a pure-index record over the
290
- * header slot `f64 | string | string[] | undefined` (types.ts's
356
+ * header slot `f64 | string | string[] | undefined` (type-mapper.ts's
291
357
  * HEADER-FAMILY canonicalization, rebuilt here for dyn-callback headers
292
358
  * with no static param type to read the shape from). */
293
- function canonicalHeaderRecord(L) {
359
+ function canonicalHeaderRecord(lowerer) {
294
360
  const arms = [F64, STRING, arrayOf(STRING), UNDEFINED_T];
295
361
  arms.sort((a, b) => (typeKey(a) < typeKey(b) ? -1 : 1));
296
- const slot = { kind: "union", unionId: L.unions.intern(arms) };
297
- const shapeId = L.shapes.intern([], false, slot, []);
362
+ const slot = { kind: "union", unionId: lowerer.unions.intern(arms) };
363
+ const shapeId = lowerer.shapes.intern([], false, slot, []);
298
364
  return { type: { kind: "record", shapeId }, shapeId };
299
365
  }
300
- function h2HeadersCallbackAdapter(L, node, what, handleKind, withStatus, loc) {
301
- let cb = L.lowerExpr(node);
366
+ function h2HeadersCallbackAdapter(lowerer, node, what, handleKind, withStatus, loc) {
367
+ let cb = lowerer.lowerExpr(node);
302
368
  const maxParams = (handleKind ? 1 : 0) + 1 /* headers */ + 1 /* flags */;
303
369
  // A checked-dynamic listener (test/common's mustCall wrapper — a dyn
304
370
  // value or an arguments-reading rest function of dyn params): wrap it
@@ -309,9 +375,9 @@ function h2HeadersCallbackAdapter(L, node, what, handleKind, withStatus, loc) {
309
375
  const handleT = handleKind === "http2Stream" ? HTTP2STREAM_T : null;
310
376
  const isDynCb = cb.type.kind === "dyn" ||
311
377
  (cb.type.kind === "func" && (cb.type.rest === true || cb.type.params.every((p) => p.kind === "dyn")) &&
312
- canBoxFuncIntoDyn(cb.type, (id) => L.shapes.get(id), (id) => L.unions.get(id)));
378
+ canBoxFuncIntoDyn(cb.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id)));
313
379
  if (isDynCb) {
314
- const rec = canonicalHeaderRecord(L);
380
+ const rec = canonicalHeaderRecord(lowerer);
315
381
  const tuple = [];
316
382
  if (handleT)
317
383
  tuple.push(handleT);
@@ -322,13 +388,13 @@ function h2HeadersCallbackAdapter(L, node, what, handleKind, withStatus, loc) {
322
388
  cb = { kind: "dynCheck", value: boxed, type: toT, loc };
323
389
  }
324
390
  if (cb.type.kind !== "func" || cb.type.ret.kind !== "void" || cb.type.params.length > maxParams) {
325
- L.unsupported("SC1090", node, `${what} with more than ${maxParams} parameters or returning a value`);
391
+ lowerer.unsupported("SC1090", node, `${what} with more than ${maxParams} parameters or returning a value`);
326
392
  }
327
393
  const fromT = cb.type;
328
394
  const headersIdx = handleT ? 1 : 0;
329
395
  const shapeId = fromT.params.length > headersIdx ? headerParamShapeId(fromT, headersIdx) : null;
330
396
  if (fromT.params.length > headersIdx && shapeId === null) {
331
- L.unsupported("SC1090", node, `${what} whose headers parameter is not a header record (type it IncomingHttpHeaders)`);
397
+ lowerer.unsupported("SC1090", node, `${what} whose headers parameter is not a header record (type it IncomingHttpHeaders)`);
332
398
  }
333
399
  // Runtime ABI params, in order.
334
400
  const abiParams = [];
@@ -340,12 +406,11 @@ function h2HeadersCallbackAdapter(L, node, what, handleKind, withStatus, loc) {
340
406
  abiParams.push({ localId: "fl.0", name: "fl", type: F64 });
341
407
  const toT = funcOf(abiParams.map((p) => p.type), VOID);
342
408
  const key = `h2.hdrcb:${handleKind}:${withStatus}:${typeKey(fromT)}:${shapeId ?? ""}`;
343
- const existing = L.arrHofHelpers.get(key);
344
- const name = existing ?? `%h2.hdrcb.${L.arrHofHelpers.size}`;
409
+ const existing = lowerer.arrHofHelpers.get(key);
410
+ const name = existing ?? `%h2.hdrcb.${lowerer.arrHofHelpers.size}`;
345
411
  if (!existing) {
346
- L.arrHofHelpers.set(key, name);
412
+ lowerer.arrHofHelpers.set(key, name);
347
413
  const impl = `${name}.impl`;
348
- const ref = (localId, type) => ({ kind: "varRef", localId, type, loc });
349
414
  const locals = [
350
415
  { id: "f.0", name: "f", type: fromT, mutable: false, boxed: true },
351
416
  ...abiParams.map((p) => ({ id: p.localId, name: p.name, type: p.type, mutable: false })),
@@ -355,30 +420,30 @@ function h2HeadersCallbackAdapter(L, node, what, handleKind, withStatus, loc) {
355
420
  if (shapeId !== null) {
356
421
  locals.push({ id: "out.0", name: "out", type: { kind: "record", shapeId }, mutable: false });
357
422
  locals.push({ id: "i.0", name: "i", type: F64, mutable: true });
358
- const stmts = h2HeaderRecordStmts(L, shapeId, "ps.0", "out.0", withStatus ? "st.0" : null, loc);
423
+ const stmts = h2HeaderRecordStmts(lowerer, shapeId, "ps.0", "out.0", withStatus ? "st.0" : null, loc);
359
424
  if (stmts === null)
360
- L.unsupported("SC1090", node, `${what} whose headers parameter is not a supported header record`);
425
+ lowerer.unsupported("SC1090", node, `${what} whose headers parameter is not a supported header record`);
361
426
  body.push(...stmts);
362
- recordRef = ref("out.0", { kind: "record", shapeId });
427
+ recordRef = varRef("out.0", { kind: "record", shapeId }, loc);
363
428
  }
364
429
  // Assemble the user-call arguments in the user's declared order.
365
430
  const callArgs = [];
366
431
  const push = (e) => { if (callArgs.length < fromT.params.length)
367
432
  callArgs.push(e); };
368
433
  if (handleT)
369
- push(ref("h.0", handleT));
434
+ push(varRef("h.0", handleT, loc));
370
435
  if (recordRef)
371
436
  push(recordRef);
372
437
  else if (fromT.params.length > headersIdx)
373
- push(ref("ps.0", arrayOf(STRING)));
374
- push(ref("fl.0", F64));
438
+ push(varRef("ps.0", arrayOf(STRING), loc));
439
+ push(varRef("fl.0", F64, loc));
375
440
  body.push({
376
441
  kind: "exprStmt",
377
- expr: { kind: "callValue", callee: ref("f.0", fromT), args: callArgs.slice(0, fromT.params.length), type: fromT.ret, loc },
442
+ expr: { kind: "callValue", callee: varRef("f.0", fromT, loc), args: callArgs.slice(0, fromT.params.length), type: fromT.ret, loc },
378
443
  loc,
379
444
  });
380
- L.liftedFns.push({ name: impl, params: abiParams, returnType: VOID, captures: [{ localId: "f.0", name: "f", type: fromT }], locals, body, loc });
381
- L.liftedFns.push({
445
+ lowerer.liftedFns.push({ name: impl, params: abiParams, returnType: VOID, captures: [{ localId: "f.0", name: "f", type: fromT }], locals, body, loc });
446
+ lowerer.liftedFns.push({
382
447
  name, params: [{ localId: "f.0", name: "f", type: fromT }], returnType: toT,
383
448
  locals: [{ id: "f.0", name: "f", type: fromT, mutable: false, boxed: true }],
384
449
  body: [{ kind: "return", value: { kind: "closure", fnName: impl, captures: ["f.0"], type: toT, loc }, loc }], loc,
@@ -389,8 +454,8 @@ function h2HeadersCallbackAdapter(L, node, what, handleKind, withStatus, loc) {
389
454
  /** Builds the flat [name, value, ...] pairs array from an OutgoingHttp
390
455
  * Headers argument (an object literal with literal/pseudo keys, or a
391
456
  * header Record). Reuses lowerClientHeadersOption's shape. */
392
- function lowerH2HeadersArg(L, node) {
393
- return lowerClientHeadersOption(L, node);
457
+ function lowerH2HeadersArg(lowerer, node) {
458
+ return lowerClientHeadersOption(lowerer, node);
394
459
  }
395
460
  /** The STATICALLY-KNOWN key text of a header-object property: literal
396
461
  * identifier/string keys, plus COMPUTED keys that are a bare identifier
@@ -398,11 +463,11 @@ function lowerH2HeadersArg(L, node) {
398
463
  * (the portless proxy shape) is as static as spelling the name out, and
399
464
  * an identifier read has no side effects to drop. Null for genuinely
400
465
  * dynamic keys (the caller fences). */
401
- function staticHeaderKeyOf(L, prop) {
466
+ function staticHeaderKeyOf(lowerer, prop) {
402
467
  if (ts.isIdentifier(prop.name) || ts.isStringLiteral(prop.name))
403
468
  return prop.name.text;
404
469
  if (ts.isComputedPropertyName(prop.name) && ts.isIdentifier(prop.name.expression)) {
405
- const t = L.typeOf(prop.name.expression);
470
+ const t = lowerer.typeOf(prop.name.expression);
406
471
  if (t.isStringLiteralType())
407
472
  return t.value;
408
473
  }
@@ -413,20 +478,20 @@ function staticHeaderKeyOf(L, prop) {
413
478
  * (the caller falls through to the ordinary builtin tables); every net
414
479
  * member lands here — unlowered ones fence with their module-qualified
415
480
  * name. */
416
- export function lowerNetModuleCall(L, expr, bi, loc) {
481
+ export function lowerNetModuleCall(lowerer, expr, bi, loc) {
417
482
  if (bi.module === "http")
418
- return lowerHttpModuleCall(L, expr, bi, loc);
483
+ return lowerHttpModuleCall(lowerer, expr, bi, loc);
419
484
  if (bi.module === "https")
420
- return lowerHttpsModuleCall(L, expr, bi, loc);
485
+ return lowerHttpsModuleCall(lowerer, expr, bi, loc);
421
486
  if (bi.module === "tls")
422
- return lowerTlsModuleCall(L, expr, bi, loc);
487
+ return lowerTlsModuleCall(lowerer, expr, bi, loc);
423
488
  if (bi.module === "http2")
424
- return lowerHttp2ModuleCall(L, expr, bi, loc);
489
+ return lowerHttp2ModuleCall(lowerer, expr, bi, loc);
425
490
  if (bi.module !== "net")
426
491
  return null;
427
492
  // Members with ordinary surfaces.ts table entries (the autoselect
428
493
  // budget pair) ride the generic path — null hands the dispatch back.
429
- if (builtinModuleFnOf(L, "net", bi.member))
494
+ if (builtinModuleFnOf(lowerer, "net", bi.member))
430
495
  return null;
431
496
  const args = expr.arguments;
432
497
  if (bi.member === "createServer") {
@@ -440,9 +505,9 @@ export function lowerNetModuleCall(L, expr, bi, loc) {
440
505
  // result — the checked-dynamic lane's concise arrows box it, and
441
506
  // the throw means it never materializes.
442
507
  if (isJsSourceFile(expr.getSourceFile())) {
443
- const t = L.mapTypeOf(L.typeOf(args[0]));
508
+ const t = lowerer.mapTypeOf(lowerer.typeOf(args[0]));
444
509
  if (t !== null && (t.kind === "string" || t.kind === "f64" || t.kind === "bool")) {
445
- const raw = L.lowerExpr(args[0]);
510
+ const raw = lowerer.lowerExpr(args[0]);
446
511
  return {
447
512
  kind: "libCall",
448
513
  fn: "error.argTypeThrow",
@@ -456,10 +521,10 @@ export function lowerNetModuleCall(L, expr, bi, loc) {
456
521
  };
457
522
  }
458
523
  }
459
- const { cb } = lowerCallbackArg(L, args[0], "connection handlers", 1, (p) => p.kind === "netSocket", "use (socket) or ()", [NETSOCKET_T]);
524
+ const { cb } = lowerCallbackArg(lowerer, args[0], "connection handlers", 1, (p) => p.kind === "netSocket", "use (socket) or ()", [NETSOCKET_T]);
460
525
  return { kind: "libCall", fn: "net.createServerCb", args: [cb], type: NETSERVER_T, loc };
461
526
  }
462
- L.noLowering(`createServer with ${args.length} arguments`, expr, "the supported forms are createServer() and createServer(socket => ...)");
527
+ lowerer.noLowering(`createServer with ${args.length} arguments`, expr, "the supported forms are createServer() and createServer(socket => ...)");
463
528
  }
464
529
  if (bi.member === "connect" || bi.member === "createConnection") {
465
530
  // The options-object form — connect({ port, host?, autoSelectFamily?,
@@ -472,22 +537,22 @@ export function lowerNetModuleCall(L, expr, bi, loc) {
472
537
  // spelling — without it Node would dial only the first address). The
473
538
  // no-lookup form is connect(port, host) with the option spellings.
474
539
  if (args.length >= 1 && ts.isObjectLiteralExpression(args[0])) {
475
- return lowerNetConnectOptions(L, expr, bi.member, loc);
540
+ return lowerNetConnectOptions(lowerer, expr, bi.member, loc);
476
541
  }
477
542
  // A RUNTIME option bag (a record binding or dyn value — the
478
543
  // invalid-input probes build theirs with computed keys): the
479
544
  // checked-dynamic walk validates Node-order and the compiler-rendered
480
545
  // fence is the post-validation tail.
481
546
  if (args.length === 1 && isJsSourceFile(expr.getSourceFile())) {
482
- const t = L.mapTypeOf(L.typeOf(args[0]));
547
+ const t = lowerer.mapTypeOf(lowerer.typeOf(args[0]));
483
548
  if (t !== null && (t.kind === "dyn" || t.kind === "record")) {
484
- const raw = L.lowerExpr(args[0]);
485
- if (raw.type.kind === "dyn" || L.dynConvertible(raw.type)) {
549
+ const raw = lowerer.lowerExpr(args[0]);
550
+ if (raw.type.kind === "dyn" || lowerer.dynConvertible(raw.type)) {
486
551
  const bag = raw.type.kind === "dyn" ? raw : { kind: "dynFrom", value: raw, type: DYN, loc };
487
552
  return {
488
553
  kind: "libCall",
489
554
  fn: "net.connectOptsChk",
490
- args: [bag, ladderFenceExpr(L, `${bi.member} with a runtime options record`, expr, "pass the options as an object literal — port, host, autoSelectFamily, autoSelectFamilyAttemptTimeout, and lookup are the supported options")],
555
+ args: [bag, ladderFenceExpr(lowerer, `${bi.member} with a runtime options record`, expr, "pass the options as an object literal — port, host, autoSelectFamily, autoSelectFamilyAttemptTimeout, and lookup are the supported options")],
491
556
  type: NETSOCKET_T,
492
557
  loc,
493
558
  };
@@ -495,15 +560,15 @@ export function lowerNetModuleCall(L, expr, bi, loc) {
495
560
  }
496
561
  }
497
562
  if (args.length < 1 || args.length > 3) {
498
- L.noLowering(`${bi.member} with ${args.length} arguments`, expr, `the supported form is ${bi.member}(port, host?, connectListener?)`);
563
+ lowerer.noLowering(`${bi.member} with ${args.length} arguments`, expr, `the supported form is ${bi.member}(port, host?, connectListener?)`);
499
564
  }
500
- const port = L.lowerExprExpecting(args[0], F64);
565
+ const port = lowerer.lowerExprExpecting(args[0], F64);
501
566
  // The optional middle host: a 2-arg call's second argument is the
502
567
  // host when string-typed, the connect listener when func-typed.
503
568
  let hostNode;
504
569
  let cbNode;
505
570
  if (args.length === 2) {
506
- if (L.mapTypeOf(L.typeOf(args[1]))?.kind === "string")
571
+ if (lowerer.mapTypeOf(lowerer.typeOf(args[1]))?.kind === "string")
507
572
  hostNode = args[1];
508
573
  else
509
574
  cbNode = args[1];
@@ -513,22 +578,22 @@ export function lowerNetModuleCall(L, expr, bi, loc) {
513
578
  cbNode = args[2];
514
579
  }
515
580
  const host = hostNode
516
- ? L.lowerExprExpecting(hostNode, STRING)
581
+ ? lowerer.lowerExprExpecting(hostNode, STRING)
517
582
  : { kind: "strLit", value: "localhost", type: STRING, loc };
518
583
  if (!cbNode) {
519
584
  return { kind: "libCall", fn: "net.connect", args: [port, host], type: NETSOCKET_T, loc };
520
585
  }
521
- const { cb } = lowerCallbackArg(L, cbNode, "connect listeners", 0, () => false, "use ()", []);
586
+ const { cb } = lowerCallbackArg(lowerer, cbNode, "connect listeners", 0, () => false, "use ()", []);
522
587
  return { kind: "libCall", fn: "net.connectCb", args: [port, host, cb], type: NETSOCKET_T, loc };
523
588
  }
524
- L.noLowering(`net.${bi.member}`, expr, "createServer, connect, and createConnection are the lowered net module functions", L.resolveValueSymbol(expr.expression));
589
+ lowerer.noLowering(`net.${bi.member}`, expr, "createServer, connect, and createConnection are the lowered net module functions", lowerer.resolveValueSymbol(expr.expression));
525
590
  }
526
591
  /** True when `t` is the lookup-function shape the connect lowering
527
592
  * accepts: (hostname: string, options: unknown, callback) => void where
528
593
  * callback is (err: <union with a null arm>, addresses: { address:
529
594
  * string, ... }[]) => void — Node's net.LookupFunction as portless
530
595
  * declares it. */
531
- function lookupFnShapeOk(L, t) {
596
+ function lookupFnShapeOk(lowerer, t) {
532
597
  if (t.kind !== "func" || t.ret.kind !== "void" || t.params.length !== 3)
533
598
  return false;
534
599
  if (t.params[0].kind !== "string")
@@ -541,7 +606,7 @@ function lookupFnShapeOk(L, t) {
541
606
  const errT = cbT.params[0];
542
607
  if (errT.kind !== "union")
543
608
  return false;
544
- const errDef = L.unions.get(errT.unionId);
609
+ const errDef = lowerer.unions.get(errT.unionId);
545
610
  if (!errDef || !errDef.arms.some((a) => a.kind === "nullT"))
546
611
  return false;
547
612
  // Every non-null arm must be the Error root: the emitted answer thunk
@@ -552,7 +617,7 @@ function lookupFnShapeOk(L, t) {
552
617
  const addrsT = cbT.params[1];
553
618
  if (addrsT.kind !== "array" || addrsT.elem.kind !== "record")
554
619
  return false;
555
- const shape = L.shapes.get(addrsT.elem.shapeId);
620
+ const shape = lowerer.shapes.get(addrsT.elem.shapeId);
556
621
  return !!shape && shape.fields.some((f) => f.name === "address" && f.type.kind === "string");
557
622
  }
558
623
  /** net.connect / net.createConnection with an OPTIONS OBJECT: { port,
@@ -563,7 +628,7 @@ function lookupFnShapeOk(L, t) {
563
628
  * alongside, portless's createLoopbackConnection). Other keys fence by
564
629
  * name; a connect listener argument is supported on the no-lookup form
565
630
  * only. */
566
- function lowerNetConnectOptions(L, expr, member, loc) {
631
+ function lowerNetConnectOptions(lowerer, expr, member, loc) {
567
632
  const args = expr.arguments;
568
633
  const optsNode = args[0];
569
634
  const isJs = isJsSourceFile(expr.getSourceFile());
@@ -579,13 +644,13 @@ function lowerNetConnectOptions(L, expr, member, loc) {
579
644
  ["objectMode", "readableObjectMode", "writableObjectMode"].includes((ts.isPropertyAssignment(p) || ts.isShorthandPropertyAssignment(p)) &&
580
645
  (ts.isIdentifier(p.name) || ts.isStringLiteral(p.name)) ? p.name.text : ""));
581
646
  if (needsBag) {
582
- const raw = L.lowerExpr(optsNode);
583
- if (raw.type.kind === "dyn" || L.dynConvertible(raw.type)) {
647
+ const raw = lowerer.lowerExpr(optsNode);
648
+ if (raw.type.kind === "dyn" || lowerer.dynConvertible(raw.type)) {
584
649
  const bag = raw.type.kind === "dyn" ? raw : { kind: "dynFrom", value: raw, type: DYN, loc };
585
650
  return {
586
651
  kind: "libCall",
587
652
  fn: "net.connectOptsChk",
588
- args: [bag, ladderFenceExpr(L, `${member} with these options`, optsNode, "port, host, autoSelectFamily, autoSelectFamilyAttemptTimeout, and lookup are the supported options")],
653
+ args: [bag, ladderFenceExpr(lowerer, `${member} with these options`, optsNode, "port, host, autoSelectFamily, autoSelectFamilyAttemptTimeout, and lookup are the supported options")],
589
654
  type: NETSOCKET_T,
590
655
  loc,
591
656
  };
@@ -619,16 +684,16 @@ function lowerNetConnectOptions(L, expr, member, loc) {
619
684
  initializer = null;
620
685
  }
621
686
  else {
622
- L.noLowering(`${member} options with computed keys or spreads`, prop, "each option must be a plain `name: value` (or shorthand) entry with a literal key");
687
+ lowerer.noLowering(`${member} options with computed keys or spreads`, prop, "each option must be a plain `name: value` (or shorthand) entry with a literal key");
623
688
  }
624
689
  const key = prop.name.text;
625
690
  const lowerVal = () => initializer !== null
626
- ? L.lowerExpr(initializer)
627
- : L.lowerShorthandValue(prop);
691
+ ? lowerer.lowerExpr(initializer)
692
+ : lowerer.lowerShorthandValue(prop);
628
693
  if (key === "port") {
629
694
  port = lowerVal();
630
695
  if (port.type.kind !== "f64") {
631
- L.noLowering(`a ${member} 'port' option of '${L.fmt(port.type)}' values`, prop, "the port is a number here");
696
+ lowerer.noLowering(`a ${member} 'port' option of '${lowerer.fmt(port.type)}' values`, prop, "the port is a number here");
632
697
  }
633
698
  }
634
699
  else if (key === "host") {
@@ -636,12 +701,12 @@ function lowerNetConnectOptions(L, expr, member, loc) {
636
701
  if (host.type.kind !== "string") {
637
702
  // A provably-non-string host (the invalid-input probes): Node's
638
703
  // lookupAndConnect throws ERR_INVALID_ARG_TYPE at connect time.
639
- if (isJs && (host.type.kind === "dyn" || L.dynConvertible(host.type))) {
704
+ if (isJs && (host.type.kind === "dyn" || lowerer.dynConvertible(host.type))) {
640
705
  optionThrow ??= propThrow("options.host", "of type string", host);
641
706
  host = null;
642
707
  continue;
643
708
  }
644
- L.noLowering(`a ${member} 'host' option of '${L.fmt(host.type)}' values`, prop, "the host is a string here");
709
+ lowerer.noLowering(`a ${member} 'host' option of '${lowerer.fmt(host.type)}' values`, prop, "the host is a string here");
645
710
  }
646
711
  }
647
712
  else if (key === "autoSelectFamily") {
@@ -651,13 +716,13 @@ function lowerNetConnectOptions(L, expr, member, loc) {
651
716
  if (initializer === null || initializer.kind !== ts.SyntaxKind.TrueKeyword) {
652
717
  // A provably-non-boolean value throws Node's validateBoolean
653
718
  // ladder instead of fencing.
654
- const raw = initializer !== null && isJs ? L.lowerExpr(initializer) : null;
719
+ const raw = initializer !== null && isJs ? lowerer.lowerExpr(initializer) : null;
655
720
  if (raw !== null && raw.type.kind !== "bool" &&
656
- (raw.type.kind === "dyn" || L.dynConvertible(raw.type))) {
721
+ (raw.type.kind === "dyn" || lowerer.dynConvertible(raw.type))) {
657
722
  optionThrow ??= propThrow("options.autoSelectFamily", "of type boolean", raw);
658
723
  continue;
659
724
  }
660
- L.noLowering(`${member} with a non-literal autoSelectFamily option`, prop, "the lowered form is autoSelectFamily: true beside a lookup function");
725
+ lowerer.noLowering(`${member} with a non-literal autoSelectFamily option`, prop, "the lowered form is autoSelectFamily: true beside a lookup function");
661
726
  }
662
727
  autoSelect = true;
663
728
  }
@@ -666,22 +731,22 @@ function lowerNetConnectOptions(L, expr, member, loc) {
666
731
  // from-1 ladder) and is then inert — the single dial has nothing
667
732
  // to time, the autoSelectFamily simplification's sibling.
668
733
  const raw = lowerVal();
669
- if (!(raw.type.kind === "dyn" || raw.kind === "unitLit" || L.dynConvertible(raw.type))) {
670
- L.noLowering(`a ${member} 'autoSelectFamilyAttemptTimeout' option of '${L.fmt(raw.type)}' values`, prop, "the budget is a number here");
734
+ if (!(raw.type.kind === "dyn" || raw.kind === "unitLit" || lowerer.dynConvertible(raw.type))) {
735
+ lowerer.noLowering(`a ${member} 'autoSelectFamilyAttemptTimeout' option of '${lowerer.fmt(raw.type)}' values`, prop, "the budget is a number here");
671
736
  }
672
737
  attempt = raw.type.kind === "dyn" ? raw : { kind: "dynFrom", value: raw, type: DYN, loc };
673
738
  }
674
739
  else if (key === "lookup") {
675
740
  if (initializer === null) {
676
- L.noLowering(`${member} with a shorthand lookup option`, prop, "spell it out: lookup: theResolver");
741
+ lowerer.noLowering(`${member} with a shorthand lookup option`, prop, "spell it out: lookup: theResolver");
677
742
  }
678
- lookup = L.lowerExpr(initializer);
679
- if (!lookupFnShapeOk(L, lookup.type)) {
680
- L.noLowering(`a ${member} 'lookup' option of '${L.fmt(lookup.type)}' values`, prop, "the lowered resolver is (hostname: string, options: unknown, callback: (err: NodeJS.ErrnoException | null, addresses: { address: string; family: number }[]) => void) => void");
743
+ lookup = lowerer.lowerExpr(initializer);
744
+ if (!lookupFnShapeOk(lowerer, lookup.type)) {
745
+ lowerer.noLowering(`a ${member} 'lookup' option of '${lowerer.fmt(lookup.type)}' values`, prop, "the lowered resolver is (hostname: string, options: unknown, callback: (err: NodeJS.ErrnoException | null, addresses: { address: string; family: number }[]) => void) => void");
681
746
  }
682
747
  }
683
748
  else {
684
- L.noLowering(`${member} option '${key}'`, prop, "port, host, autoSelectFamily, and lookup are the supported options");
749
+ lowerer.noLowering(`${member} option '${key}'`, prop, "port, host, autoSelectFamily, and lookup are the supported options");
685
750
  }
686
751
  }
687
752
  // A collected option-contract violation replaces the whole call: Node
@@ -690,21 +755,21 @@ function lowerNetConnectOptions(L, expr, member, loc) {
690
755
  if (optionThrow !== null)
691
756
  return optionThrow;
692
757
  if (port === null) {
693
- L.noLowering(`${member} options without a port`, optsNode, "the supported options object is { port, host?, autoSelectFamily?, lookup? }");
758
+ lowerer.noLowering(`${member} options without a port`, optsNode, "the supported options object is { port, host?, autoSelectFamily?, lookup? }");
694
759
  }
695
760
  host ??= { kind: "strLit", value: "localhost", type: STRING, loc };
696
761
  if (attempt !== null) {
697
762
  if (lookup !== null || args.length !== 1) {
698
- L.noLowering(`${member} with an autoSelectFamilyAttemptTimeout beside a lookup or connect listener`, expr, "the validated-budget form is the bare options call — register listeners separately");
763
+ lowerer.noLowering(`${member} with an autoSelectFamilyAttemptTimeout beside a lookup or connect listener`, expr, "the validated-budget form is the bare options call — register listeners separately");
699
764
  }
700
765
  return { kind: "libCall", fn: "net.connectAttempt", args: [port, host, attempt], type: NETSOCKET_T, loc };
701
766
  }
702
767
  if (lookup !== null) {
703
768
  if (!autoSelect) {
704
- L.noLowering(`${member} with a lookup but no autoSelectFamily: true`, optsNode, "the lookup form dials every answered address in order — Node does that under autoSelectFamily: true, so spell it");
769
+ lowerer.noLowering(`${member} with a lookup but no autoSelectFamily: true`, optsNode, "the lookup form dials every answered address in order — Node does that under autoSelectFamily: true, so spell it");
705
770
  }
706
771
  if (args.length !== 1) {
707
- L.noLowering(`${member} with a lookup and a connect listener`, expr, "register the listener separately: socket.once('connect', ...)");
772
+ lowerer.noLowering(`${member} with a lookup and a connect listener`, expr, "register the listener separately: socket.once('connect', ...)");
708
773
  }
709
774
  return { kind: "libCall", fn: "net.connectLookup", args: [port, host, lookup], type: NETSOCKET_T, loc };
710
775
  }
@@ -712,9 +777,9 @@ function lowerNetConnectOptions(L, expr, member, loc) {
712
777
  return { kind: "libCall", fn: "net.connect", args: [port, host], type: NETSOCKET_T, loc };
713
778
  }
714
779
  if (args.length !== 2) {
715
- L.noLowering(`${member} with ${args.length} arguments`, expr, `the supported form is ${member}(options[, connectListener])`);
780
+ lowerer.noLowering(`${member} with ${args.length} arguments`, expr, `the supported form is ${member}(options[, connectListener])`);
716
781
  }
717
- const { cb } = lowerCallbackArg(L, args[1], "connect listeners", 0, () => false, "use ()", []);
782
+ const { cb } = lowerCallbackArg(lowerer, args[1], "connect listeners", 0, () => false, "use ()", []);
718
783
  return { kind: "libCall", fn: "net.connectCb", args: [port, host, cb], type: NETSOCKET_T, loc };
719
784
  }
720
785
  /** `wrapper.close.bind(wrapper)` — the bound REAL close as a VALUE (the
@@ -726,7 +791,7 @@ function lowerNetConnectOptions(L, expr, member, loc) {
726
791
  * binding as the method receiver — any other `this` would be a
727
792
  * different close. Null when the shape doesn't match (generic fences
728
793
  * name `.bind` otherwise). */
729
- function lowerServerCloseBind(L, call, access) {
794
+ function lowerServerCloseBind(lowerer, call, access) {
730
795
  if (call.questionDotToken || access.questionDotToken)
731
796
  return null;
732
797
  if (access.name.text !== "bind")
@@ -734,9 +799,9 @@ function lowerServerCloseBind(L, call, access) {
734
799
  const closeAccess = access.expression;
735
800
  if (!ts.isPropertyAccessExpression(closeAccess) || closeAccess.name.text !== "close")
736
801
  return null;
737
- if (L.mapTypeOf(L.typeOf(closeAccess.expression))?.kind !== "netServer")
802
+ if (lowerer.mapTypeOf(lowerer.typeOf(closeAccess.expression))?.kind !== "netServer")
738
803
  return null;
739
- if (!L.isStdlibMember(closeAccess))
804
+ if (!lowerer.isStdlibMember(closeAccess))
740
805
  return null;
741
806
  const loc = locOf(call);
742
807
  const recvNode = closeAccess.expression;
@@ -745,15 +810,15 @@ function lowerServerCloseBind(L, call, access) {
745
810
  !thisArg ||
746
811
  !ts.isIdentifier(recvNode) ||
747
812
  !ts.isIdentifier(thisArg) ||
748
- L.resolveValueSymbol(recvNode) !== L.resolveValueSymbol(thisArg)) {
749
- L.noLowering("close.bind with this argument shape", call, "the supported form is server.close.bind(server) — the same server binding on both sides");
813
+ lowerer.resolveValueSymbol(recvNode) !== lowerer.resolveValueSymbol(thisArg)) {
814
+ lowerer.noLowering("close.bind with this argument shape", call, "the supported form is server.close.bind(server) — the same server binding on both sides");
750
815
  }
751
- const server = L.lowerExpr(thisArg);
752
- const t = L.mapTypeOf(L.typeOf(call));
816
+ const server = lowerer.lowerExpr(thisArg);
817
+ const t = lowerer.mapTypeOf(lowerer.typeOf(call));
753
818
  const cbUnion = t?.kind === "func" && t.params.length === 1 ? t.params[0] : null;
754
819
  const cbOk = cbUnion?.kind === "union" &&
755
820
  (() => {
756
- const def = L.unions.get(cbUnion.unionId);
821
+ const def = lowerer.unions.get(cbUnion.unionId);
757
822
  return (!!def &&
758
823
  def.arms.some((a) => a.kind === "func" && a.params.length <= 1 && a.ret.kind === "void") &&
759
824
  def.arms.some((a) => a.kind === "undefinedT"));
@@ -762,7 +827,7 @@ function lowerServerCloseBind(L, call, access) {
762
827
  // => void) => Server; the shipped fallback (callback?: () => void) =>
763
828
  // void — the emitted adapter follows the mapped shape either way.
764
829
  if (!t || t.kind !== "func" || !cbOk || (t.ret.kind !== "netServer" && t.ret.kind !== "void")) {
765
- L.noLowering("close.bind with this signature", call, "the bound close is (callback?: (err?: Error) => void) => Server");
830
+ lowerer.noLowering("close.bind with this signature", call, "the bound close is (callback?: (err?: Error) => void) => Server");
766
831
  }
767
832
  return { kind: "libCall", fn: "net.serverCloseBind", args: [server], type: t, loc };
768
833
  }
@@ -772,27 +837,27 @@ function lowerServerCloseBind(L, call, access) {
772
837
  * emitted zero-arg wrapper; server.close() runs it instead of closing,
773
838
  * and the override reaches the real close through its bound origClose.
774
839
  * Null when the target isn't a net.Server close member. */
775
- export function lowerServerCloseOverrideAssignment(L, left, right, loc) {
840
+ export function lowerServerCloseOverrideAssignment(lowerer, left, right, loc) {
776
841
  if (!ts.isPropertyAccessExpression(left) || left.questionDotToken)
777
842
  return null;
778
843
  if (left.name.text !== "close")
779
844
  return null;
780
- if (L.mapTypeOf(L.typeOf(left.expression))?.kind !== "netServer")
845
+ if (lowerer.mapTypeOf(lowerer.typeOf(left.expression))?.kind !== "netServer")
781
846
  return null;
782
- const server = L.lowerExpr(left.expression);
783
- const value = L.lowerExpr(right);
847
+ const server = lowerer.lowerExpr(left.expression);
848
+ const value = lowerer.lowerExpr(right);
784
849
  const t = value.type;
785
850
  const cbUnion = t.kind === "func" && t.params.length === 1 ? t.params[0] : null;
786
851
  const shapeOk = cbUnion?.kind === "union" &&
787
852
  (t.kind === "func" && (t.ret.kind === "netServer" || t.ret.kind === "void")) &&
788
853
  (() => {
789
- const def = L.unions.get(cbUnion.unionId);
854
+ const def = lowerer.unions.get(cbUnion.unionId);
790
855
  return (!!def &&
791
856
  def.arms.some((a) => a.kind === "func" && a.params.length <= 1 && a.ret.kind === "void") &&
792
857
  def.arms.some((a) => a.kind === "undefinedT"));
793
858
  })();
794
859
  if (!shapeOk) {
795
- L.noLowering("assigning this value to server.close", right, "the override must be a (callback?: (err?: Error) => void) => Server function");
860
+ lowerer.noLowering("assigning this value to server.close", right, "the override must be a (callback?: (err?: Error) => void) => Server function");
796
861
  }
797
862
  return {
798
863
  kind: "exprStmt",
@@ -804,20 +869,20 @@ export function lowerServerCloseOverrideAssignment(L, left, right, loc) {
804
869
  * writable ServerResponse properties (the implicit head reads them):
805
870
  * routed from lower-stmts' property-assignment path beside the
806
871
  * close-override hook. Null when the target isn't one of the two. */
807
- export function lowerHttpResPropertyAssignment(L, left, right, loc) {
872
+ export function lowerHttpResPropertyAssignment(lowerer, left, right, loc) {
808
873
  if (!ts.isPropertyAccessExpression(left) || left.questionDotToken)
809
874
  return null;
810
875
  const name = left.name.text;
811
876
  if (name !== "statusCode" && name !== "statusMessage")
812
877
  return null;
813
- if (L.mapTypeOf(L.typeOf(left.expression))?.kind !== "httpRes")
878
+ if (lowerer.mapTypeOf(lowerer.typeOf(left.expression))?.kind !== "httpRes")
814
879
  return null;
815
- if (!L.isStdlibMember(left))
880
+ if (!lowerer.isStdlibMember(left))
816
881
  return null;
817
- const receiver = L.lowerExpr(left.expression);
882
+ const receiver = lowerer.lowerExpr(left.expression);
818
883
  const value = name === "statusCode"
819
- ? L.lowerExprExpecting(right, F64)
820
- : L.lowerExprExpecting(right, STRING);
884
+ ? lowerer.lowerExprExpecting(right, F64)
885
+ : lowerer.lowerExprExpecting(right, STRING);
821
886
  const fn = name === "statusCode" ? "http.resStatusSet" : "http.resStatusMsgSet";
822
887
  return {
823
888
  kind: "exprStmt",
@@ -829,19 +894,19 @@ export function lowerHttpResPropertyAssignment(L, left, right, loc) {
829
894
  * siblings. These are ordinary writable number properties in Node: the
830
895
  * runtime stores their exact value per server; active timeout behavior is
831
896
  * a separate protocol concern. */
832
- export function lowerHttpServerTimeoutAssignment(L, left, right, loc) {
897
+ export function lowerHttpServerTimeoutAssignment(lowerer, left, right, loc) {
833
898
  if (!ts.isPropertyAccessExpression(left) || left.questionDotToken)
834
899
  return null;
835
900
  const field = httpServerTimeoutField(left.name.text);
836
901
  if (field === null)
837
902
  return null;
838
- if (L.mapTypeOf(L.typeOf(left.expression))?.kind !== "netServer")
903
+ if (lowerer.mapTypeOf(lowerer.typeOf(left.expression))?.kind !== "netServer")
839
904
  return null;
840
- if (!L.isStdlibMember(left))
905
+ if (!lowerer.isStdlibMember(left))
841
906
  return null;
842
- const receiver = handleReceiver(L, left.expression, NETSERVER_T);
907
+ const receiver = coerceToHandle(lowerer, left.expression, NETSERVER_T);
843
908
  const selector = { kind: "numLit", value: field, type: F64, loc };
844
- const value = L.lowerExprExpecting(right, F64);
909
+ const value = lowerer.lowerExprExpecting(right, F64);
845
910
  return {
846
911
  kind: "exprStmt",
847
912
  expr: { kind: "libCall", fn: "http.serverTimeoutSet", args: [receiver, selector, value], type: VOID, loc },
@@ -851,17 +916,17 @@ export function lowerHttpServerTimeoutAssignment(L, left, right, loc) {
851
916
  /** Method calls on net.Server receivers: listen(port[, cb]), close([cb]),
852
917
  * on/once("connection" | "error" | "close", cb). address() alone fences
853
918
  * toward the composed address().port read. Null for other receivers. */
854
- function lowerNetServerMethodCall(L, call, access) {
855
- if (L.mapTypeOf(L.typeOf(access.expression))?.kind !== "netServer")
919
+ function lowerNetServerMethodCall(lowerer, call, access) {
920
+ if (lowerer.mapTypeOf(lowerer.typeOf(access.expression))?.kind !== "netServer")
856
921
  return null;
857
- if (!L.isStdlibMember(access))
922
+ if (!lowerer.isStdlibMember(access))
858
923
  return null;
859
924
  const name = access.name.text;
860
925
  const loc = locOf(call);
861
926
  const args = call.arguments;
862
927
  if (name === "listen") {
863
928
  if (args.length < 1 || args.length > 3) {
864
- L.noLowering(`listen with ${args.length} arguments`, call, "the supported form is listen(port[, host][, callback]) — port 0 binds an ephemeral port");
929
+ lowerer.noLowering(`listen with ${args.length} arguments`, call, "the supported form is listen(port[, host][, callback]) — port 0 binds an ephemeral port");
865
930
  }
866
931
  // Node answers the server (`return this` chaining — `const s =
867
932
  // http.createServer(...).listen(0)`, `server.listen(0).address()`):
@@ -871,19 +936,23 @@ function lowerNetServerMethodCall(L, call, access) {
871
936
  if (ts.isExpressionStatement(call.parent)) {
872
937
  return { kind: "libCall", fn, args: callArgs, type: VOID, loc };
873
938
  }
874
- return receiverReturningCall(L, fn, callArgs, NETSERVER_T, loc);
939
+ return receiverReturningCall(lowerer, fn, callArgs, NETSERVER_T, loc);
875
940
  };
876
- const receiver = handleReceiver(L, access.expression, NETSERVER_T);
877
- // The options-object form — listen({ port, host?, ipv6Only? }[, cb]),
941
+ const receiver = coerceToHandle(lowerer, access.expression, NETSERVER_T);
942
+ // The options-object form — listen({ port, host?, ipv6Only?, reusePort? }[, cb]),
878
943
  // the portless listenOnProxyInterface shape: host binds that ONE
879
944
  // address (an IP literal — the runtime has no resolver here; absent
880
945
  // = Node's host-less dual-stack any), ipv6Only sets IPV6_V6ONLY
881
946
  // (truthiness, like Node's option handling — `boolean | undefined`
882
- // flows). Every other key fences by name.
947
+ // flows). reusePort is different: Node enables it only for exact true,
948
+ // while its presence selects the additive ABI even when the value is
949
+ // false.
950
+ // Every other key fences by name.
883
951
  if (ts.isObjectLiteralExpression(args[0])) {
884
952
  let port = null;
885
953
  let host = null;
886
954
  let v6only = null;
955
+ let reusePort = null;
887
956
  for (const prop of args[0].properties) {
888
957
  let initializer;
889
958
  if (ts.isPropertyAssignment(prop) &&
@@ -894,47 +963,59 @@ function lowerNetServerMethodCall(L, call, access) {
894
963
  initializer = null;
895
964
  }
896
965
  else {
897
- L.noLowering("listen options with computed keys or spreads", prop, "each option must be a plain `name: value` (or shorthand) entry with a literal key");
966
+ lowerer.noLowering("listen options with computed keys or spreads", prop, "each option must be a plain `name: value` (or shorthand) entry with a literal key");
898
967
  }
899
968
  const key = prop.name.text;
900
969
  if (key === "port") {
901
970
  port = initializer !== null
902
- ? L.lowerExpr(initializer)
903
- : L.lowerShorthandValue(prop);
971
+ ? lowerer.lowerExpr(initializer)
972
+ : lowerer.lowerShorthandValue(prop);
904
973
  if (port.type.kind !== "f64") {
905
- L.noLowering(`a listen 'port' option of '${L.fmt(port.type)}' values`, prop, "the port is a number here");
974
+ lowerer.noLowering(`a listen 'port' option of '${lowerer.fmt(port.type)}' values`, prop, "the port is a number here");
906
975
  }
907
976
  }
908
977
  else if (key === "host") {
909
978
  host = initializer !== null
910
- ? L.lowerExpr(initializer)
911
- : L.lowerShorthandValue(prop);
979
+ ? lowerer.lowerExpr(initializer)
980
+ : lowerer.lowerShorthandValue(prop);
912
981
  if (host.type.kind !== "string") {
913
- L.noLowering(`a listen 'host' option of '${L.fmt(host.type)}' values`, prop, "the host is an IP string here");
982
+ lowerer.noLowering(`a listen 'host' option of '${lowerer.fmt(host.type)}' values`, prop, "the host is an IP string here");
914
983
  }
915
984
  }
916
985
  else if (key === "ipv6Only") {
917
986
  if (initializer !== null) {
918
- v6only = L.lowerCondition(initializer); /* truthiness: `boolean | undefined` flows */
987
+ v6only = lowerer.lowerCondition(initializer); /* truthiness: `boolean | undefined` flows */
919
988
  }
920
989
  else {
921
- const v = L.lowerShorthandValue(prop);
990
+ const v = lowerer.lowerShorthandValue(prop);
922
991
  if (v.type.kind !== "bool") {
923
- L.noLowering(`a listen 'ipv6Only' option of '${L.fmt(v.type)}' values`, prop, "spell the option out (ipv6Only: value) so non-boolean values can narrow");
992
+ lowerer.noLowering(`a listen 'ipv6Only' option of '${lowerer.fmt(v.type)}' values`, prop, "spell the option out (ipv6Only: value) so non-boolean values can narrow");
924
993
  }
925
994
  v6only = v;
926
995
  }
927
996
  }
997
+ else if (key === "reusePort") {
998
+ if (initializer !== null) {
999
+ reusePort = lowerExactReusePort(lowerer, lowerer.lowerExpr(initializer), prop);
1000
+ }
1001
+ else {
1002
+ const v = lowerer.lowerShorthandValue(prop);
1003
+ if (v.type.kind !== "bool") {
1004
+ lowerer.noLowering(`a listen 'reusePort' option of '${lowerer.fmt(v.type)}' values`, prop, "spell the option out (reusePort: value) so optional values can narrow");
1005
+ }
1006
+ reusePort = v;
1007
+ }
1008
+ }
928
1009
  else if (key === "signal" && ts.isPropertyAssignment(prop) &&
929
1010
  isJsSourceFile(call.getSourceFile())) {
930
1011
  // A provably-non-AbortSignal signal (the invalid-input probes:
931
1012
  // strings, numbers, plain records) throws Node's
932
1013
  // validateAbortSignal ladder; plausible signal values keep the
933
1014
  // fence — abort-driven close has no lowering yet.
934
- const raw = L.lowerExpr(prop.initializer);
1015
+ const raw = lowerer.lowerExpr(prop.initializer);
935
1016
  const provablyNot = raw.type.kind === "string" || raw.type.kind === "f64" ||
936
1017
  raw.type.kind === "bool" || raw.type.kind === "record" || raw.type.kind === "array";
937
- if (provablyNot && L.dynConvertible(raw.type)) {
1018
+ if (provablyNot && lowerer.dynConvertible(raw.type)) {
938
1019
  return {
939
1020
  kind: "libCall",
940
1021
  fn: "error.propTypeThrow",
@@ -947,19 +1028,23 @@ function lowerNetServerMethodCall(L, call, access) {
947
1028
  loc,
948
1029
  };
949
1030
  }
950
- L.noLowering(`listen option 'signal'`, prop, "abort-driven close has no lowering yet — port, host, and ipv6Only are the supported listen options");
1031
+ lowerer.noLowering(`listen option 'signal'`, prop, "abort-driven close has no lowering yet — port, host, ipv6Only, and reusePort are the supported listen options");
951
1032
  }
952
1033
  else {
953
- L.noLowering(`listen option '${key}'`, prop, "port, host, and ipv6Only are the supported listen options");
1034
+ lowerer.noLowering(`listen option '${key}'`, prop, "port, host, ipv6Only, and reusePort are the supported listen options");
954
1035
  }
955
1036
  }
956
1037
  if (port === null) {
957
- L.noLowering("listen options without a port", args[0], "the supported options object is { port, host?, ipv6Only? } — port 0 binds an ephemeral port");
1038
+ lowerer.noLowering("listen options without a port", args[0], "the supported options object is { port, host?, ipv6Only?, reusePort? } — port 0 binds an ephemeral port");
958
1039
  }
959
1040
  host ??= { kind: "strLit", value: "", type: STRING, loc }; /* "" = the dual-stack any default */
960
1041
  v6only ??= boolLit(false, loc);
1042
+ const listenOptsFn = reusePort === null ? "net.listenOpts" : "net.listenOptsReusePort";
1043
+ const listenOptsCbFn = reusePort === null ? "net.listenOptsCb" : "net.listenOptsReusePortCb";
961
1044
  if (args.length === 1) {
962
- return listenResult("net.listenOpts", [receiver, port, host, v6only]);
1045
+ return listenResult(listenOptsFn, reusePort === null
1046
+ ? [receiver, port, host, v6only]
1047
+ : [receiver, port, host, v6only, reusePort]);
963
1048
  }
964
1049
  // The callback may be an OPTIONAL binding — `(() => void) |
965
1050
  // undefined`, portless's listenOnProxyInterface pass-through: the
@@ -967,7 +1052,7 @@ function lowerNetServerMethodCall(L, call, access) {
967
1052
  // pattern) and the runtime takes NULL for the undefined arm. A
968
1053
  // checked-dynamic callback (a JS wrapper value) adapts through the
969
1054
  // dynCheck function boundary.
970
- let cbV = L.lowerExpr(args[1]);
1055
+ let cbV = lowerer.lowerExpr(args[1]);
971
1056
  if (cbV.type.kind === "dyn") {
972
1057
  cbV = { kind: "dynCheck", value: cbV, type: funcOf([], VOID), loc };
973
1058
  }
@@ -975,25 +1060,27 @@ function lowerNetServerMethodCall(L, call, access) {
975
1060
  const cbOk = cbFuncOk(cbV.type) ||
976
1061
  (cbV.type.kind === "union" &&
977
1062
  (() => {
978
- const def = L.unions.get(cbV.type.unionId);
1063
+ const def = lowerer.unions.get(cbV.type.unionId);
979
1064
  return (!!def &&
980
1065
  def.arms.length === 2 &&
981
1066
  def.arms.some(cbFuncOk) &&
982
1067
  def.arms.some((a) => a.kind === "undefinedT"));
983
1068
  })());
984
1069
  if (!cbOk) {
985
- L.unsupported("SC1090", args[1], `listen callbacks of type '${L.fmt(cbV.type)}' (use () — an optional \`(() => void) | undefined\` binding also flows)`);
1070
+ lowerer.unsupported("SC1090", args[1], `listen callbacks of type '${lowerer.fmt(cbV.type)}' (use () — an optional \`(() => void) | undefined\` binding also flows)`);
986
1071
  }
987
- return listenResult("net.listenOptsCb", [receiver, port, host, v6only, cbV]);
1072
+ return listenResult(listenOptsCbFn, reusePort === null
1073
+ ? [receiver, port, host, v6only, cbV]
1074
+ : [receiver, port, host, v6only, reusePort, cbV]);
988
1075
  }
989
- const port = L.lowerExprExpecting(args[0], F64);
1076
+ const port = lowerer.lowerExprExpecting(args[0], F64);
990
1077
  // The optional middle host — listen(port, '127.0.0.1'[, cb]): a
991
1078
  // string-typed second argument is the bind address (the net.connect
992
1079
  // disambiguation), routed through the options-form entry.
993
1080
  let hostNode;
994
1081
  let cbNode;
995
1082
  if (args.length === 2) {
996
- if (L.mapTypeOf(L.typeOf(args[1]))?.kind === "string")
1083
+ if (lowerer.mapTypeOf(lowerer.typeOf(args[1]))?.kind === "string")
997
1084
  hostNode = args[1];
998
1085
  else
999
1086
  cbNode = args[1];
@@ -1003,37 +1090,37 @@ function lowerNetServerMethodCall(L, call, access) {
1003
1090
  cbNode = args[2];
1004
1091
  }
1005
1092
  if (hostNode !== undefined) {
1006
- const host = L.lowerExprExpecting(hostNode, STRING);
1093
+ const host = lowerer.lowerExprExpecting(hostNode, STRING);
1007
1094
  const v6only = boolLit(false, loc);
1008
1095
  if (!cbNode)
1009
1096
  return listenResult("net.listenOpts", [receiver, port, host, v6only]);
1010
- const { cb } = lowerCallbackArg(L, cbNode, "listen callbacks", 0, () => false, "use ()", []);
1097
+ const { cb } = lowerCallbackArg(lowerer, cbNode, "listen callbacks", 0, () => false, "use ()", []);
1011
1098
  return listenResult("net.listenOptsCb", [receiver, port, host, v6only, cb]);
1012
1099
  }
1013
1100
  if (!cbNode) {
1014
1101
  return listenResult("net.listen", [receiver, port]);
1015
1102
  }
1016
- const { cb } = lowerCallbackArg(L, cbNode, "listen callbacks", 0, () => false, "use ()", []);
1103
+ const { cb } = lowerCallbackArg(lowerer, cbNode, "listen callbacks", 0, () => false, "use ()", []);
1017
1104
  return listenResult("net.listenCb", [receiver, port, cb]);
1018
1105
  }
1019
1106
  if (name === "close") {
1020
- requireStatementPosition(L, call, "server.close(...)");
1107
+ requireStatementPosition(lowerer, call, "server.close(...)");
1021
1108
  if (args.length > 1) {
1022
- L.noLowering(`close with ${args.length} arguments`, call, "the supported form is close([callback])");
1109
+ lowerer.noLowering(`close with ${args.length} arguments`, call, "the supported form is close([callback])");
1023
1110
  }
1024
- const receiver = handleReceiver(L, access.expression, NETSERVER_T);
1111
+ const receiver = coerceToHandle(lowerer, access.expression, NETSERVER_T);
1025
1112
  if (args.length === 0) {
1026
1113
  return { kind: "libCall", fn: "net.serverClose", args: [receiver], type: VOID, loc };
1027
1114
  }
1028
- const { cb } = lowerCallbackArg(L, args[0], "close callbacks", 0, () => false, "use ()", []);
1115
+ const { cb } = lowerCallbackArg(lowerer, args[0], "close callbacks", 0, () => false, "use ()", []);
1029
1116
  return { kind: "libCall", fn: "net.serverCloseCb", args: [receiver, cb], type: VOID, loc };
1030
1117
  }
1031
1118
  if ((name === "on" || name === "once" || name === "addListener") && args.length === 2) {
1032
- requireStatementPosition(L, call, `server.${name}(...)`);
1119
+ requireStatementPosition(lowerer, call, `server.${name}(...)`);
1033
1120
  const once = boolLit(name === "once", loc);
1034
- const evT = L.typeOf(args[0]);
1121
+ const evT = lowerer.typeOf(args[0]);
1035
1122
  const event = evT.isStringLiteralType() ? evT.value : null;
1036
- const receiver = handleReceiver(L, access.expression, NETSERVER_T);
1123
+ const receiver = coerceToHandle(lowerer, access.expression, NETSERVER_T);
1037
1124
  if (event === "connection" || event === "secureConnection") {
1038
1125
  // 'secureConnection' rides the same list: a TLS server's
1039
1126
  // 'connection' listeners are DEFERRED to handshake completion
@@ -1041,23 +1128,23 @@ function lowerNetServerMethodCall(L, call, access) {
1041
1128
  // secureConnection timing; on a plain net server the name would
1042
1129
  // never fire in Node either — the runtime entry gates on the
1043
1130
  // deferral flag so the split stays exact.
1044
- const { cb } = lowerCallbackArg(L, args[1], `${event} listeners`, 1, (p) => p.kind === "netSocket", "use (socket) or ()", [NETSOCKET_T]);
1131
+ const { cb } = lowerCallbackArg(lowerer, args[1], `${event} listeners`, 1, (p) => p.kind === "netSocket", "use (socket) or ()", [NETSOCKET_T]);
1045
1132
  const fn = event === "connection" ? "net.serverOnConnection" : "net.serverOnSecureConnection";
1046
1133
  return { kind: "libCall", fn, args: [receiver, cb, once], type: VOID, loc };
1047
1134
  }
1048
1135
  if (event === "error") {
1049
- const { cb } = lowerCallbackArg(L, args[1], "error listeners", 1, (p) => p.kind === "object" && p.className === "%Error", "use (err) or ()", [ERROR_T]);
1136
+ const { cb } = lowerCallbackArg(lowerer, args[1], "error listeners", 1, (p) => p.kind === "object" && p.className === "%Error", "use (err) or ()", [ERROR_T]);
1050
1137
  return { kind: "libCall", fn: "net.serverOnError", args: [receiver, cb, once], type: VOID, loc };
1051
1138
  }
1052
1139
  if (event === "close") {
1053
- const { cb } = lowerCallbackArg(L, args[1], "close listeners", 0, () => false, "use ()", []);
1140
+ const { cb } = lowerCallbackArg(lowerer, args[1], "close listeners", 0, () => false, "use ()", []);
1054
1141
  return { kind: "libCall", fn: "net.serverOnClose", args: [receiver, cb, once], type: VOID, loc };
1055
1142
  }
1056
1143
  if (event === "listening") {
1057
1144
  // The deferred bind emit — listen(port, cb)'s event twin: fires
1058
1145
  // once after a successful listen; late registrations on an
1059
1146
  // already-listening server never fire (Node's once-per-listen).
1060
- const { cb } = lowerCallbackArg(L, args[1], "listening listeners", 0, () => false, "use ()", []);
1147
+ const { cb } = lowerCallbackArg(lowerer, args[1], "listening listeners", 0, () => false, "use ()", []);
1061
1148
  return { kind: "libCall", fn: "net.serverOnListening", args: [receiver, cb, once], type: VOID, loc };
1062
1149
  }
1063
1150
  if (event === "request") {
@@ -1066,20 +1153,20 @@ function lowerNetServerMethodCall(L, call, access) {
1066
1153
  // handler. Same (req, res) shapes as the createServer callback; on a
1067
1154
  // server with no HTTP parser (net.createServer) the registration is
1068
1155
  // Node-honest dead weight: the event never fires there either.
1069
- const cb = lowerRequestHandlerArg(L, args[1]);
1156
+ const cb = lowerRequestHandlerArg(lowerer, args[1]);
1070
1157
  return { kind: "libCall", fn: "http.serverOnRequest", args: [receiver, cb, once], type: VOID, loc };
1071
1158
  }
1072
1159
  if (event === "stream") {
1073
1160
  // The h2c server's request event: (stream, headers, flags). The
1074
1161
  // adapter builds the headers record from the pairs the runtime
1075
1162
  // hands over. Dead weight on a non-h2 server (never fires).
1076
- const cb = h2HeadersCallbackAdapter(L, args[1], "stream listeners", "http2Stream", false, loc);
1163
+ const cb = h2HeadersCallbackAdapter(lowerer, args[1], "stream listeners", "http2Stream", false, loc);
1077
1164
  return { kind: "libCall", fn: "http2.serverOnStream", args: [receiver, cb, once], type: VOID, loc };
1078
1165
  }
1079
1166
  if (event === "session") {
1080
1167
  // The h2c server's per-connection session event: (session). The
1081
1168
  // result is voidized; the handle passes by reference.
1082
- const { cb } = lowerCallbackArg(L, args[1], "session listeners", 1, (p) => p.kind === "http2Session", "use (session) or ()", [HTTP2SESSION_T]);
1169
+ const { cb } = lowerCallbackArg(lowerer, args[1], "session listeners", 1, (p) => p.kind === "http2Session", "use (session) or ()", [HTTP2SESSION_T]);
1083
1170
  return { kind: "libCall", fn: "http2.serverOnSession", args: [receiver, cb, once], type: VOID, loc };
1084
1171
  }
1085
1172
  if (event === "connect") {
@@ -1090,12 +1177,12 @@ function lowerNetServerMethodCall(L, call, access) {
1090
1177
  // CONNECT and an Http2ServerResponse for valid traditional/extended
1091
1178
  // HTTP/2 CONNECT, so portless's union-typed listener selects the
1092
1179
  // protocol arm with `instanceof net.Socket`.
1093
- const cb = L.lowerExpr(args[1]);
1180
+ const cb = lowerer.lowerExpr(args[1]);
1094
1181
  if (cb.type.kind !== "func" || cb.type.params.length > 3) {
1095
- L.unsupported("SC1090", args[1], "connect listeners with more than three parameters (use (req, socket, head))");
1182
+ lowerer.unsupported("SC1090", args[1], "connect listeners with more than three parameters (use (req, socket, head))");
1096
1183
  }
1097
1184
  if (cb.type.ret.kind !== "void") {
1098
- L.unsupported("SC1090", args[1], "connect listeners returning a value (make the callback body a block)");
1185
+ lowerer.unsupported("SC1090", args[1], "connect listeners returning a value (make the callback body a block)");
1099
1186
  }
1100
1187
  const [p0, p1, p2] = cb.type.params;
1101
1188
  const sockParamOk = (t) => {
@@ -1103,13 +1190,13 @@ function lowerNetServerMethodCall(L, call, access) {
1103
1190
  return true;
1104
1191
  if (t.kind !== "union")
1105
1192
  return false;
1106
- const def = L.unions.get(t.unionId);
1193
+ const def = lowerer.unions.get(t.unionId);
1107
1194
  return !!def && def.arms.some((a) => a.kind === "netSocket");
1108
1195
  };
1109
1196
  if ((p0 !== undefined && p0.kind !== "httpReq") ||
1110
1197
  (p1 !== undefined && !sockParamOk(p1)) ||
1111
1198
  (p2 !== undefined && !(p2.kind === "bytes" && p2.elem === "u8"))) {
1112
- L.unsupported("SC1090", args[1], "connect listeners whose parameters are not (req: IncomingMessage, socket: Socket — or a union carrying the Socket arm, the h2 compat shape, head: Buffer)");
1199
+ lowerer.unsupported("SC1090", args[1], "connect listeners whose parameters are not (req: IncomingMessage, socket: Socket — or a union carrying the Socket arm, the h2 compat shape, head: Buffer)");
1113
1200
  }
1114
1201
  return { kind: "libCall", fn: "http.serverOnConnect", args: [receiver, cb, once], type: VOID, loc };
1115
1202
  }
@@ -1119,50 +1206,50 @@ function lowerNetServerMethodCall(L, call, access) {
1119
1206
  // socket over raw with the bytes read past the head, and destroys
1120
1207
  // the socket when no listener exists. Registration works on every
1121
1208
  // server kind (a parserless net server never fires it, like Node).
1122
- const cb = L.lowerExpr(args[1]);
1209
+ const cb = lowerer.lowerExpr(args[1]);
1123
1210
  if (cb.type.kind !== "func" || cb.type.params.length > 3) {
1124
- L.unsupported("SC1090", args[1], "upgrade listeners with more than three parameters (use (req, socket, head))");
1211
+ lowerer.unsupported("SC1090", args[1], "upgrade listeners with more than three parameters (use (req, socket, head))");
1125
1212
  }
1126
1213
  if (cb.type.ret.kind !== "void") {
1127
- L.unsupported("SC1090", args[1], "upgrade listeners returning a value (make the callback body a block)");
1214
+ lowerer.unsupported("SC1090", args[1], "upgrade listeners returning a value (make the callback body a block)");
1128
1215
  }
1129
1216
  const [p0, p1, p2] = cb.type.params;
1130
1217
  if ((p0 !== undefined && p0.kind !== "httpReq") ||
1131
1218
  (p1 !== undefined && p1.kind !== "netSocket") ||
1132
1219
  (p2 !== undefined && !(p2.kind === "bytes" && p2.elem === "u8"))) {
1133
- L.unsupported("SC1090", args[1], "upgrade listeners whose parameters are not (req: IncomingMessage, socket: Socket, head: Buffer)");
1220
+ lowerer.unsupported("SC1090", args[1], "upgrade listeners whose parameters are not (req: IncomingMessage, socket: Socket, head: Buffer)");
1134
1221
  }
1135
1222
  return { kind: "libCall", fn: "http.serverOnUpgrade", args: [receiver, cb, once], type: VOID, loc };
1136
1223
  }
1137
1224
  if (event === "sessionError") {
1138
- const cb = L.lowerExpr(args[1]);
1225
+ const cb = lowerer.lowerExpr(args[1]);
1139
1226
  if (cb.type.kind !== "func" || cb.type.ret.kind !== "void" || cb.type.params.length > 2) {
1140
- L.unsupported("SC1090", args[1], "sessionError listeners with more than two parameters or returning a value");
1227
+ lowerer.unsupported("SC1090", args[1], "sessionError listeners with more than two parameters or returning a value");
1141
1228
  }
1142
1229
  const [err, session] = cb.type.params;
1143
1230
  if ((err !== undefined && !(err.kind === "object" && err.className === "%Error")) ||
1144
1231
  (session !== undefined && session.kind !== "http2Session")) {
1145
- L.unsupported("SC1090", args[1], "sessionError listeners whose parameters are not (error: Error, session: ServerHttp2Session)");
1232
+ lowerer.unsupported("SC1090", args[1], "sessionError listeners whose parameters are not (error: Error, session: ServerHttp2Session)");
1146
1233
  }
1147
1234
  return { kind: "libCall", fn: "http2.serverOnSessionError", args: [receiver, cb, once], type: VOID, loc };
1148
1235
  }
1149
- L.noLowering(`server.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, args[0], '"connection", "request", "stream", "session", "upgrade", "connect", "error", "close", "listening", and "sessionError" are the supported server events (as literals)');
1236
+ lowerer.noLowering(`server.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, args[0], '"connection", "request", "stream", "session", "upgrade", "connect", "error", "close", "listening", and "sessionError" are the supported server events (as literals)');
1150
1237
  }
1151
1238
  if (name === "emit") {
1152
1239
  // The demux route: emit("connection", socket) hands an accepted
1153
1240
  // socket to ANOTHER server (portless's first-byte TLS peek). Only
1154
1241
  // the literal "connection" form lowers; Node's boolean result is
1155
1242
  // dropped (statement position required).
1156
- requireStatementPosition(L, call, "server.emit(...)");
1157
- const evT = args.length >= 1 ? L.typeOf(args[0]) : null;
1243
+ requireStatementPosition(lowerer, call, "server.emit(...)");
1244
+ const evT = args.length >= 1 ? lowerer.typeOf(args[0]) : null;
1158
1245
  const event = evT?.isStringLiteralType() ? evT.value : null;
1159
1246
  if (event !== "connection" || args.length !== 2) {
1160
- L.noLowering(`server.emit(${event === null ? "non-literal event" : `"${event}"`}, ...)`, call, 'emit("connection", socket) is the supported emit form (the demux route)');
1247
+ lowerer.noLowering(`server.emit(${event === null ? "non-literal event" : `"${event}"`}, ...)`, call, 'emit("connection", socket) is the supported emit form (the demux route)');
1161
1248
  }
1162
- const receiver = handleReceiver(L, access.expression, NETSERVER_T);
1163
- const sock = L.lowerExpr(args[1]);
1249
+ const receiver = coerceToHandle(lowerer, access.expression, NETSERVER_T);
1250
+ const sock = lowerer.lowerExpr(args[1]);
1164
1251
  if (sock.type.kind !== "netSocket") {
1165
- L.noLowering(`emit("connection", …) with a '${L.fmt(sock.type)}' argument`, args[1], "the second argument must be a net socket");
1252
+ lowerer.noLowering(`emit("connection", …) with a '${lowerer.fmt(sock.type)}' argument`, args[1], "the second argument must be a net socket");
1166
1253
  }
1167
1254
  return { kind: "libCall", fn: "net.serverEmitConnection", args: [receiver, sock], type: VOID, loc };
1168
1255
  }
@@ -1172,30 +1259,30 @@ function lowerNetServerMethodCall(L, call, access) {
1172
1259
  // the property path; this is the record-valued remainder (`const a =
1173
1260
  // server.address()` — the listen-callback shape).
1174
1261
  if (args.length !== 0) {
1175
- L.noLowering(`address with ${args.length} arguments`, call, "address() takes no arguments");
1262
+ lowerer.noLowering(`address with ${args.length} arguments`, call, "address() takes no arguments");
1176
1263
  }
1177
- const result = L.mapTypeOf(L.typeOf(call));
1178
- if (!result || !isAddressInfoRecord(L, result)) {
1179
- L.noLowering("address() where the result is not the {address, family, port} record", call, "the AddressInfo shape is the supported result");
1264
+ const result = lowerer.mapTypeOf(lowerer.typeOf(call));
1265
+ if (!result || !isAddressInfoRecord(lowerer, result)) {
1266
+ lowerer.noLowering("address() where the result is not the {address, family, port} record", call, "the AddressInfo shape is the supported result");
1180
1267
  }
1181
- const receiver = handleReceiver(L, access.expression, NETSERVER_T);
1268
+ const receiver = coerceToHandle(lowerer, access.expression, NETSERVER_T);
1182
1269
  return { kind: "libCall", fn: "net.serverAddress", args: [receiver], type: result, loc };
1183
1270
  }
1184
- L.noLowering(`Server.${name}`, call, "listen, close, address().port, emit(\"connection\", socket), and on/once of connection/request/upgrade/error/close/listening/sessionError are the supported Server members", L.checker.getSymbolAtLocation(access.name));
1271
+ lowerer.noLowering(`Server.${name}`, call, "listen, close, address().port, emit(\"connection\", socket), and on/once of connection/request/upgrade/error/close/listening/sessionError are the supported Server members", lowerer.checker.getSymbolAtLocation(access.name));
1185
1272
  }
1186
1273
  /** Method calls on net.Socket receivers: write/end/destroy/pipe and
1187
1274
  * on/once("data" | "end" | "close" | "error" | "connect"). Null for
1188
1275
  * other receivers. */
1189
- function lowerNetSocketMethodCall(L, call, access) {
1190
- if (L.mapTypeOf(L.typeOf(access.expression))?.kind !== "netSocket")
1276
+ function lowerNetSocketMethodCall(lowerer, call, access) {
1277
+ if (lowerer.mapTypeOf(lowerer.typeOf(access.expression))?.kind !== "netSocket")
1191
1278
  return null;
1192
- if (!L.isStdlibMember(access))
1279
+ if (!lowerer.isStdlibMember(access))
1193
1280
  return null;
1194
1281
  const name = access.name.text;
1195
1282
  const loc = locOf(call);
1196
1283
  const args = call.arguments;
1197
1284
  if (name === "write" || name === "end") {
1198
- requireStatementPosition(L, call, `socket.${name}(...)`);
1285
+ requireStatementPosition(lowerer, call, `socket.${name}(...)`);
1199
1286
  // write(chunk, encoding) — the two-argument encoding form: 'buffer'
1200
1287
  // beside a string chunk is Node's stream_base typecheck ("Second
1201
1288
  // argument must be a buffer", thrown synchronously on an established
@@ -1203,36 +1290,36 @@ function lowerNetSocketMethodCall(L, call, access) {
1203
1290
  // plain write (that IS the encoding written); a Buffer chunk ignores
1204
1291
  // the encoding like Node does. Other encodings keep the fence.
1205
1292
  if (name === "write" && args.length === 2) {
1206
- const encT = L.typeOf(args[1]);
1207
- const chunkT = L.mapTypeOf(L.typeOf(args[0]));
1293
+ const encT = lowerer.typeOf(args[1]);
1294
+ const chunkT = lowerer.mapTypeOf(lowerer.typeOf(args[0]));
1208
1295
  if (encT.isStringLiteralType() && chunkT !== null) {
1209
1296
  if (encT.value === "buffer" && chunkT.kind === "string" &&
1210
1297
  isJsSourceFile(call.getSourceFile())) {
1211
- L.lowerExpr(args[0]); // evaluation order (effect-free in practice)
1298
+ lowerer.lowerExpr(args[0]); // evaluation order (effect-free in practice)
1212
1299
  return nodeThrowExpr(1, "ERR_INVALID_ARG_TYPE", "Second argument must be a buffer", VOID, loc);
1213
1300
  }
1214
1301
  const passthrough = (chunkT.kind === "string" && (encT.value === "utf8" || encT.value === "utf-8")) ||
1215
1302
  (chunkT.kind === "bytes" && chunkT.elem === "u8");
1216
1303
  if (passthrough) {
1217
- const receiver2 = handleReceiver(L, access.expression, NETSOCKET_T);
1218
- const data2 = L.lowerExpr(args[0]);
1219
- const fn = data2.type.kind === "string" ? "net.sockWrite" : "net.sockWriteBytes";
1220
- return { kind: "libCall", fn, args: [receiver2, data2], type: VOID, loc };
1304
+ const socket = coerceToHandle(lowerer, access.expression, NETSOCKET_T);
1305
+ const chunk = lowerer.lowerExpr(args[0]);
1306
+ const fn = chunk.type.kind === "string" ? "net.sockWrite" : "net.sockWriteBytes";
1307
+ return { kind: "libCall", fn, args: [socket, chunk], type: VOID, loc };
1221
1308
  }
1222
1309
  }
1223
1310
  }
1224
1311
  const maxArgs = name === "write" ? 1 : 1;
1225
1312
  const minArgs = name === "write" ? 1 : 0;
1226
1313
  if (args.length < minArgs || args.length > maxArgs) {
1227
- L.noLowering(`${name} with ${args.length} arguments`, call, name === "write"
1314
+ lowerer.noLowering(`${name} with ${args.length} arguments`, call, name === "write"
1228
1315
  ? "the supported form is write(data) — one string or Buffer"
1229
1316
  : "the supported forms are end() and end(data)");
1230
1317
  }
1231
- const receiver = handleReceiver(L, access.expression, NETSOCKET_T);
1318
+ const receiver = coerceToHandle(lowerer, access.expression, NETSOCKET_T);
1232
1319
  if (args.length === 0) {
1233
1320
  return { kind: "libCall", fn: "net.sockEnd", args: [receiver], type: VOID, loc };
1234
1321
  }
1235
- const data = L.lowerExpr(args[0]);
1322
+ const data = lowerer.lowerExpr(args[0]);
1236
1323
  if (data.type.kind === "string") {
1237
1324
  const fn = name === "write" ? "net.sockWrite" : "net.sockEndStr";
1238
1325
  return { kind: "libCall", fn, args: [receiver, data], type: VOID, loc };
@@ -1247,33 +1334,33 @@ function lowerNetSocketMethodCall(L, call, access) {
1247
1334
  const fn = name === "write" ? "net.sockWriteDyn" : "net.sockEndDyn";
1248
1335
  return { kind: "libCall", fn, args: [receiver, data], type: VOID, loc };
1249
1336
  }
1250
- L.noLowering(`${name} of '${L.fmt(data.type)}' data`, args[0] ?? call, NARROW_DATA_HINT);
1337
+ lowerer.noLowering(`${name} of '${lowerer.fmt(data.type)}' data`, args[0] ?? call, NARROW_DATA_HINT);
1251
1338
  }
1252
1339
  if (name === "destroy") {
1253
- requireStatementPosition(L, call, "socket.destroy()");
1340
+ requireStatementPosition(lowerer, call, "socket.destroy()");
1254
1341
  if (args.length !== 0) {
1255
- L.noLowering(`destroy with ${args.length} arguments`, call, "destroy() takes no arguments here");
1342
+ lowerer.noLowering(`destroy with ${args.length} arguments`, call, "destroy() takes no arguments here");
1256
1343
  }
1257
- const receiver = handleReceiver(L, access.expression, NETSOCKET_T);
1344
+ const receiver = coerceToHandle(lowerer, access.expression, NETSOCKET_T);
1258
1345
  return { kind: "libCall", fn: "net.sockDestroy", args: [receiver], type: VOID, loc };
1259
1346
  }
1260
1347
  if (name === "setEncoding") {
1261
1348
  // The req twin: utf8 flips 'data' delivery to strings.
1262
- requireStatementPosition(L, call, "socket.setEncoding(...)");
1349
+ requireStatementPosition(lowerer, call, "socket.setEncoding(...)");
1263
1350
  if (args.length !== 1) {
1264
- L.noLowering(`setEncoding with ${args.length} arguments`, call, "the supported form is setEncoding(encoding)");
1351
+ lowerer.noLowering(`setEncoding with ${args.length} arguments`, call, "the supported form is setEncoding(encoding)");
1265
1352
  }
1266
- const receiver = handleReceiver(L, access.expression, NETSOCKET_T);
1267
- const enc = L.lowerExprExpecting(args[0], STRING);
1353
+ const receiver = coerceToHandle(lowerer, access.expression, NETSOCKET_T);
1354
+ const enc = lowerer.lowerExprExpecting(args[0], STRING);
1268
1355
  return { kind: "libCall", fn: "net.sockSetEncoding", args: [receiver, enc], type: VOID, loc };
1269
1356
  }
1270
1357
  if (name === "setTimeout") {
1271
- requireStatementPosition(L, call, "socket.setTimeout(...)");
1358
+ requireStatementPosition(lowerer, call, "socket.setTimeout(...)");
1272
1359
  if (args.length !== 1) {
1273
- L.noLowering(`setTimeout with ${args.length} arguments`, call, "the supported form is setTimeout(ms) — register the callback separately: socket.once('timeout', ...)");
1360
+ lowerer.noLowering(`setTimeout with ${args.length} arguments`, call, "the supported form is setTimeout(ms) — register the callback separately: socket.once('timeout', ...)");
1274
1361
  }
1275
- const receiver = handleReceiver(L, access.expression, NETSOCKET_T);
1276
- const ms = L.lowerExprExpecting(args[0], F64);
1362
+ const receiver = coerceToHandle(lowerer, access.expression, NETSOCKET_T);
1363
+ const ms = lowerer.lowerExprExpecting(args[0], F64);
1277
1364
  return { kind: "libCall", fn: "net.sockSetTimeout", args: [receiver, ms], type: VOID, loc };
1278
1365
  }
1279
1366
  if (name === "pause" || name === "resume") {
@@ -1282,9 +1369,9 @@ function lowerNetSocketMethodCall(L, call, access) {
1282
1369
  // (and discards sans listeners, so 'end' is reachable). Both answer
1283
1370
  // the socket, Node's chaining.
1284
1371
  if (args.length !== 0) {
1285
- L.noLowering(`${name} with ${args.length} arguments`, call, `the form is ${name}()`);
1372
+ lowerer.noLowering(`${name} with ${args.length} arguments`, call, `the form is ${name}()`);
1286
1373
  }
1287
- const receiver = handleReceiver(L, access.expression, NETSOCKET_T);
1374
+ const receiver = coerceToHandle(lowerer, access.expression, NETSOCKET_T);
1288
1375
  const fn = name === "pause" ? "net.sockPause" : "net.sockResume";
1289
1376
  return { kind: "libCall", fn, args: [receiver], type: NETSOCKET_T, loc };
1290
1377
  }
@@ -1292,22 +1379,22 @@ function lowerNetSocketMethodCall(L, call, access) {
1292
1379
  // TCP_NODELAY on the live fd; missing/undefined means true (Node).
1293
1380
  // Answers the socket, Node's chaining.
1294
1381
  if (args.length > 1) {
1295
- L.noLowering(`setNoDelay with ${args.length} arguments`, call, "the form is setNoDelay(noDelay?)");
1382
+ lowerer.noLowering(`setNoDelay with ${args.length} arguments`, call, "the form is setNoDelay(noDelay?)");
1296
1383
  }
1297
- const receiver = handleReceiver(L, access.expression, NETSOCKET_T);
1384
+ const receiver = coerceToHandle(lowerer, access.expression, NETSOCKET_T);
1298
1385
  const enable = args.length === 1
1299
- ? L.lowerExprExpecting(args[0], BOOL)
1386
+ ? lowerer.lowerExprExpecting(args[0], BOOL)
1300
1387
  : boolLit(true, loc);
1301
1388
  return { kind: "libCall", fn: "net.sockSetNoDelay", args: [receiver, enable], type: NETSOCKET_T, loc };
1302
1389
  }
1303
1390
  if (name === "destroySoon") {
1304
1391
  // end() now, destroy once the FIN actually flushed — Node's
1305
1392
  // 'finish'-then-destroy.
1306
- requireStatementPosition(L, call, "socket.destroySoon()");
1393
+ requireStatementPosition(lowerer, call, "socket.destroySoon()");
1307
1394
  if (args.length !== 0) {
1308
- L.noLowering(`destroySoon with ${args.length} arguments`, call, "the form is destroySoon()");
1395
+ lowerer.noLowering(`destroySoon with ${args.length} arguments`, call, "the form is destroySoon()");
1309
1396
  }
1310
- const receiver = handleReceiver(L, access.expression, NETSOCKET_T);
1397
+ const receiver = coerceToHandle(lowerer, access.expression, NETSOCKET_T);
1311
1398
  return { kind: "libCall", fn: "net.sockDestroySoon", args: [receiver], type: VOID, loc };
1312
1399
  }
1313
1400
  if (name === "read") {
@@ -1315,61 +1402,61 @@ function lowerNetSocketMethodCall(L, call, access) {
1315
1402
  // `Buffer | null` union: exactly n buffered bytes, or null (Node's
1316
1403
  // less-than-n answer); read() drains the whole buffer.
1317
1404
  if (args.length > 1) {
1318
- L.noLowering(`read with ${args.length} arguments`, call, "the supported forms are read() and read(n)");
1405
+ lowerer.noLowering(`read with ${args.length} arguments`, call, "the supported forms are read() and read(n)");
1319
1406
  }
1320
- const receiver = handleReceiver(L, access.expression, NETSOCKET_T);
1407
+ const receiver = coerceToHandle(lowerer, access.expression, NETSOCKET_T);
1321
1408
  const n = args.length === 1
1322
- ? L.lowerExprExpecting(args[0], F64)
1409
+ ? lowerer.lowerExprExpecting(args[0], F64)
1323
1410
  : { kind: "numLit", value: 0, type: F64, loc };
1324
- const type = { kind: "union", unionId: L.unions.intern([BYTES_U8, NULL_T]) };
1411
+ const type = { kind: "union", unionId: lowerer.unions.intern([BYTES_U8, NULL_T]) };
1325
1412
  return { kind: "libCall", fn: "net.sockRead", args: [receiver, n], type, loc };
1326
1413
  }
1327
1414
  if (name === "unshift") {
1328
- requireStatementPosition(L, call, "socket.unshift(...)");
1415
+ requireStatementPosition(lowerer, call, "socket.unshift(...)");
1329
1416
  if (args.length !== 1) {
1330
- L.noLowering(`unshift with ${args.length} arguments`, call, "the supported form is unshift(buffer)");
1417
+ lowerer.noLowering(`unshift with ${args.length} arguments`, call, "the supported form is unshift(buffer)");
1331
1418
  }
1332
- const receiver = handleReceiver(L, access.expression, NETSOCKET_T);
1333
- const data = L.lowerExpr(args[0]);
1419
+ const receiver = coerceToHandle(lowerer, access.expression, NETSOCKET_T);
1420
+ const data = lowerer.lowerExpr(args[0]);
1334
1421
  if (data.type.kind !== "bytes" || data.type.elem !== "u8") {
1335
- L.noLowering(`unshift of '${L.fmt(data.type)}' data`, args[0], "unshift takes one Buffer/Uint8Array (narrow unions first — the read(1) result needs its null arm checked)");
1422
+ lowerer.noLowering(`unshift of '${lowerer.fmt(data.type)}' data`, args[0], "unshift takes one Buffer/Uint8Array (narrow unions first — the read(1) result needs its null arm checked)");
1336
1423
  }
1337
1424
  return { kind: "libCall", fn: "net.sockUnshift", args: [receiver, data], type: VOID, loc };
1338
1425
  }
1339
1426
  if (name === "pipe") {
1340
- requireStatementPosition(L, call, "socket.pipe(...)");
1427
+ requireStatementPosition(lowerer, call, "socket.pipe(...)");
1341
1428
  if (args.length !== 1) {
1342
- L.noLowering(`pipe with ${args.length} arguments`, call, "the supported form is pipe(destination)");
1429
+ lowerer.noLowering(`pipe with ${args.length} arguments`, call, "the supported form is pipe(destination)");
1343
1430
  }
1344
- const receiver = handleReceiver(L, access.expression, NETSOCKET_T);
1345
- const dst = L.lowerExpr(args[0]);
1431
+ const receiver = coerceToHandle(lowerer, access.expression, NETSOCKET_T);
1432
+ const dst = lowerer.lowerExpr(args[0]);
1346
1433
  if (dst.type.kind === "httpRes") {
1347
1434
  // socket → ServerResponse (the extended-CONNECT bridge leg): raw
1348
1435
  // chunks become response body writes; EOF ends the response.
1349
1436
  return { kind: "libCall", fn: "net.sockPipeRes", args: [receiver, dst], type: VOID, loc };
1350
1437
  }
1351
1438
  if (dst.type.kind !== "netSocket") {
1352
- L.noLowering(`pipe into '${L.fmt(dst.type)}' destinations`, args[0], "a socket pipes into another socket or a ServerResponse");
1439
+ lowerer.noLowering(`pipe into '${lowerer.fmt(dst.type)}' destinations`, args[0], "a socket pipes into another socket or a ServerResponse");
1353
1440
  }
1354
1441
  return { kind: "libCall", fn: "net.sockPipe", args: [receiver, dst], type: VOID, loc };
1355
1442
  }
1356
1443
  if ((name === "on" || name === "once" || name === "addListener") && args.length === 2) {
1357
- requireStatementPosition(L, call, `socket.${name}(...)`);
1444
+ requireStatementPosition(lowerer, call, `socket.${name}(...)`);
1358
1445
  const once = boolLit(name === "once", loc);
1359
- const evT = L.typeOf(args[0]);
1446
+ const evT = lowerer.typeOf(args[0]);
1360
1447
  const event = evT.isStringLiteralType() ? evT.value : null;
1361
- const receiver = handleReceiver(L, access.expression, NETSOCKET_T);
1448
+ const receiver = coerceToHandle(lowerer, access.expression, NETSOCKET_T);
1362
1449
  if (event === "data") {
1363
- const { cb } = lowerCallbackArg(L, args[1], "data listeners", 1, (p) => p.kind === "bytes" && p.elem === "u8", "use (chunk: Buffer) or ()", [DYN]);
1450
+ const { cb } = lowerCallbackArg(lowerer, args[1], "data listeners", 1, (p) => p.kind === "bytes" && p.elem === "u8", "use (chunk: Buffer) or ()", [DYN]);
1364
1451
  return { kind: "libCall", fn: "net.sockOnData", args: [receiver, cb, once], type: VOID, loc };
1365
1452
  }
1366
1453
  if (event === "error") {
1367
- const { cb } = lowerCallbackArg(L, args[1], "error listeners", 1, (p) => p.kind === "object" && p.className === "%Error", "use (err) or ()", [ERROR_T]);
1454
+ const { cb } = lowerCallbackArg(lowerer, args[1], "error listeners", 1, (p) => p.kind === "object" && p.className === "%Error", "use (err) or ()", [ERROR_T]);
1368
1455
  return { kind: "libCall", fn: "net.sockOnError", args: [receiver, cb, once], type: VOID, loc };
1369
1456
  }
1370
1457
  if (event === "end" || event === "close" || event === "connect" || event === "timeout" ||
1371
1458
  event === "readable") {
1372
- const { cb } = lowerCallbackArg(L, args[1], `${event} listeners`, 0, () => false, "use ()", []);
1459
+ const { cb } = lowerCallbackArg(lowerer, args[1], `${event} listeners`, 0, () => false, "use ()", []);
1373
1460
  const fn = event === "end" ? "net.sockOnEnd"
1374
1461
  : event === "close" ? "net.sockOnClose"
1375
1462
  : event === "timeout" ? "net.sockOnTimeout"
@@ -1380,7 +1467,7 @@ function lowerNetSocketMethodCall(L, call, access) {
1380
1467
  if (event === "finish") {
1381
1468
  // Fires once when the FIN goes out — once either way (the event
1382
1469
  // happens at most once per socket).
1383
- const { cb } = lowerCallbackArg(L, args[1], "finish listeners", 0, () => false, "use ()", []);
1470
+ const { cb } = lowerCallbackArg(lowerer, args[1], "finish listeners", 0, () => false, "use ()", []);
1384
1471
  return { kind: "libCall", fn: "net.sockOnFinish", args: [receiver, cb], type: VOID, loc };
1385
1472
  }
1386
1473
  if (event === "secureConnect") {
@@ -1388,33 +1475,33 @@ function lowerNetSocketMethodCall(L, call, access) {
1388
1475
  // 'connect' list already fires at establishment (scr_net.c's
1389
1476
  // transport pump); the runtime gates on the transport so a plain
1390
1477
  // socket's registration never fires — Node's exact split.
1391
- const { cb } = lowerCallbackArg(L, args[1], "secureConnect listeners", 0, () => false, "use ()", []);
1478
+ const { cb } = lowerCallbackArg(lowerer, args[1], "secureConnect listeners", 0, () => false, "use ()", []);
1392
1479
  return { kind: "libCall", fn: "tls.sockOnSecureConnect", args: [receiver, cb, once], type: VOID, loc };
1393
1480
  }
1394
1481
  if (event === "session") {
1395
1482
  // The received-ticket event: fires once per TLS client socket with
1396
1483
  // the serialized session (a Buffer); plain sockets never fire it.
1397
- const { cb } = lowerCallbackArg(L, args[1], "session listeners", 1, (p) => p.kind === "bytes" && p.elem === "u8", "use (session: Buffer) or ()", [DYN]);
1484
+ const { cb } = lowerCallbackArg(lowerer, args[1], "session listeners", 1, (p) => p.kind === "bytes" && p.elem === "u8", "use (session: Buffer) or ()", [DYN]);
1398
1485
  return { kind: "libCall", fn: "tls.sockOnSession", args: [receiver, cb, once], type: VOID, loc };
1399
1486
  }
1400
- L.noLowering(`socket.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, args[0], '"data", "end", "close", "error", "connect", "timeout", "readable", "secureConnect", and "session" are the supported socket events (as literals)');
1487
+ lowerer.noLowering(`socket.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, args[0], '"data", "end", "close", "error", "connect", "timeout", "readable", "secureConnect", and "session" are the supported socket events (as literals)');
1401
1488
  }
1402
- L.noLowering(`Socket.${name}`, call, "write, end, destroy, pipe, setTimeout, remoteAddress, read, unshift, and on/once of data/end/close/error/connect/timeout/readable are the supported Socket members", L.checker.getSymbolAtLocation(access.name));
1489
+ lowerer.noLowering(`Socket.${name}`, call, "write, end, destroy, pipe, setTimeout, remoteAddress, read, unshift, and on/once of data/end/close/error/connect/timeout/readable are the supported Socket members", lowerer.checker.getSymbolAtLocation(access.name));
1403
1490
  }
1404
1491
  /** The method-call dispatch for both server-surface receiver kinds — one
1405
1492
  * entry in lower-calls.ts's intrinsic chain (the lowerChildMethodCall
1406
1493
  * slot). Null when the receiver is neither. */
1407
- export function lowerServerMethodCall(L, call, access) {
1408
- if (call.questionDotToken || (access.questionDotToken && !L.chainHandled.has(access)))
1494
+ export function lowerServerMethodCall(lowerer, call, access) {
1495
+ if (call.questionDotToken || (access.questionDotToken && !lowerer.chainHandled.has(access)))
1409
1496
  return null;
1410
- return (lowerServerCloseBind(L, call, access) ??
1411
- lowerNetServerMethodCall(L, call, access) ??
1412
- lowerNetSocketMethodCall(L, call, access) ??
1413
- lowerH2SessionMethodCall(L, call, access) ??
1414
- lowerH2StreamMethodCall(L, call, access) ??
1415
- lowerHttpReqMethodCall(L, call, access) ??
1416
- lowerHttpResMethodCall(L, call, access) ??
1417
- lowerHttpClientMethodCall(L, call, access));
1497
+ return (lowerServerCloseBind(lowerer, call, access) ??
1498
+ lowerNetServerMethodCall(lowerer, call, access) ??
1499
+ lowerNetSocketMethodCall(lowerer, call, access) ??
1500
+ lowerH2SessionMethodCall(lowerer, call, access) ??
1501
+ lowerH2StreamMethodCall(lowerer, call, access) ??
1502
+ lowerHttpReqMethodCall(lowerer, call, access) ??
1503
+ lowerHttpResMethodCall(lowerer, call, access) ??
1504
+ lowerHttpClientMethodCall(lowerer, call, access));
1418
1505
  }
1419
1506
  /** The `{ ...req.headers }` SNAPSHOT helper, interned per target shape —
1420
1507
  * the envSnapshotHelper pattern over http.reqHeaderPairs: a fresh
@@ -1422,107 +1509,27 @@ export function lowerServerMethodCall(L, call, access) {
1422
1509
  * arrival order), each value wrapped at the slot union's string arm. Null
1423
1510
  * when the shape is not a pure index-signature record with a string arm
1424
1511
  * (the caller fences). */
1425
- function headersSnapshotHelper(L, shapeId, loc) {
1426
- const shape = L.shapes.get(shapeId);
1427
- if (!shape || shape.tuple || shape.fields.length > 0 || !shape.indexValue)
1428
- return null;
1429
- const iv = shape.indexValue;
1430
- if (iv.kind !== "union")
1431
- return null;
1432
- const strTag = L.armTag(iv.unionId, STRING);
1433
- if (strTag < 0)
1434
- return null;
1435
- const key = `headers.snapshot:${shapeId}`;
1436
- const existing = L.widthHelpers.get(key);
1437
- if (existing)
1438
- return existing;
1439
- const name = `%headers.snapshot.${L.widthHelpers.size}`;
1440
- L.widthHelpers.set(key, name);
1441
- const recT = { kind: "record", shapeId };
1442
- const pairsT = arrayOf(STRING);
1443
- const ref = (localId, type) => ({ kind: "varRef", localId, type, loc });
1444
- const num = (value) => ({ kind: "numLit", value, type: F64, loc });
1445
- const pairAt = (offset) => ({
1446
- kind: "arrayGet",
1447
- arr: ref("ps.0", pairsT),
1448
- index: offset === 0
1449
- ? ref("i.0", F64)
1450
- : { kind: "bin", op: "+", left: ref("i.0", F64), right: num(offset), type: F64, loc },
1451
- type: STRING,
1452
- loc,
1453
- });
1454
- const body = [
1455
- {
1456
- kind: "varDecl",
1457
- localId: "ps.0",
1458
- init: { kind: "libCall", fn: "http.reqHeaderPairs", args: [ref("r.0", HTTPREQ_T)], type: pairsT, loc },
1459
- loc,
1460
- },
1461
- {
1462
- kind: "varDecl",
1463
- localId: "out.0",
1464
- init: { kind: "recordLit", fields: [], type: recT, loc },
1465
- loc,
1466
- },
1467
- {
1468
- kind: "for",
1469
- init: { kind: "varDecl", localId: "i.0", init: num(0), loc },
1470
- cond: {
1471
- kind: "bin",
1472
- op: "<",
1473
- left: ref("i.0", F64),
1474
- right: { kind: "arrIntrinsic", method: "length", receiver: ref("ps.0", pairsT), args: [], type: F64, loc },
1475
- type: BOOL,
1476
- loc,
1477
- },
1478
- update: {
1479
- kind: "assign",
1480
- localId: "i.0",
1481
- value: { kind: "bin", op: "+", left: ref("i.0", F64), right: num(2), type: F64, loc },
1482
- loc,
1483
- },
1484
- body: [
1485
- {
1486
- kind: "recordKeySet",
1487
- obj: ref("out.0", recT),
1488
- shapeId,
1489
- key: pairAt(0),
1490
- value: { kind: "unionWrap", unionId: iv.unionId, tag: strTag, value: pairAt(1), type: iv, loc },
1491
- loc,
1492
- },
1493
- ],
1494
- loc,
1495
- },
1496
- { kind: "return", value: ref("out.0", recT), loc },
1497
- ];
1498
- L.liftedFns.push({
1499
- name,
1512
+ function headersSnapshotHelper(lowerer, shapeId, loc) {
1513
+ return pairsSnapshotHelper(lowerer, shapeId, loc, {
1514
+ keyPrefix: "headers",
1515
+ libCall: "http.reqHeaderPairs",
1500
1516
  params: [{ localId: "r.0", name: "r", type: HTTPREQ_T }],
1501
- returnType: recT,
1502
- locals: [
1503
- { id: "r.0", name: "r", type: HTTPREQ_T, mutable: false },
1504
- { id: "ps.0", name: "ps", type: pairsT, mutable: false },
1505
- { id: "out.0", name: "out", type: recT, mutable: false },
1506
- { id: "i.0", name: "i", type: F64, mutable: true },
1507
- ],
1508
- body,
1509
- loc,
1517
+ callArgs: [varRef("r.0", HTTPREQ_T, loc)],
1510
1518
  });
1511
- return name;
1512
1519
  }
1513
1520
  /** The `endStream` boolean of an h2 options object literal, as a literal
1514
1521
  * bool. Returns undefined when absent (or the arg is absent). Fences on
1515
1522
  * a non-literal endStream value or unknown keys that would matter. */
1516
- function h2EndStreamOption(L, node) {
1523
+ function h2EndStreamOption(lowerer, node) {
1517
1524
  if (node === undefined)
1518
1525
  return undefined;
1519
1526
  if (!ts.isObjectLiteralExpression(node)) {
1520
- L.noLowering("h2 options argument", node, "pass the options as an object literal ({ endStream: true })");
1527
+ lowerer.noLowering("h2 options argument", node, "pass the options as an object literal ({ endStream: true })");
1521
1528
  }
1522
1529
  let end;
1523
1530
  for (const prop of node.properties) {
1524
1531
  if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name)) {
1525
- L.noLowering("h2 options with spreads or computed keys", prop, "use plain `name: value` entries");
1532
+ lowerer.noLowering("h2 options with spreads or computed keys", prop, "use plain `name: value` entries");
1526
1533
  }
1527
1534
  const key = prop.name.text;
1528
1535
  if (key === "endStream") {
@@ -1531,7 +1538,7 @@ function h2EndStreamOption(L, node) {
1531
1538
  else if (prop.initializer.kind === ts.SyntaxKind.FalseKeyword)
1532
1539
  end = false;
1533
1540
  else
1534
- L.noLowering("a non-literal endStream option", prop.initializer, "spell it true or false");
1541
+ lowerer.noLowering("a non-literal endStream option", prop.initializer, "spell it true or false");
1535
1542
  }
1536
1543
  // Other keys (waitForTrailers, exclusive, parent, weight) are accepted
1537
1544
  // and ignored — the honest-defaults stance (they tune framing this
@@ -1541,35 +1548,35 @@ function h2EndStreamOption(L, node) {
1541
1548
  }
1542
1549
  /** Method calls on ClientHttp2Session / ServerHttp2Session receivers.
1543
1550
  * Null for other receivers (the chain keeps trying). */
1544
- function lowerH2SessionMethodCall(L, call, access) {
1545
- if (L.mapTypeOf(L.typeOf(access.expression))?.kind !== "http2Session")
1551
+ function lowerH2SessionMethodCall(lowerer, call, access) {
1552
+ if (lowerer.mapTypeOf(lowerer.typeOf(access.expression))?.kind !== "http2Session")
1546
1553
  return null;
1547
- if (!L.isStdlibMember(access))
1554
+ if (!lowerer.isStdlibMember(access))
1548
1555
  return null;
1549
1556
  const name = access.name.text;
1550
1557
  const loc = locOf(call);
1551
1558
  const args = call.arguments;
1552
- const receiver = () => handleReceiver(L, access.expression, HTTP2SESSION_T);
1559
+ const receiver = () => coerceToHandle(lowerer, access.expression, HTTP2SESSION_T);
1553
1560
  if (name === "request") {
1554
1561
  const pairs = args.length >= 1 && !ts.isObjectLiteralExpression(args[0]) === false && args.length >= 1
1555
1562
  ? null : null;
1556
1563
  void pairs;
1557
1564
  // arg0: headers (optional), arg1: options (optional).
1558
- const headersArg = args.length >= 1 ? lowerH2HeadersArg(L, args[0]) : { kind: "arrayLit", elems: [], type: arrayOf(STRING), loc };
1559
- const end = h2EndStreamOption(L, args[1]);
1565
+ const headersArg = args.length >= 1 ? lowerH2HeadersArg(lowerer, args[0]) : { kind: "arrayLit", elems: [], type: arrayOf(STRING), loc };
1566
+ const end = h2EndStreamOption(lowerer, args[1]);
1560
1567
  const endF64 = { kind: "numLit", value: end === undefined ? -1 : end ? 1 : 0, type: F64, loc };
1561
1568
  return { kind: "libCall", fn: "http2.sessionRequest", args: [receiver(), headersArg, endF64], type: HTTP2STREAM_T, loc };
1562
1569
  }
1563
1570
  if (name === "close") {
1564
- requireStatementPosition(L, call, "session.close(...)");
1571
+ requireStatementPosition(lowerer, call, "session.close(...)");
1565
1572
  if (args.length === 0) {
1566
1573
  return { kind: "libCall", fn: "http2.sessionClose", args: [receiver()], type: VOID, loc };
1567
1574
  }
1568
- const { cb } = lowerCallbackArg(L, args[0], "close callbacks", 0, () => false, "use ()", []);
1575
+ const { cb } = lowerCallbackArg(lowerer, args[0], "close callbacks", 0, () => false, "use ()", []);
1569
1576
  return { kind: "libCall", fn: "http2.sessionCloseCb", args: [receiver(), cb], type: VOID, loc };
1570
1577
  }
1571
1578
  if (name === "destroy") {
1572
- requireStatementPosition(L, call, "session.destroy(...)");
1579
+ requireStatementPosition(lowerer, call, "session.destroy(...)");
1573
1580
  return { kind: "libCall", fn: "http2.sessionDestroy", args: [receiver()], type: VOID, loc };
1574
1581
  }
1575
1582
  if (name === "settings") {
@@ -1577,110 +1584,110 @@ function lowerH2SessionMethodCall(L, call, access) {
1577
1584
  // value (the checked-dynamic boundary — object literals box); the
1578
1585
  // callback fires on the peer's ACK ((err, settings, duration) in the
1579
1586
  // dyn flavor, zero-arg in the typed one).
1580
- requireStatementPosition(L, call, "session.settings(...)");
1587
+ requireStatementPosition(lowerer, call, "session.settings(...)");
1581
1588
  if (args.length === 0) {
1582
1589
  return { kind: "libCall", fn: "http2.sessionSettings0", args: [receiver()], type: VOID, loc };
1583
1590
  }
1584
- const v = L.lowerExpr(args[0]);
1591
+ const v = lowerer.lowerExpr(args[0]);
1585
1592
  const settingsArg = v.type.kind === "dyn" ? v : { kind: "dynFrom", value: v, type: DYN, loc };
1586
1593
  if (args.length >= 2) {
1587
- const cbV = L.lowerExpr(args[1]);
1594
+ const cbV = lowerer.lowerExpr(args[1]);
1588
1595
  if (cbV.type.kind === "dyn") {
1589
1596
  // The dyn callback keeps Node's exact (err, settings, duration)
1590
1597
  // shape — the runtime fires it through the checked-dynamic tree.
1591
1598
  return { kind: "libCall", fn: "http2.sessionSettingsDynCb", args: [receiver(), settingsArg, cbV], type: VOID, loc };
1592
1599
  }
1593
- const { cb } = lowerCallbackArg(L, args[1], "settings callbacks", 0, () => false, "use () — or a dynamic (mustCall-wrapped) callback for the (err, settings, duration) shape", []);
1600
+ const { cb } = lowerCallbackArg(lowerer, args[1], "settings callbacks", 0, () => false, "use () — or a dynamic (mustCall-wrapped) callback for the (err, settings, duration) shape", []);
1594
1601
  return { kind: "libCall", fn: "http2.sessionSettingsCb0", args: [receiver(), settingsArg, cb], type: VOID, loc };
1595
1602
  }
1596
1603
  return { kind: "libCall", fn: "http2.sessionSettings", args: [receiver(), settingsArg], type: VOID, loc };
1597
1604
  }
1598
1605
  if ((name === "on" || name === "once" || name === "addListener") && args.length === 2) {
1599
- requireStatementPosition(L, call, `session.${name}(...)`);
1606
+ requireStatementPosition(lowerer, call, `session.${name}(...)`);
1600
1607
  const once = boolLit(name === "once", loc);
1601
- const evT = L.typeOf(args[0]);
1608
+ const evT = lowerer.typeOf(args[0]);
1602
1609
  const event = evT.isStringLiteralType() ? evT.value : null;
1603
1610
  if (event === "localSettings" || event === "remoteSettings") {
1604
1611
  // The settings payload crosses as a dyn value: dyn (mustCall)
1605
1612
  // listeners fire with the settings record; zero-arg typed
1606
1613
  // listeners register plainly.
1607
1614
  const local = boolLit(event === "localSettings", loc);
1608
- const cbV = L.lowerExpr(args[1]);
1615
+ const cbV = lowerer.lowerExpr(args[1]);
1609
1616
  if (cbV.type.kind === "dyn") {
1610
1617
  return { kind: "libCall", fn: "http2.sessionOnSettingsDyn", args: [receiver(), cbV, once, local], type: VOID, loc };
1611
1618
  }
1612
- const { cb } = lowerCallbackArg(L, args[1], `${event} listeners`, 0, () => false, "use () — or a dynamic (mustCall-wrapped) listener for the (settings) payload", []);
1619
+ const { cb } = lowerCallbackArg(lowerer, args[1], `${event} listeners`, 0, () => false, "use () — or a dynamic (mustCall-wrapped) listener for the (settings) payload", []);
1613
1620
  return { kind: "libCall", fn: "http2.sessionOnSettings0", args: [receiver(), cb, once, local], type: VOID, loc };
1614
1621
  }
1615
1622
  if (event === "close") {
1616
- const { cb } = lowerCallbackArg(L, args[1], "close listeners", 0, () => false, "use ()", []);
1623
+ const { cb } = lowerCallbackArg(lowerer, args[1], "close listeners", 0, () => false, "use ()", []);
1617
1624
  return { kind: "libCall", fn: "http2.sessionOnClose", args: [receiver(), cb, once], type: VOID, loc };
1618
1625
  }
1619
1626
  if (event === "error") {
1620
- const { cb } = lowerCallbackArg(L, args[1], "error listeners", 1, (p) => p.kind === "object" && p.className === "%Error", "use (err) or ()", [ERROR_T]);
1627
+ const { cb } = lowerCallbackArg(lowerer, args[1], "error listeners", 1, (p) => p.kind === "object" && p.className === "%Error", "use (err) or ()", [ERROR_T]);
1621
1628
  return { kind: "libCall", fn: "http2.sessionOnError", args: [receiver(), cb, once], type: VOID, loc };
1622
1629
  }
1623
1630
  if (event === "connect") {
1624
- const { cb } = lowerCallbackArg(L, args[1], "connect listeners", 2, (p) => p.kind === "http2Session" || p.kind === "netSocket", "use (session, socket) or ()", [HTTP2SESSION_T, NETSOCKET_T]);
1631
+ const { cb } = lowerCallbackArg(lowerer, args[1], "connect listeners", 2, (p) => p.kind === "http2Session" || p.kind === "netSocket", "use (session, socket) or ()", [HTTP2SESSION_T, NETSOCKET_T]);
1625
1632
  return { kind: "libCall", fn: "http2.sessionOnConnect", args: [receiver(), cb, once], type: VOID, loc };
1626
1633
  }
1627
1634
  if (event === "stream") {
1628
- const cb = h2HeadersCallbackAdapter(L, args[1], "stream listeners", "http2Stream", false, loc);
1635
+ const cb = h2HeadersCallbackAdapter(lowerer, args[1], "stream listeners", "http2Stream", false, loc);
1629
1636
  return { kind: "libCall", fn: "http2.sessionOnStream", args: [receiver(), cb, once], type: VOID, loc };
1630
1637
  }
1631
1638
  if (event === "goaway") {
1632
- const cb = L.lowerExpr(args[1]);
1639
+ const cb = lowerer.lowerExpr(args[1]);
1633
1640
  if (cb.type.kind !== "func" || cb.type.ret.kind !== "void" || cb.type.params.length > 3) {
1634
- L.unsupported("SC1090", args[1], "goaway listeners with more than three parameters or returning a value");
1641
+ lowerer.unsupported("SC1090", args[1], "goaway listeners with more than three parameters or returning a value");
1635
1642
  }
1636
1643
  if (cb.type.params.some((p) => p.kind !== "f64" && p.kind !== "bytes")) {
1637
- L.unsupported("SC1090", args[1], "goaway listeners whose parameters are not (errorCode, lastStreamID, opaqueData?)");
1644
+ lowerer.unsupported("SC1090", args[1], "goaway listeners whose parameters are not (errorCode, lastStreamID, opaqueData?)");
1638
1645
  }
1639
- return { kind: "libCall", fn: "http2.sessionOnGoaway", args: [receiver(), voidizedCallback(L, cb, loc), once], type: VOID, loc };
1646
+ return { kind: "libCall", fn: "http2.sessionOnGoaway", args: [receiver(), voidizedCallback(lowerer, cb, loc), once], type: VOID, loc };
1640
1647
  }
1641
- L.noLowering(`session.${name}("${event ?? "?"}", ...)`, args[0], '"close", "error", "connect", "stream", and "goaway" are the supported session events');
1648
+ lowerer.noLowering(`session.${name}("${event ?? "?"}", ...)`, args[0], '"close", "error", "connect", "stream", and "goaway" are the supported session events');
1642
1649
  }
1643
- L.noLowering(`session.${name}`, call, "close/destroy/request and on(\"close\"|\"error\"|\"connect\"|\"stream\"|\"goaway\") are the lowered session members");
1650
+ lowerer.noLowering(`session.${name}`, call, "close/destroy/request and on(\"close\"|\"error\"|\"connect\"|\"stream\"|\"goaway\") are the lowered session members");
1644
1651
  }
1645
1652
  /** Method calls on ClientHttp2Stream / ServerHttp2Stream receivers. */
1646
- function lowerH2StreamMethodCall(L, call, access, receiverOverride) {
1653
+ function lowerH2StreamMethodCall(lowerer, call, access, receiverOverride) {
1647
1654
  const compatReqStream = ts.isPropertyAccessExpression(access.expression) &&
1648
1655
  access.expression.name.text === "stream" &&
1649
- L.mapTypeOf(L.typeOf(access.expression.expression))?.kind === "httpReq";
1650
- if (L.mapTypeOf(L.typeOf(access.expression))?.kind !== "http2Stream" && !compatReqStream)
1656
+ lowerer.mapTypeOf(lowerer.typeOf(access.expression.expression))?.kind === "httpReq";
1657
+ if (lowerer.mapTypeOf(lowerer.typeOf(access.expression))?.kind !== "http2Stream" && !compatReqStream)
1651
1658
  return null;
1652
- if (!L.isStdlibMember(access) && !compatReqStream)
1659
+ if (!lowerer.isStdlibMember(access) && !compatReqStream)
1653
1660
  return null;
1654
1661
  const name = access.name.text;
1655
1662
  const loc = locOf(call);
1656
1663
  const args = call.arguments;
1657
- const receiver = () => receiverOverride ?? handleReceiver(L, access.expression, HTTP2STREAM_T);
1664
+ const receiver = () => receiverOverride ?? coerceToHandle(lowerer, access.expression, HTTP2STREAM_T);
1658
1665
  if (name === "respond") {
1659
- requireStatementPosition(L, call, "stream.respond(...)");
1666
+ requireStatementPosition(lowerer, call, "stream.respond(...)");
1660
1667
  const headersArg = args.length >= 1
1661
- ? lowerH2HeadersArg(L, args[0])
1668
+ ? lowerH2HeadersArg(lowerer, args[0])
1662
1669
  : { kind: "arrayLit", elems: [], type: arrayOf(STRING), loc };
1663
- const end = h2EndStreamOption(L, args[1]);
1670
+ const end = h2EndStreamOption(lowerer, args[1]);
1664
1671
  return { kind: "libCall", fn: "http2.streamRespond", args: [receiver(), headersArg, boolLit(end ?? false, loc)], type: VOID, loc };
1665
1672
  }
1666
1673
  if (name === "write" || name === "end") {
1667
- requireStatementPosition(L, call, `stream.${name}(...)`);
1674
+ requireStatementPosition(lowerer, call, `stream.${name}(...)`);
1668
1675
  const minArgs = name === "write" ? 1 : 0;
1669
1676
  if (args.length < minArgs || args.length > 1) {
1670
1677
  // end() with a trailing callback is common; accept (data?, cb?) by
1671
1678
  // dropping a trailing closure arg (fire-and-forget — the finish
1672
1679
  // callback is not modeled here).
1673
1680
  if (!(name === "end" && args.length === 2)) {
1674
- L.noLowering(`${name} with ${args.length} arguments`, call, `use ${name}(data${name === "write" ? "" : "?"})`);
1681
+ lowerer.noLowering(`${name} with ${args.length} arguments`, call, `use ${name}(data${name === "write" ? "" : "?"})`);
1675
1682
  }
1676
1683
  }
1677
1684
  if (args.length === 0) {
1678
1685
  return { kind: "libCall", fn: "http2.streamEnd", args: [receiver()], type: VOID, loc };
1679
1686
  }
1680
- const data = L.lowerExpr(args[0]);
1687
+ const data = lowerer.lowerExpr(args[0]);
1681
1688
  const isBytes = data.type.kind === "bytes";
1682
1689
  if (data.type.kind !== "string" && !isBytes) {
1683
- L.noLowering(`${name} with '${L.fmt(data.type)}' data`, args[0], "the chunk is a string or a Uint8Array here");
1690
+ lowerer.noLowering(`${name} with '${lowerer.fmt(data.type)}' data`, args[0], "the chunk is a string or a Uint8Array here");
1684
1691
  }
1685
1692
  const fn = name === "write"
1686
1693
  ? (isBytes ? "http2.streamWriteBytes" : "http2.streamWrite")
@@ -1688,25 +1695,25 @@ function lowerH2StreamMethodCall(L, call, access, receiverOverride) {
1688
1695
  return { kind: "libCall", fn, args: [receiver(), data], type: VOID, loc };
1689
1696
  }
1690
1697
  if (name === "close") {
1691
- requireStatementPosition(L, call, "stream.close(...)");
1692
- const code = args.length >= 1 ? L.lowerExpr(args[0]) : { kind: "numLit", value: 0, type: F64, loc };
1698
+ requireStatementPosition(lowerer, call, "stream.close(...)");
1699
+ const code = args.length >= 1 ? lowerer.lowerExpr(args[0]) : { kind: "numLit", value: 0, type: F64, loc };
1693
1700
  if (code.type.kind !== "f64") {
1694
- L.noLowering("stream.close with a non-numeric code", args[0], "the code is a number (http2.constants.NGHTTP2_*)");
1701
+ lowerer.noLowering("stream.close with a non-numeric code", args[0], "the code is a number (http2.constants.NGHTTP2_*)");
1695
1702
  }
1696
1703
  if (args.length >= 2) {
1697
- const { cb } = lowerCallbackArg(L, args[1], "close callbacks", 0, () => false, "use ()", []);
1704
+ const { cb } = lowerCallbackArg(lowerer, args[1], "close callbacks", 0, () => false, "use ()", []);
1698
1705
  return { kind: "libCall", fn: "http2.streamCloseCb", args: [receiver(), code, cb], type: VOID, loc };
1699
1706
  }
1700
1707
  return { kind: "libCall", fn: "http2.streamClose", args: [receiver(), code], type: VOID, loc };
1701
1708
  }
1702
1709
  if (name === "destroy") {
1703
- requireStatementPosition(L, call, "stream.destroy(...)");
1710
+ requireStatementPosition(lowerer, call, "stream.destroy(...)");
1704
1711
  return { kind: "libCall", fn: "http2.streamDestroy", args: [receiver()], type: VOID, loc };
1705
1712
  }
1706
1713
  if (name === "setEncoding") {
1707
- const enc = L.lowerExpr(args[0]);
1714
+ const enc = lowerer.lowerExpr(args[0]);
1708
1715
  if (enc.type.kind !== "string")
1709
- L.noLowering("setEncoding with a non-string encoding", args[0], "pass \"utf8\"");
1716
+ lowerer.noLowering("setEncoding with a non-string encoding", args[0], "pass \"utf8\"");
1710
1717
  if (ts.isExpressionStatement(call.parent) || ts.isArrowFunction(call.parent)) {
1711
1718
  return { kind: "libCall", fn: "http2.streamSetEncoding", args: [receiver(), enc], type: VOID, loc };
1712
1719
  }
@@ -1715,57 +1722,57 @@ function lowerH2StreamMethodCall(L, call, access, receiverOverride) {
1715
1722
  return { kind: "libCall", fn: "http2.streamSetEncodingRet", args: [receiver(), enc], type: HTTP2STREAM_T, loc };
1716
1723
  }
1717
1724
  if (name === "resume" || name === "pause") {
1718
- requireStatementPosition(L, call, `stream.${name}(...)`);
1725
+ requireStatementPosition(lowerer, call, `stream.${name}(...)`);
1719
1726
  return { kind: "libCall", fn: name === "resume" ? "http2.streamResume" : "http2.streamPause", args: [receiver()], type: VOID, loc };
1720
1727
  }
1721
1728
  if ((name === "on" || name === "once" || name === "addListener") && args.length === 2) {
1722
- requireStatementPosition(L, call, `stream.${name}(...)`);
1729
+ requireStatementPosition(lowerer, call, `stream.${name}(...)`);
1723
1730
  const once = boolLit(name === "once", loc);
1724
- const evT = L.typeOf(args[0]);
1731
+ const evT = lowerer.typeOf(args[0]);
1725
1732
  const event = evT.isStringLiteralType() ? evT.value : null;
1726
1733
  if (event === "data") {
1727
- const { cb } = lowerCallbackArg(L, args[1], "data listeners", 1, (p) => (p.kind === "bytes" && p.elem === "u8") || p.kind === "string" || p.kind === "dyn", "use (chunk) or ()", [BYTES_U8]);
1734
+ const { cb } = lowerCallbackArg(lowerer, args[1], "data listeners", 1, (p) => (p.kind === "bytes" && p.elem === "u8") || p.kind === "string" || p.kind === "dyn", "use (chunk) or ()", [BYTES_U8]);
1728
1735
  return { kind: "libCall", fn: "http2.streamOnData", args: [receiver(), cb, once], type: VOID, loc };
1729
1736
  }
1730
1737
  if (event === "end" || event === "close" || event === "aborted") {
1731
- const { cb } = lowerCallbackArg(L, args[1], `${event} listeners`, 0, () => false, "use ()", []);
1738
+ const { cb } = lowerCallbackArg(lowerer, args[1], `${event} listeners`, 0, () => false, "use ()", []);
1732
1739
  const fn = event === "end" ? "http2.streamOnEnd" : event === "close" ? "http2.streamOnClose" : "http2.streamOnAborted";
1733
1740
  return { kind: "libCall", fn, args: [receiver(), cb, once], type: VOID, loc };
1734
1741
  }
1735
1742
  if (event === "error") {
1736
- const { cb } = lowerCallbackArg(L, args[1], "error listeners", 1, (p) => p.kind === "object" && p.className === "%Error", "use (err) or ()", [ERROR_T]);
1743
+ const { cb } = lowerCallbackArg(lowerer, args[1], "error listeners", 1, (p) => p.kind === "object" && p.className === "%Error", "use (err) or ()", [ERROR_T]);
1737
1744
  return { kind: "libCall", fn: "http2.streamOnError", args: [receiver(), cb, once], type: VOID, loc };
1738
1745
  }
1739
1746
  if (event === "response") {
1740
- const cb = h2HeadersCallbackAdapter(L, args[1], "response listeners", null, true, loc);
1747
+ const cb = h2HeadersCallbackAdapter(lowerer, args[1], "response listeners", null, true, loc);
1741
1748
  return { kind: "libCall", fn: "http2.streamOnResponse", args: [receiver(), cb, once], type: VOID, loc };
1742
1749
  }
1743
- L.noLowering(`stream.${name}("${event ?? "?"}", ...)`, args[0], '"data", "end", "close", "aborted", "error", and "response" are the supported stream events');
1750
+ lowerer.noLowering(`stream.${name}("${event ?? "?"}", ...)`, args[0], '"data", "end", "close", "aborted", "error", and "response" are the supported stream events');
1744
1751
  }
1745
- L.noLowering(`stream.${name}`, call, "respond/write/end/close/destroy/setEncoding/resume/pause and on(...) are the lowered stream members");
1752
+ lowerer.noLowering(`stream.${name}`, call, "respond/write/end/close/destroy/setEncoding/resume/pause and on(...) are the lowered stream members");
1746
1753
  }
1747
1754
  /** A compatibility request's `req.stream?.method(...)`: the static Node
1748
1755
  * type omits the HTTP/1 undefined arm, so build the runtime guard explicitly.
1749
1756
  * The body receives the narrowed backing stream directly, preserving lazy
1750
1757
  * argument evaluation on the HTTP/1 arm. */
1751
- export function lowerCompatReqStreamOptionalCall(L, call) {
1758
+ export function lowerCompatReqStreamOptionalCall(lowerer, call) {
1752
1759
  if (!ts.isPropertyAccessExpression(call.expression) || !call.expression.questionDotToken)
1753
1760
  return null;
1754
1761
  const stream = call.expression.expression;
1755
1762
  if (!ts.isPropertyAccessExpression(stream) || stream.name.text !== "stream" ||
1756
- L.mapTypeOf(L.typeOf(stream.expression))?.kind !== "httpReq")
1763
+ lowerer.mapTypeOf(lowerer.typeOf(stream.expression))?.kind !== "httpReq")
1757
1764
  return null;
1758
1765
  const loc = locOf(call);
1759
- const unionT = { kind: "union", unionId: L.unions.intern([HTTP2STREAM_T, UNDEFINED_T]) };
1766
+ const unionT = { kind: "union", unionId: lowerer.unions.intern([HTTP2STREAM_T, UNDEFINED_T]) };
1760
1767
  const guarded = {
1761
1768
  kind: "libCall",
1762
1769
  fn: "http.reqH2Stream",
1763
- args: [handleReceiver(L, stream.expression, HTTPREQ_T)],
1770
+ args: [coerceToHandle(lowerer, stream.expression, HTTPREQ_T)],
1764
1771
  type: unionT,
1765
1772
  loc,
1766
1773
  };
1767
- const id = `chain.${L.chainCounter++}`;
1768
- const body = lowerH2StreamMethodCall(L, call, call.expression, { kind: "chainRecv", id, type: HTTP2STREAM_T, loc });
1774
+ const id = `chain.${lowerer.chainCounter++}`;
1775
+ const body = lowerH2StreamMethodCall(lowerer, call, call.expression, { kind: "chainRecv", id, type: HTTP2STREAM_T, loc });
1769
1776
  if (body === null)
1770
1777
  return null;
1771
1778
  return { kind: "optChain", id, receiver: guarded, body, type: VOID, loc };
@@ -1774,76 +1781,76 @@ export function lowerCompatReqStreamOptionalCall(L, call) {
1774
1781
  * randomBytes(n).toString(enc) precedent: the AddressInfo record between
1775
1782
  * the two reads never materializes; the runtime answers the bound port
1776
1783
  * directly. Null for every other property shape. */
1777
- export function lowerServerProperty(L, expr) {
1778
- if (expr.questionDotToken && !L.chainHandled.has(expr))
1784
+ export function lowerServerProperty(lowerer, expr) {
1785
+ if (expr.questionDotToken && !lowerer.chainHandled.has(expr))
1779
1786
  return null;
1780
1787
  const loc = locOf(expr);
1781
1788
  // req.url / req.method — always-present strings on server requests;
1782
1789
  // req.headers.NAME — the `string | undefined` union (envGet's type).
1783
- const recvKind = L.mapTypeOf(L.typeOf(expr.expression))?.kind;
1784
- if (recvKind === "netServer" && L.isStdlibMember(expr)) {
1790
+ const recvKind = lowerer.mapTypeOf(lowerer.typeOf(expr.expression))?.kind;
1791
+ if (recvKind === "netServer" && lowerer.isStdlibMember(expr)) {
1785
1792
  const field = httpServerTimeoutField(expr.name.text);
1786
1793
  if (field !== null) {
1787
- const receiver = handleReceiver(L, expr.expression, NETSERVER_T);
1794
+ const receiver = coerceToHandle(lowerer, expr.expression, NETSERVER_T);
1788
1795
  const selector = { kind: "numLit", value: field, type: F64, loc };
1789
1796
  return { kind: "libCall", fn: "http.serverTimeoutGet", args: [receiver, selector], type: F64, loc };
1790
1797
  }
1791
1798
  }
1792
- if (recvKind === "httpReq" && L.isStdlibMember(expr)) {
1799
+ if (recvKind === "httpReq" && lowerer.isStdlibMember(expr)) {
1793
1800
  const name = expr.name.text;
1794
1801
  if (name === "url" || name === "method") {
1795
- const receiver = handleReceiver(L, expr.expression, HTTPREQ_T);
1802
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPREQ_T);
1796
1803
  const fn = name === "url" ? "http.reqUrl" : "http.reqMethod";
1797
1804
  return { kind: "libCall", fn, args: [receiver], type: STRING, loc };
1798
1805
  }
1799
1806
  if (name === "statusCode") {
1800
1807
  // `number | undefined` — a real status on client responses, the
1801
1808
  // undefined arm on server requests (Node's IncomingMessage split).
1802
- const receiver = handleReceiver(L, expr.expression, HTTPREQ_T);
1803
- return { kind: "libCall", fn: "http.reqStatusCode", args: [receiver], type: L.withUndefinedArm(F64), loc };
1809
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPREQ_T);
1810
+ return { kind: "libCall", fn: "http.reqStatusCode", args: [receiver], type: lowerer.withUndefinedArm(F64), loc };
1804
1811
  }
1805
1812
  if (name === "socket") {
1806
- const receiver = handleReceiver(L, expr.expression, HTTPREQ_T);
1813
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPREQ_T);
1807
1814
  return { kind: "libCall", fn: "http.reqSocket", args: [receiver], type: NETSOCKET_T, loc };
1808
1815
  }
1809
1816
  if (name === "httpVersion") {
1810
- const receiver = handleReceiver(L, expr.expression, HTTPREQ_T);
1817
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPREQ_T);
1811
1818
  return { kind: "libCall", fn: "http.reqHttpVersion", args: [receiver], type: STRING, loc };
1812
1819
  }
1813
1820
  if (name === "httpVersionMajor" || name === "httpVersionMinor") {
1814
- const receiver = handleReceiver(L, expr.expression, HTTPREQ_T);
1821
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPREQ_T);
1815
1822
  const fn = name === "httpVersionMajor" ? "http.reqHttpVersionMajor" : "http.reqHttpVersionMinor";
1816
1823
  return { kind: "libCall", fn, args: [receiver], type: F64, loc };
1817
1824
  }
1818
1825
  if (name === "aborted" || name === "complete") {
1819
1826
  // The compat pair's flags (Http2ServerRequest); an http/1 request
1820
1827
  // answers aborted: false and complete-once-ended the same way.
1821
- const receiver = handleReceiver(L, expr.expression, HTTPREQ_T);
1828
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPREQ_T);
1822
1829
  const fn = name === "aborted" ? "http.reqAborted" : "http.reqComplete";
1823
1830
  return { kind: "libCall", fn, args: [receiver], type: BOOL, loc };
1824
1831
  }
1825
1832
  if (name === "rawHeaders") {
1826
1833
  // [name, value, name, value, ...] in arrival order, names in their
1827
1834
  // ORIGINAL case — Node's shape; a fresh string[] per read.
1828
- const receiver = handleReceiver(L, expr.expression, HTTPREQ_T);
1835
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPREQ_T);
1829
1836
  return { kind: "libCall", fn: "http.reqRawHeaders", args: [receiver], type: arrayOf(STRING), loc };
1830
1837
  }
1831
1838
  if (name === "statusMessage") {
1832
1839
  // `string | undefined` — the reason phrase on client responses (""
1833
1840
  // when the status line carried none), undefined on server requests
1834
1841
  // (the statusCode split).
1835
- const receiver = handleReceiver(L, expr.expression, HTTPREQ_T);
1836
- return { kind: "libCall", fn: "http.reqStatusMessage", args: [receiver], type: L.envValueType(), loc };
1842
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPREQ_T);
1843
+ return { kind: "libCall", fn: "http.reqStatusMessage", args: [receiver], type: lowerer.envValueType(), loc };
1837
1844
  }
1838
1845
  if (name === "stream") {
1839
1846
  const parent = expr.parent;
1840
1847
  if (ts.isPropertyAccessExpression(parent) && parent.expression === expr &&
1841
1848
  ts.isCallExpression(parent.parent) && parent.parent.expression === parent) {
1842
- const receiver = handleReceiver(L, expr.expression, HTTPREQ_T);
1849
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPREQ_T);
1843
1850
  if (parent.questionDotToken) {
1844
1851
  const type = {
1845
1852
  kind: "union",
1846
- unionId: L.unions.intern([HTTP2STREAM_T, UNDEFINED_T]),
1853
+ unionId: lowerer.unions.intern([HTTP2STREAM_T, UNDEFINED_T]),
1847
1854
  };
1848
1855
  return { kind: "libCall", fn: "http.reqH2Stream", args: [receiver], type, loc };
1849
1856
  }
@@ -1855,31 +1862,31 @@ export function lowerServerProperty(L, expr) {
1855
1862
  loc,
1856
1863
  };
1857
1864
  }
1858
- L.noLowering("reading 'stream' from a request outside a method call", expr, "call req.stream methods directly; optional calls remain undefined on HTTP/1 and use the live stream on HTTP/2");
1865
+ lowerer.noLowering("reading 'stream' from a request outside a method call", expr, "call req.stream methods directly; optional calls remain undefined on HTTP/1 and use the live stream on HTTP/2");
1859
1866
  }
1860
1867
  if (name === "session") {
1861
1868
  // Http2ServerRequest's h2-only members are not exposed through the
1862
1869
  // compatibility request handle yet. The call forms retain their
1863
1870
  // guarded-no-op / unguarded-TypeError stance; other reads fence.
1864
- L.noLowering(`reading '${name}' (an HTTP/2-only member) from a request`, expr, "compatibility requests do not expose their backing h2 stream/session yet; guarded method calls no-op and other reads have no lowering");
1871
+ lowerer.noLowering(`reading '${name}' (an HTTP/2-only member) from a request`, expr, "compatibility requests do not expose their backing h2 stream/session yet; guarded method calls no-op and other reads have no lowering");
1865
1872
  }
1866
1873
  if (name === "headers") {
1867
1874
  // `req.headers` as a VALUE — the `{ ...req.headers }` spread and
1868
1875
  // record flows: a fresh snapshot record per read (Node's spread
1869
1876
  // copies too; the per-name READS keep their direct lowerings).
1870
- const mapped = L.mapTypeOf(L.typeOf(expr));
1877
+ const mapped = lowerer.mapTypeOf(lowerer.typeOf(expr));
1871
1878
  if (mapped?.kind === "record") {
1872
- const helper = headersSnapshotHelper(L, mapped.shapeId, loc);
1879
+ const helper = headersSnapshotHelper(lowerer, mapped.shapeId, loc);
1873
1880
  if (helper !== null) {
1874
- const receiver = handleReceiver(L, expr.expression, HTTPREQ_T);
1881
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPREQ_T);
1875
1882
  return { kind: "call", callee: helper, args: [receiver], type: mapped, loc };
1876
1883
  }
1877
1884
  }
1878
- L.unsupported("SC1090", expr, "req.headers as a value of this type (read one header: req.headers.name or req.headers[name])");
1885
+ lowerer.unsupported("SC1090", expr, "req.headers as a value of this type (read one header: req.headers.name or req.headers[name])");
1879
1886
  }
1880
1887
  }
1881
- if (recvKind === "httpRes" && L.isStdlibMember(expr) && expr.name.text === "stream") {
1882
- L.noLowering("reading 'stream' (an HTTP/2-only member) from a response", expr, "compatibility responses do not expose their backing h2 stream yet — guard method calls with '?.' or drop the use");
1888
+ if (recvKind === "httpRes" && lowerer.isStdlibMember(expr) && expr.name.text === "stream") {
1889
+ lowerer.noLowering("reading 'stream' (an HTTP/2-only member) from a response", expr, "compatibility responses do not expose their backing h2 stream yet — guard method calls with '?.' or drop the use");
1883
1890
  }
1884
1891
  if (recvKind === "netSocket" && expr.name.text === "encrypted") {
1885
1892
  // `boolean | undefined` — Node types `encrypted` on TLSSocket only
@@ -1890,85 +1897,85 @@ export function lowerServerProperty(L, expr) {
1890
1897
  // stdlib-provenance check deliberately does not apply: the receiver
1891
1898
  // KIND is a real socket either way, and `encrypted` on a socket has
1892
1899
  // exactly one meaning.
1893
- const receiver = handleReceiver(L, expr.expression, NETSOCKET_T);
1894
- return { kind: "libCall", fn: "net.sockEncrypted", args: [receiver], type: L.withUndefinedArm(BOOL), loc };
1900
+ const receiver = coerceToHandle(lowerer, expr.expression, NETSOCKET_T);
1901
+ return { kind: "libCall", fn: "net.sockEncrypted", args: [receiver], type: lowerer.withUndefinedArm(BOOL), loc };
1895
1902
  }
1896
1903
  if (recvKind === "netSocket" && expr.name.text === "authorized") {
1897
1904
  // TLSSocket.authorized — Node's verify verdict (false on plain
1898
1905
  // sockets, servers without requestCert, and unverified clients).
1899
1906
  // Like `encrypted`, no stdlib-provenance gate: the member has exactly
1900
1907
  // one meaning on a socket-kind receiver.
1901
- const receiver = handleReceiver(L, expr.expression, NETSOCKET_T);
1908
+ const receiver = coerceToHandle(lowerer, expr.expression, NETSOCKET_T);
1902
1909
  return { kind: "libCall", fn: "tls.sockAuthorized", args: [receiver], type: BOOL, loc };
1903
1910
  }
1904
1911
  if (recvKind === "netSocket" && expr.name.text === "authorizationError") {
1905
1912
  // TLSSocket.authorizationError — the verify-failure CODE STRING
1906
1913
  // (DEPTH_ZERO_SELF_SIGNED_CERT, ...) or null when authorized/never
1907
1914
  // verified: Node's exact value shape (a string, not an Error).
1908
- const receiver = handleReceiver(L, expr.expression, NETSOCKET_T);
1909
- const type = { kind: "union", unionId: L.unions.intern([STRING, NULL_T]) };
1915
+ const receiver = coerceToHandle(lowerer, expr.expression, NETSOCKET_T);
1916
+ const type = { kind: "union", unionId: lowerer.unions.intern([STRING, NULL_T]) };
1910
1917
  return { kind: "libCall", fn: "tls.sockAuthError", args: [receiver], type, loc };
1911
1918
  }
1912
- if (recvKind === "netSocket" && L.isStdlibMember(expr) && expr.name.text === "destroyed") {
1919
+ if (recvKind === "netSocket" && lowerer.isStdlibMember(expr) && expr.name.text === "destroyed") {
1913
1920
  // true once the fd is gone (destroy() or full close) — Node's flag,
1914
1921
  // the proxy's re-entrant teardown guard.
1915
- const receiver = handleReceiver(L, expr.expression, NETSOCKET_T);
1922
+ const receiver = coerceToHandle(lowerer, expr.expression, NETSOCKET_T);
1916
1923
  return { kind: "libCall", fn: "net.sockDestroyed", args: [receiver], type: BOOL, loc };
1917
1924
  }
1918
- if (recvKind === "netSocket" && L.isStdlibMember(expr) && expr.name.text === "writable") {
1925
+ if (recvKind === "netSocket" && lowerer.isStdlibMember(expr) && expr.name.text === "writable") {
1919
1926
  // Node's stream answer: the write half is open — no end() yet, no FIN
1920
1927
  // sent, fd alive (connecting sockets answer true; writes queue). The
1921
1928
  // proxy's "may I still answer 502" guard.
1922
- const receiver = handleReceiver(L, expr.expression, NETSOCKET_T);
1929
+ const receiver = coerceToHandle(lowerer, expr.expression, NETSOCKET_T);
1923
1930
  return { kind: "libCall", fn: "net.sockWritable", args: [receiver], type: BOOL, loc };
1924
1931
  }
1925
- if (recvKind === "netSocket" && L.isStdlibMember(expr) && expr.name.text === "bytesWritten") {
1932
+ if (recvKind === "netSocket" && lowerer.isStdlibMember(expr) && expr.name.text === "bytesWritten") {
1926
1933
  // Every byte the write paths accepted (buffered included — Node
1927
1934
  // counts those too; plaintext on TLS sockets).
1928
- const receiver = handleReceiver(L, expr.expression, NETSOCKET_T);
1935
+ const receiver = coerceToHandle(lowerer, expr.expression, NETSOCKET_T);
1929
1936
  return { kind: "libCall", fn: "net.sockBytesWritten", args: [receiver], type: F64, loc };
1930
1937
  }
1931
- if (recvKind === "netSocket" && L.isStdlibMember(expr) && expr.name.text === "readable") {
1938
+ if (recvKind === "netSocket" && lowerer.isStdlibMember(expr) && expr.name.text === "readable") {
1932
1939
  // true until the read half is done (peer FIN / destroy).
1933
- const receiver = handleReceiver(L, expr.expression, NETSOCKET_T);
1940
+ const receiver = coerceToHandle(lowerer, expr.expression, NETSOCKET_T);
1934
1941
  return { kind: "libCall", fn: "net.sockReadable", args: [receiver], type: BOOL, loc };
1935
1942
  }
1936
- if (recvKind === "netSocket" && L.isStdlibMember(expr) && expr.name.text === "remoteAddress") {
1943
+ if (recvKind === "netSocket" && lowerer.isStdlibMember(expr) && expr.name.text === "remoteAddress") {
1937
1944
  // `string | undefined` — Node's read-time caching: a value read while
1938
1945
  // connected survives destroy; never-read sockets answer undefined
1939
1946
  // after close.
1940
- const receiver = handleReceiver(L, expr.expression, NETSOCKET_T);
1941
- return { kind: "libCall", fn: "net.sockRemoteAddress", args: [receiver], type: L.envValueType(), loc };
1947
+ const receiver = coerceToHandle(lowerer, expr.expression, NETSOCKET_T);
1948
+ return { kind: "libCall", fn: "net.sockRemoteAddress", args: [receiver], type: lowerer.envValueType(), loc };
1942
1949
  }
1943
- if (recvKind === "httpClientReq" && L.isStdlibMember(expr) && expr.name.text === "destroyed") {
1944
- const receiver = handleReceiver(L, expr.expression, HTTPCLIENTREQ_T);
1950
+ if (recvKind === "httpClientReq" && lowerer.isStdlibMember(expr) && expr.name.text === "destroyed") {
1951
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPCLIENTREQ_T);
1945
1952
  return { kind: "libCall", fn: "http.clientDestroyed", args: [receiver], type: BOOL, loc };
1946
1953
  }
1947
- if (isHttpReqHeaders(L, expr.expression)) {
1948
- const receiver = handleReceiver(L, expr.expression.expression, HTTPREQ_T);
1954
+ if (isHttpReqHeaders(lowerer, expr.expression)) {
1955
+ const receiver = coerceToHandle(lowerer, expr.expression.expression, HTTPREQ_T);
1949
1956
  const key = { kind: "strLit", value: expr.name.text, type: STRING, loc };
1950
- return { kind: "libCall", fn: "http.reqHeader", args: [receiver, key], type: L.envValueType(), loc };
1957
+ return { kind: "libCall", fn: "http.reqHeader", args: [receiver, key], type: lowerer.envValueType(), loc };
1951
1958
  }
1952
- if (recvKind === "httpRes" && L.isStdlibMember(expr) && expr.name.text === "headersSent") {
1953
- const receiver = handleReceiver(L, expr.expression, HTTPRES_T);
1959
+ if (recvKind === "httpRes" && lowerer.isStdlibMember(expr) && expr.name.text === "headersSent") {
1960
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPRES_T);
1954
1961
  return { kind: "libCall", fn: "http.resHeadersSent", args: [receiver], type: BOOL, loc };
1955
1962
  }
1956
- if (recvKind === "httpRes" && L.isStdlibMember(expr) && expr.name.text === "statusCode") {
1963
+ if (recvKind === "httpRes" && lowerer.isStdlibMember(expr) && expr.name.text === "statusCode") {
1957
1964
  // 200 until assigned — Node's fresh-response default; the assignment
1958
1965
  // twin lives in lowerHttpResPropertyAssignment.
1959
- const receiver = handleReceiver(L, expr.expression, HTTPRES_T);
1966
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPRES_T);
1960
1967
  return { kind: "libCall", fn: "http.resStatusGet", args: [receiver], type: F64, loc };
1961
1968
  }
1962
- if (recvKind === "httpRes" && L.isStdlibMember(expr) && expr.name.text === "statusMessage") {
1969
+ if (recvKind === "httpRes" && lowerer.isStdlibMember(expr) && expr.name.text === "statusMessage") {
1963
1970
  // The assigned reason phrase, or the current status code's default
1964
1971
  // when none was set (Node answers undefined until the head goes out
1965
1972
  // — divergence: this surface is string-typed, the checker's shape).
1966
- const receiver = handleReceiver(L, expr.expression, HTTPRES_T);
1973
+ const receiver = coerceToHandle(lowerer, expr.expression, HTTPRES_T);
1967
1974
  return { kind: "libCall", fn: "http.resStatusMsgGet", args: [receiver], type: STRING, loc };
1968
1975
  }
1969
- if (recvKind === "http2Session" && L.isStdlibMember(expr)) {
1976
+ if (recvKind === "http2Session" && lowerer.isStdlibMember(expr)) {
1970
1977
  const m = expr.name.text;
1971
- const recv = () => handleReceiver(L, expr.expression, HTTP2SESSION_T);
1978
+ const recv = () => coerceToHandle(lowerer, expr.expression, HTTP2SESSION_T);
1972
1979
  if (m === "closed")
1973
1980
  return { kind: "libCall", fn: "http2.sessionClosed", args: [recv()], type: BOOL, loc };
1974
1981
  if (m === "destroyed")
@@ -1992,9 +1999,9 @@ export function lowerServerProperty(L, expr) {
1992
1999
  };
1993
2000
  }
1994
2001
  }
1995
- if (recvKind === "http2Stream" && L.isStdlibMember(expr)) {
2002
+ if (recvKind === "http2Stream" && lowerer.isStdlibMember(expr)) {
1996
2003
  const m = expr.name.text;
1997
- const recv = () => handleReceiver(L, expr.expression, HTTP2STREAM_T);
2004
+ const recv = () => coerceToHandle(lowerer, expr.expression, HTTP2STREAM_T);
1998
2005
  if (m === "id")
1999
2006
  return { kind: "libCall", fn: "http2.streamId", args: [recv()], type: F64, loc };
2000
2007
  if (m === "rstCode")
@@ -2020,11 +2027,11 @@ export function lowerServerProperty(L, expr) {
2020
2027
  const inner = recv.expression;
2021
2028
  if (inner.name.text !== "address" || inner.questionDotToken)
2022
2029
  return null;
2023
- if (L.mapTypeOf(L.typeOf(inner.expression))?.kind !== "netServer")
2030
+ if (lowerer.mapTypeOf(lowerer.typeOf(inner.expression))?.kind !== "netServer")
2024
2031
  return null;
2025
- if (!L.isStdlibMember(inner))
2032
+ if (!lowerer.isStdlibMember(inner))
2026
2033
  return null;
2027
- const receiver = handleReceiver(L, inner.expression, NETSERVER_T);
2034
+ const receiver = coerceToHandle(lowerer, inner.expression, NETSERVER_T);
2028
2035
  return { kind: "libCall", fn: "net.serverPort", args: [receiver], type: F64, loc };
2029
2036
  }
2030
2037
  /** The (req, res) request-handler argument — http.createServer's, https
@@ -2033,8 +2040,8 @@ export function lowerServerProperty(L, expr) {
2033
2040
  * A value-returning handler adapts through the cast-and-discard helper
2034
2041
  * (Node ignores handler results — the writeHead-chaining body
2035
2042
  * `(req, res) => res.writeHead(200).end()` is the motivating shape). */
2036
- function lowerRequestHandlerArg(L, node) {
2037
- const cb = L.lowerExpr(node);
2043
+ function lowerRequestHandlerArg(lowerer, node) {
2044
+ const cb = lowerer.lowerExpr(node);
2038
2045
  if (cb.type.kind === "dyn") {
2039
2046
  // A CHECKED-DYNAMIC handler (test/common's mustCall wrapper around
2040
2047
  // the (req, res) listener — the canonical suite shape): adapt
@@ -2048,7 +2055,7 @@ function lowerRequestHandlerArg(L, node) {
2048
2055
  if (cb.type.kind === "func" &&
2049
2056
  (cb.type.rest === true ||
2050
2057
  (cb.type.params.length > 0 && cb.type.params.every((p) => p.kind === "dyn"))) &&
2051
- canBoxFuncIntoDyn(cb.type, (id) => L.shapes.get(id), (id) => L.unions.get(id))) {
2058
+ canBoxFuncIntoDyn(cb.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
2052
2059
  // A hoisted plain-JS handler (`http.createServer(handle)` where
2053
2060
  // `function handle(req, res)` has no contextual type — dyn params),
2054
2061
  // or an arguments-reading rest function: box it and adapt exactly
@@ -2058,13 +2065,13 @@ function lowerRequestHandlerArg(L, node) {
2058
2065
  return { kind: "dynCheck", value: boxed, type: funcOf([HTTPREQ_T, HTTPRES_T], VOID), loc: locOf(node) };
2059
2066
  }
2060
2067
  if (cb.type.kind !== "func" || cb.type.params.length > 2) {
2061
- L.unsupported("SC1090", node, "request handlers with more than two parameters (use (req, res))");
2068
+ lowerer.unsupported("SC1090", node, "request handlers with more than two parameters (use (req, res))");
2062
2069
  }
2063
2070
  const [p0, p1] = cb.type.params;
2064
2071
  if ((p0 !== undefined && p0.kind !== "httpReq") || (p1 !== undefined && p1.kind !== "httpRes")) {
2065
- L.unsupported("SC1090", node, "request handlers whose parameters are not (req: IncomingMessage, res: ServerResponse)");
2072
+ lowerer.unsupported("SC1090", node, "request handlers whose parameters are not (req: IncomingMessage, res: ServerResponse)");
2066
2073
  }
2067
- return voidizedCallback(L, cb, locOf(node));
2074
+ return voidizedCallback(lowerer, cb, locOf(node));
2068
2075
  }
2069
2076
  /** The http.createServer / http.Server options object — { requireHostHeader?,
2070
2077
  * joinDuplicateHeaders?, keepAliveTimeoutBuffer?, ... }. The first two
@@ -2072,9 +2079,9 @@ function lowerRequestHandlerArg(L, node) {
2072
2079
  * writable server field after Node's non-negative-safe-integer validation.
2073
2080
  * Other documented keys fence by name; unknown keys drop like Node drops
2074
2081
  * them. */
2075
- function lowerHttpServerOptions(L, node, what) {
2082
+ function lowerHttpServerOptions(lowerer, node, what) {
2076
2083
  if (!ts.isObjectLiteralExpression(node)) {
2077
- L.noLowering(`${what} with a non-literal options argument`, node, "pass the options as an object literal: { requireHostHeader?, joinDuplicateHeaders? }");
2084
+ lowerer.noLowering(`${what} with a non-literal options argument`, node, "pass the options as an object literal: { requireHostHeader?, joinDuplicateHeaders? }");
2078
2085
  }
2079
2086
  let joinDup = false;
2080
2087
  let keepAliveTimeoutBuffer = null;
@@ -2088,7 +2095,7 @@ function lowerHttpServerOptions(L, node, what) {
2088
2095
  initializer = null;
2089
2096
  }
2090
2097
  else {
2091
- L.noLowering(`${what} options with computed keys or spreads`, prop, "each option must be a plain `name: value` (or shorthand) entry with a literal key");
2098
+ lowerer.noLowering(`${what} options with computed keys or spreads`, prop, "each option must be a plain `name: value` (or shorthand) entry with a literal key");
2092
2099
  }
2093
2100
  const key = prop.name.text;
2094
2101
  if (key === "requireHostHeader") {
@@ -2097,7 +2104,7 @@ function lowerHttpServerOptions(L, node, what) {
2097
2104
  // (true: answer 400) is the behavior this slice does not have, so
2098
2105
  // `true`/dynamic values fence instead of silently not enforcing.
2099
2106
  if (initializer === null || initializer.kind !== ts.SyntaxKind.FalseKeyword) {
2100
- L.noLowering(`${what} with a non-\`false\` requireHostHeader option`, prop, "this parser never answers 400 for a missing Host header — requireHostHeader: false is the honest (and only) lowered value");
2107
+ lowerer.noLowering(`${what} with a non-\`false\` requireHostHeader option`, prop, "this parser never answers 400 for a missing Host header — requireHostHeader: false is the honest (and only) lowered value");
2101
2108
  }
2102
2109
  continue;
2103
2110
  }
@@ -2111,18 +2118,18 @@ function lowerHttpServerOptions(L, node, what) {
2111
2118
  if (initializer !== null && initializer.kind === ts.SyntaxKind.FalseKeyword) {
2112
2119
  continue; /* Node's default: repeats keep the first value */
2113
2120
  }
2114
- L.noLowering(`${what} with a non-literal joinDuplicateHeaders option`, prop, "the lowered forms are the literals joinDuplicateHeaders: true (repeats join \", \") and false (the keep-first default)");
2121
+ lowerer.noLowering(`${what} with a non-literal joinDuplicateHeaders option`, prop, "the lowered forms are the literals joinDuplicateHeaders: true (repeats join \", \") and false (the keep-first default)");
2115
2122
  }
2116
2123
  if (key === "keepAliveTimeoutBuffer") {
2117
2124
  if (keepAliveTimeoutBuffer !== null) {
2118
- L.noLowering(`${what} with duplicate keepAliveTimeoutBuffer options`, prop, "write keepAliveTimeoutBuffer once in the options literal");
2125
+ lowerer.noLowering(`${what} with duplicate keepAliveTimeoutBuffer options`, prop, "write keepAliveTimeoutBuffer once in the options literal");
2119
2126
  }
2120
2127
  const raw = initializer !== null
2121
- ? L.lowerExpr(initializer)
2122
- : L.lowerShorthandValue(prop);
2123
- const value = L.coerceToExpected(raw, DYN);
2128
+ ? lowerer.lowerExpr(initializer)
2129
+ : lowerer.lowerShorthandValue(prop);
2130
+ const value = lowerer.coerceToExpected(raw, DYN);
2124
2131
  if (value.type.kind !== "dyn") {
2125
- L.noLowering(`${what} with a keepAliveTimeoutBuffer value that cannot cross the runtime option boundary`, prop, "keepAliveTimeoutBuffer is a number or undefined");
2132
+ lowerer.noLowering(`${what} with a keepAliveTimeoutBuffer value that cannot cross the runtime option boundary`, prop, "keepAliveTimeoutBuffer is a number or undefined");
2126
2133
  }
2127
2134
  // Preserve the optional field's undefined arm until runtime: Node
2128
2135
  // treats it as absent, while numbers take the constructor-only
@@ -2132,7 +2139,7 @@ function lowerHttpServerOptions(L, node, what) {
2132
2139
  keepAliveTimeoutBuffer = value;
2133
2140
  continue;
2134
2141
  }
2135
- fenceOrDropOptionKey(L, prop, key, what, HTTP_SERVER_DOCUMENTED_OPTIONS, "requireHostHeader: false, joinDuplicateHeaders, and keepAliveTimeoutBuffer are the supported options");
2142
+ fenceOrDropOptionKey(lowerer, prop, key, what, HTTP_SERVER_DOCUMENTED_OPTIONS, "requireHostHeader: false, joinDuplicateHeaders, and keepAliveTimeoutBuffer are the supported options");
2136
2143
  // An undocumented key, dropped like Node drops it.
2137
2144
  }
2138
2145
  return { joinDup, keepAliveTimeoutBuffer };
@@ -2142,10 +2149,10 @@ function lowerHttpServerOptions(L, node, what) {
2142
2149
  * (the on("request") route), a lone handler, a lone options object, and
2143
2150
  * (options, handler). Modeled option values wrap the construction in an
2144
2151
  * interned option-setting helper. */
2145
- function lowerHttpCreateServerForms(L, expr, what, loc) {
2152
+ function lowerHttpCreateServerForms(lowerer, expr, what, loc) {
2146
2153
  const args = expr.arguments ?? [];
2147
2154
  if (args.length > 2) {
2148
- L.noLowering(`${what} with ${args.length} arguments`, expr, `the supported forms are ${what}([options][, (req, res) => ...])`);
2155
+ lowerer.noLowering(`${what} with ${args.length} arguments`, expr, `the supported forms are ${what}([options][, (req, res) => ...])`);
2149
2156
  }
2150
2157
  let optsNode = null;
2151
2158
  let handlerNode = null;
@@ -2160,10 +2167,10 @@ function lowerHttpCreateServerForms(L, expr, what, loc) {
2160
2167
  handlerNode = args[0];
2161
2168
  }
2162
2169
  const opts = optsNode !== null
2163
- ? lowerHttpServerOptions(L, optsNode, what)
2170
+ ? lowerHttpServerOptions(lowerer, optsNode, what)
2164
2171
  : { joinDup: false, keepAliveTimeoutBuffer: null };
2165
2172
  const server = handlerNode !== null
2166
- ? { kind: "libCall", fn: "http.createServer", args: [lowerRequestHandlerArg(L, handlerNode)], type: NETSERVER_T, loc }
2173
+ ? { kind: "libCall", fn: "http.createServer", args: [lowerRequestHandlerArg(lowerer, handlerNode)], type: NETSERVER_T, loc }
2167
2174
  : { kind: "libCall", fn: "http.createServerEmpty", args: [], type: NETSERVER_T, loc };
2168
2175
  if (!opts.joinDup && opts.keepAliveTimeoutBuffer === null)
2169
2176
  return server;
@@ -2173,10 +2180,10 @@ function lowerHttpCreateServerForms(L, expr, what, loc) {
2173
2180
  // the server as the constructor/factory result.
2174
2181
  const hasBuffer = opts.keepAliveTimeoutBuffer !== null;
2175
2182
  const key = `server.opts:${opts.joinDup ? 1 : 0}:${hasBuffer ? 1 : 0}`;
2176
- const existing = L.arrHofHelpers.get(key);
2177
- const name = existing ?? `%server.opts.${L.arrHofHelpers.size}`;
2183
+ const existing = lowerer.arrHofHelpers.get(key);
2184
+ const name = existing ?? `%server.opts.${lowerer.arrHofHelpers.size}`;
2178
2185
  if (!existing) {
2179
- L.arrHofHelpers.set(key, name);
2186
+ lowerer.arrHofHelpers.set(key, name);
2180
2187
  const params = [
2181
2188
  ...(hasBuffer ? [{ localId: "b.0", name: "buffer", type: DYN }] : []),
2182
2189
  { localId: "s.0", name: "s", type: NETSERVER_T },
@@ -2200,7 +2207,7 @@ function lowerHttpCreateServerForms(L, expr, what, loc) {
2200
2207
  });
2201
2208
  }
2202
2209
  body.push({ kind: "return", value: ref, loc });
2203
- L.liftedFns.push({
2210
+ lowerer.liftedFns.push({
2204
2211
  name,
2205
2212
  params,
2206
2213
  returnType: NETSERVER_T,
@@ -2232,37 +2239,35 @@ function lowerHttpCreateServerForms(L, expr, what, loc) {
2232
2239
  * DROPS (no free pool exists, so selection order cannot observe), other
2233
2240
  * documented keys fence by name, and undocumented keys drop like Node
2234
2241
  * drops them. Null when the callee isn't the http/https Agent. */
2235
- export function lowerHttpAgentNew(L, expr) {
2242
+ export function lowerHttpAgentNew(lowerer, expr) {
2236
2243
  const callee = expr.expression;
2237
2244
  const bi = ts.isPropertyAccessExpression(callee) && callee.name.text === "Agent"
2238
- ? L.builtinMemberOf(callee)
2245
+ ? lowerer.builtinMemberOf(callee)
2239
2246
  : ts.isIdentifier(callee)
2240
- ? L.builtinImportOf(callee)
2247
+ ? lowerer.builtinImportOf(callee)
2241
2248
  : null;
2242
2249
  if (!bi || bi.member !== "Agent" || (bi.module !== "http" && bi.module !== "https"))
2243
2250
  return null;
2244
2251
  const loc = locOf(expr);
2245
2252
  const api = `new ${bi.module}.Agent`;
2246
- const numLit = (value) => ({ kind: "numLit", value, type: F64, loc });
2247
- const boolAt = (value) => ({ kind: "boolLit", value, type: BOOL, loc });
2248
- let keepAlive = boolAt(false);
2249
- let kaMsecs = numLit(-1);
2250
- let maxSockets = numLit(-1);
2251
- let maxFree = numLit(-1);
2252
- let timeout = numLit(-1);
2253
- let port = numLit(-1);
2253
+ let keepAlive = boolLit(false, loc);
2254
+ let kaMsecs = numLit(-1, loc);
2255
+ let maxSockets = numLit(-1, loc);
2256
+ let maxFree = numLit(-1, loc);
2257
+ let timeout = numLit(-1, loc);
2258
+ let port = numLit(-1, loc);
2254
2259
  const args = expr.arguments ?? [];
2255
2260
  if (args.length > 1) {
2256
- L.noLowering(`${api} with ${args.length} arguments`, expr, "the supported form is new Agent(options?)");
2261
+ lowerer.noLowering(`${api} with ${args.length} arguments`, expr, "the supported form is new Agent(options?)");
2257
2262
  }
2258
2263
  if (args.length === 1) {
2259
2264
  const optsNode = stripParensAndCasts(args[0]);
2260
2265
  if (!ts.isObjectLiteralExpression(optsNode)) {
2261
- L.noLowering(`${api} with a non-literal options value`, args[0], "spell the options as an object literal at the construction site");
2266
+ lowerer.noLowering(`${api} with a non-literal options value`, args[0], "spell the options as an object literal at the construction site");
2262
2267
  }
2263
2268
  for (const prop of optsNode.properties) {
2264
2269
  if (ts.isSpreadAssignment(prop)) {
2265
- L.noLowering(`${api} with an options spread`, prop, "write each option inline");
2270
+ lowerer.noLowering(`${api} with an options spread`, prop, "write each option inline");
2266
2271
  }
2267
2272
  let initializer;
2268
2273
  if (ts.isPropertyAssignment(prop) &&
@@ -2273,18 +2278,18 @@ export function lowerHttpAgentNew(L, expr) {
2273
2278
  initializer = null;
2274
2279
  }
2275
2280
  else {
2276
- L.noLowering(`${api} options with computed keys`, prop, "each option must be a plain `name: value` (or shorthand) entry with a literal key");
2281
+ lowerer.noLowering(`${api} options with computed keys`, prop, "each option must be a plain `name: value` (or shorthand) entry with a literal key");
2277
2282
  }
2278
2283
  const key = prop.name.text;
2279
2284
  const lowerVal = (want) => {
2280
2285
  const v = initializer !== null
2281
- ? L.lowerExpr(initializer)
2282
- : L.lowerShorthandValue(prop);
2286
+ ? lowerer.lowerExpr(initializer)
2287
+ : lowerer.lowerShorthandValue(prop);
2283
2288
  if (v.type.kind === "dyn") {
2284
2289
  return { kind: "dynCheck", value: v, type: want === "bool" ? BOOL : F64, loc: locOf(prop) };
2285
2290
  }
2286
2291
  if (v.type.kind !== want) {
2287
- L.noLowering(`a ${api} '${key}' option of '${L.fmt(v.type)}' values`, prop, want === "bool" ? "the option value must be a boolean" : "the option value must be a number");
2292
+ lowerer.noLowering(`a ${api} '${key}' option of '${lowerer.fmt(v.type)}' values`, prop, want === "bool" ? "the option value must be a boolean" : "the option value must be a number");
2288
2293
  }
2289
2294
  return v;
2290
2295
  };
@@ -2313,46 +2318,46 @@ export function lowerHttpAgentNew(L, expr) {
2313
2318
  // Free-socket selection order: no free pool exists here (no
2314
2319
  // keep-alive reuse), so the choice cannot observe — dropped.
2315
2320
  if (initializer !== null)
2316
- L.lowerExpr(initializer); // evaluate, like Node
2321
+ lowerer.lowerExpr(initializer); // evaluate, like Node
2317
2322
  break;
2318
2323
  default:
2319
- fenceOrDropOptionKey(L, prop, key, api, AGENT_DOCUMENTED_OPTIONS, "keepAlive, keepAliveMsecs, maxSockets, maxFreeSockets, timeout, port, and scheduling are the supported options");
2324
+ fenceOrDropOptionKey(lowerer, prop, key, api, AGENT_DOCUMENTED_OPTIONS, "keepAlive, keepAliveMsecs, maxSockets, maxFreeSockets, timeout, port, and scheduling are the supported options");
2320
2325
  }
2321
2326
  }
2322
2327
  }
2323
2328
  return {
2324
2329
  kind: "libCall",
2325
2330
  fn: "http.agentNew",
2326
- args: [boolAt(bi.module === "https"), keepAlive, kaMsecs, maxSockets, maxFree, timeout, port],
2331
+ args: [boolLit(bi.module === "https", loc), keepAlive, kaMsecs, maxSockets, maxFree, timeout, port],
2327
2332
  type: DYN,
2328
2333
  loc,
2329
2334
  };
2330
2335
  }
2331
- export function lowerHttpServerNew(L, expr) {
2336
+ export function lowerHttpServerNew(lowerer, expr) {
2332
2337
  const callee = expr.expression;
2333
2338
  const isHttpServer = (ts.isPropertyAccessExpression(callee) &&
2334
2339
  callee.name.text === "Server" &&
2335
- L.builtinMemberOf(callee)?.module === "http") ||
2340
+ lowerer.builtinMemberOf(callee)?.module === "http") ||
2336
2341
  (ts.isIdentifier(callee) &&
2337
- L.builtinImportOf(callee)?.module === "http" &&
2338
- L.builtinImportOf(callee)?.member === "Server");
2342
+ lowerer.builtinImportOf(callee)?.module === "http" &&
2343
+ lowerer.builtinImportOf(callee)?.member === "Server");
2339
2344
  if (!isHttpServer)
2340
2345
  return null;
2341
- return lowerHttpCreateServerForms(L, expr, "new http.Server", locOf(expr));
2346
+ return lowerHttpCreateServerForms(lowerer, expr, "new http.Server", locOf(expr));
2342
2347
  }
2343
2348
  /** Module-function calls on http import bindings: createServer([options][,
2344
2349
  * handler]) and the call-form Server (Node's constructor works without
2345
2350
  * `new` — test/parallel's http.Server(fn) spelling). The handler takes
2346
2351
  * (req, res), (req), or () — runtime adapters bridge each shape.
2347
2352
  * Everything else the module declares fences qualified. */
2348
- function lowerHttpModuleCall(L, expr, bi, loc) {
2353
+ function lowerHttpModuleCall(lowerer, expr, bi, loc) {
2349
2354
  if (bi.member === "createServer" || bi.member === "Server") {
2350
- return lowerHttpCreateServerForms(L, expr, `http.${bi.member}`, loc);
2355
+ return lowerHttpCreateServerForms(lowerer, expr, `http.${bi.member}`, loc);
2351
2356
  }
2352
2357
  if (bi.member === "request" || bi.member === "get") {
2353
- return lowerHttpClientCall(L, expr, bi.member, loc);
2358
+ return lowerHttpClientCall(lowerer, expr, bi.member, loc);
2354
2359
  }
2355
- L.noLowering(`http.${bi.member}`, expr, "createServer, Server, request, and get are the lowered http module functions", L.resolveValueSymbol(expr.expression));
2360
+ lowerer.noLowering(`http.${bi.member}`, expr, "createServer, Server, request, and get are the lowered http module functions", lowerer.resolveValueSymbol(expr.expression));
2356
2361
  }
2357
2362
  /** The cert/key PEM option of tls.createServer / https.createServer: an
2358
2363
  * OBJECT LITERAL whose lowered `cert` and `key` entries are strings or
@@ -2360,9 +2365,9 @@ function lowerHttpModuleCall(L, expr, bi, loc) {
2360
2365
  * runtime-valued (dyn) entry rides the tls.pemDyn extraction, throwing
2361
2366
  * the fence at runtime for non-PEM kinds (the divergence-66 stance).
2362
2367
  * Every other key fences by name; SNICallback gets the pointed hint. */
2363
- function lowerTlsServerOptions(L, node, what) {
2368
+ function lowerTlsServerOptions(lowerer, node, what) {
2364
2369
  if (!ts.isObjectLiteralExpression(node)) {
2365
- L.noLowering(`${what} with a non-literal options argument`, node, "pass the options as an object literal: { cert, key }");
2370
+ lowerer.noLowering(`${what} with a non-literal options argument`, node, "pass the options as an object literal: { cert, key }");
2366
2371
  }
2367
2372
  const loc = locOf(node);
2368
2373
  let cert = null;
@@ -2377,7 +2382,7 @@ function lowerTlsServerOptions(L, node, what) {
2377
2382
  initializer = null;
2378
2383
  }
2379
2384
  else {
2380
- L.noLowering(`${what} options with computed keys or spreads`, prop, "each option must be a plain `name: value` (or shorthand) entry with a literal key");
2385
+ lowerer.noLowering(`${what} options with computed keys or spreads`, prop, "each option must be a plain `name: value` (or shorthand) entry with a literal key");
2381
2386
  }
2382
2387
  const k = prop.name.text;
2383
2388
  if (k !== "cert" && k !== "key") {
@@ -2394,15 +2399,15 @@ function lowerTlsServerOptions(L, node, what) {
2394
2399
  (init === null || init.kind === ts.SyntaxKind.FalseKeyword)) {
2395
2400
  continue; // Node's false default, spelled out
2396
2401
  }
2397
- fenceOrDropOptionKey(L, prop, k, what, TLS_SERVER_DOCUMENTED_OPTIONS, "cert and key (PEM strings or Buffers) are the supported options", {
2402
+ fenceOrDropOptionKey(lowerer, prop, k, what, TLS_SERVER_DOCUMENTED_OPTIONS, "cert and key (PEM strings or Buffers) are the supported options", {
2398
2403
  SNICallback: "SNICallback lowers only on http2.createSecureServer({ allowHTTP1: true, ... }) — serve one cert/key pair here",
2399
2404
  requestCert: "client-certificate handshakes are not modeled (SEMANTICS.md divergence 55) — requestCert: false is the lowered value",
2400
2405
  });
2401
2406
  continue; // an undocumented key, dropped like Node drops it
2402
2407
  }
2403
2408
  let v = initializer !== null
2404
- ? L.lowerExpr(initializer)
2405
- : L.lowerShorthandValue(prop);
2409
+ ? lowerer.lowerExpr(initializer)
2410
+ : lowerer.lowerShorthandValue(prop);
2406
2411
  const isArrayOfPem = v.type.kind === "array" &&
2407
2412
  (v.type.elem.kind === "string" || (v.type.elem.kind === "bytes" && v.type.elem.elem === "u8"));
2408
2413
  if (v.type.kind === "dyn" || isArrayOfPem) {
@@ -2422,7 +2427,7 @@ function lowerTlsServerOptions(L, node, what) {
2422
2427
  };
2423
2428
  }
2424
2429
  else if (v.type.kind !== "string" && !(v.type.kind === "bytes" && v.type.elem === "u8")) {
2425
- L.noLowering(`a ${what} '${k}' option of '${L.fmt(v.type)}' values`, prop, "cert/key are PEM strings or Buffers here");
2430
+ lowerer.noLowering(`a ${what} '${k}' option of '${lowerer.fmt(v.type)}' values`, prop, "cert/key are PEM strings or Buffers here");
2426
2431
  }
2427
2432
  if (k === "cert")
2428
2433
  cert = v;
@@ -2430,7 +2435,7 @@ function lowerTlsServerOptions(L, node, what) {
2430
2435
  key = v;
2431
2436
  }
2432
2437
  if (cert === null || key === null) {
2433
- L.noLowering(`${what} without both cert and key`, node, "the supported options object is { cert, key } (PEM strings or Buffers)");
2438
+ lowerer.noLowering(`${what} without both cert and key`, node, "the supported options object is { cert, key } (PEM strings or Buffers)");
2434
2439
  }
2435
2440
  return { cert, key };
2436
2441
  }
@@ -2460,12 +2465,12 @@ function tlsLiteralNeedsRuntimeWalk(node, includeHttpTimeoutOptions = false) {
2460
2465
  ((includeHttpTimeoutOptions && p.name.text === "keepAliveTimeoutBuffer") ||
2461
2466
  (jsSource && TLS_VALIDATED_OPTIONS.has(p.name.text))));
2462
2467
  }
2463
- function lowerTlsServerOptionsOrDyn(L, node, what, includeHttpTimeoutOptions = false) {
2468
+ function lowerTlsServerOptionsOrDyn(lowerer, node, what, includeHttpTimeoutOptions = false) {
2464
2469
  if (ts.isObjectLiteralExpression(node) &&
2465
2470
  !tlsLiteralNeedsRuntimeWalk(node, includeHttpTimeoutOptions)) {
2466
- return lowerTlsServerOptions(L, node, what);
2471
+ return lowerTlsServerOptions(lowerer, node, what);
2467
2472
  }
2468
- const v = L.lowerExpr(node);
2473
+ const v = lowerer.lowerExpr(node);
2469
2474
  if (v.type.kind === "dyn")
2470
2475
  return { dyn: v };
2471
2476
  // A typed options RECORD binding (`const options = { key, cert, ... };
@@ -2474,10 +2479,10 @@ function lowerTlsServerOptionsOrDyn(L, node, what, includeHttpTimeoutOptions = f
2474
2479
  // stance — members read at runtime, out-of-bounds ones throw the
2475
2480
  // catchable fence, undefined/undocumented ones drop). canConvertToDyn
2476
2481
  // now folds in the bytes-bearing option records the walker can box.
2477
- if (canConvertToDyn(v.type, (id) => L.shapes.get(id), (id) => L.unions.get(id))) {
2482
+ if (canConvertToDyn(v.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
2478
2483
  return { dyn: { kind: "dynFrom", value: v, type: DYN, loc: locOf(node) } };
2479
2484
  }
2480
- L.noLowering(`${what} with a non-literal options argument`, node, "pass the options as an object literal: { cert, key }");
2485
+ lowerer.noLowering(`${what} with a non-literal options argument`, node, "pass the options as an object literal: { cert, key }");
2481
2486
  }
2482
2487
  /** tls.connect — the TLS client socket. The lowered forms are
2483
2488
  * connect(options[, cb]) and connect(port[, host][, options][, cb]) with
@@ -2487,24 +2492,23 @@ function lowerTlsServerOptionsOrDyn(L, node, what, includeHttpTimeoutOptions = f
2487
2492
  * fence for other documented members (the divergence-66 stance). The
2488
2493
  * callback (and 'secureConnect'/'connect' listeners) fires
2489
2494
  * post-handshake — Node's secureConnect timing. */
2490
- function lowerTlsConnectCall(L, expr, loc) {
2495
+ function lowerTlsConnectCall(lowerer, expr, loc) {
2491
2496
  const args = expr.arguments;
2492
2497
  const FORMS_HINT = "the supported forms are connect(options[, cb]) and connect(port[, host][, options][, cb]) — options implement port/host/rejectUnauthorized/ca/servername";
2493
2498
  if (args.length < 1 || args.length > 4 || args.some(ts.isSpreadElement)) {
2494
- L.noLowering(`tls.connect with ${args.length} arguments`, expr, FORMS_HINT);
2499
+ lowerer.noLowering(`tls.connect with ${args.length} arguments`, expr, FORMS_HINT);
2495
2500
  }
2496
2501
  const isFuncish = (a) => ts.isFunctionExpression(a) || ts.isArrowFunction(a) ||
2497
- L.checker.getCallSignatures(L.typeOf(a)).length > 0;
2502
+ lowerer.checker.getCallSignatures(lowerer.typeOf(a)).length > 0;
2498
2503
  const isObjectish = (a) => {
2499
2504
  if (ts.isObjectLiteralExpression(a))
2500
2505
  return true;
2501
2506
  if (isFuncish(a) || ts.isStringLiteralLike(a) || ts.isNumericLiteral(a))
2502
2507
  return false;
2503
- const t = L.typeOf(a);
2508
+ const t = lowerer.typeOf(a);
2504
2509
  return (t.flags & ts.TypeFlags.Object) !== 0;
2505
2510
  };
2506
- const num = (value) => ({ kind: "numLit", value, type: F64, loc });
2507
- let port = num(-1); // -1: the runtime reads options.port
2511
+ let port = numLit(-1, loc); // -1: the runtime reads options.port
2508
2512
  let host = { kind: "strLit", value: "", type: STRING, loc }; // "": options.host / localhost
2509
2513
  let optsNode = null;
2510
2514
  let i = 0;
@@ -2513,25 +2517,25 @@ function lowerTlsConnectCall(L, expr, loc) {
2513
2517
  i = 1;
2514
2518
  }
2515
2519
  else if (isFuncish(args[0])) {
2516
- L.noLowering("tls.connect with a callback-first argument shape", expr, FORMS_HINT);
2520
+ lowerer.noLowering("tls.connect with a callback-first argument shape", expr, FORMS_HINT);
2517
2521
  }
2518
2522
  else {
2519
- const p = L.lowerExpr(args[0]);
2523
+ const p = lowerer.lowerExpr(args[0]);
2520
2524
  if (p.type.kind === "f64")
2521
2525
  port = p;
2522
2526
  else if (p.type.kind === "dyn")
2523
2527
  port = { kind: "dynCheck", value: p, type: F64, loc };
2524
2528
  else
2525
- L.noLowering(`tls.connect with a '${L.fmt(p.type)}' port`, args[0], FORMS_HINT);
2529
+ lowerer.noLowering(`tls.connect with a '${lowerer.fmt(p.type)}' port`, args[0], FORMS_HINT);
2526
2530
  i = 1;
2527
2531
  if (i < args.length && !isFuncish(args[i]) && !isObjectish(args[i])) {
2528
- const h = L.lowerExpr(args[i]);
2532
+ const h = lowerer.lowerExpr(args[i]);
2529
2533
  if (h.type.kind === "string")
2530
2534
  host = h;
2531
2535
  else if (h.type.kind === "dyn")
2532
2536
  host = { kind: "dynCheck", value: h, type: STRING, loc };
2533
2537
  else
2534
- L.noLowering(`tls.connect with a '${L.fmt(h.type)}' host`, args[i], FORMS_HINT);
2538
+ lowerer.noLowering(`tls.connect with a '${lowerer.fmt(h.type)}' host`, args[i], FORMS_HINT);
2535
2539
  i++;
2536
2540
  }
2537
2541
  if (i < args.length && isObjectish(args[i])) {
@@ -2543,20 +2547,20 @@ function lowerTlsConnectCall(L, expr, loc) {
2543
2547
  // directly; a typed record that converts boxes into the checked-dynamic tree.
2544
2548
  let opts;
2545
2549
  if (optsNode !== null) {
2546
- const o = L.lowerExpr(optsNode);
2550
+ const o = lowerer.lowerExpr(optsNode);
2547
2551
  if (o.type.kind === "dyn") {
2548
2552
  opts = o;
2549
2553
  }
2550
- else if (canConvertToDyn(o.type, (id) => L.shapes.get(id), (id) => L.unions.get(id))) {
2554
+ else if (canConvertToDyn(o.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
2551
2555
  opts = { kind: "dynFrom", value: o, type: DYN, loc };
2552
2556
  }
2553
2557
  else {
2554
- L.noLowering(`tls.connect with a '${L.fmt(o.type)}' options record`, optsNode, FORMS_HINT);
2558
+ lowerer.noLowering(`tls.connect with a '${lowerer.fmt(o.type)}' options record`, optsNode, FORMS_HINT);
2555
2559
  }
2556
2560
  }
2557
2561
  else {
2558
2562
  if (port.kind === "numLit" && port.value === -1) {
2559
- L.noLowering("tls.connect without a port or options", expr, FORMS_HINT);
2563
+ lowerer.noLowering("tls.connect without a port or options", expr, FORMS_HINT);
2560
2564
  }
2561
2565
  // No options: Node's defaults (rejectUnauthorized: true) — the
2562
2566
  // runtime walk reads an absent record (the dyn undefined).
@@ -2570,9 +2574,9 @@ function lowerTlsConnectCall(L, expr, loc) {
2570
2574
  let cb = null;
2571
2575
  if (i < args.length) {
2572
2576
  if (i !== args.length - 1 || !isFuncish(args[i])) {
2573
- L.noLowering("tls.connect with this argument shape", expr, FORMS_HINT);
2577
+ lowerer.noLowering("tls.connect with this argument shape", expr, FORMS_HINT);
2574
2578
  }
2575
- const r = lowerCallbackArg(L, args[i], "secureConnect listeners", 0, () => false, "use ()", []);
2579
+ const r = lowerCallbackArg(lowerer, args[i], "secureConnect listeners", 0, () => false, "use ()", []);
2576
2580
  cb = r.cb;
2577
2581
  }
2578
2582
  return cb !== null
@@ -2584,39 +2588,39 @@ function lowerTlsConnectCall(L, expr, loc) {
2584
2588
  * socket that behaves exactly like a net socket. Everything else the
2585
2589
  * module declares fences qualified (createSecureContext and connect
2586
2590
  * carry pointed hints from the fence-hint table). */
2587
- function lowerTlsModuleCall(L, expr, bi, loc) {
2591
+ function lowerTlsModuleCall(lowerer, expr, bi, loc) {
2588
2592
  const args = expr.arguments;
2589
2593
  if (bi.member === "createServer") {
2590
2594
  if (args.length < 1 || args.length > 2) {
2591
- L.noLowering(`createServer with ${args.length} arguments`, expr, "the supported form is createServer({ cert, key }, socket => ...)");
2595
+ lowerer.noLowering(`createServer with ${args.length} arguments`, expr, "the supported form is createServer({ cert, key }, socket => ...)");
2592
2596
  }
2593
- const opts = lowerTlsServerOptionsOrDyn(L, args[0], "tls.createServer");
2597
+ const opts = lowerTlsServerOptionsOrDyn(lowerer, args[0], "tls.createServer");
2594
2598
  if (args.length === 1) {
2595
2599
  return opts.dyn !== undefined
2596
2600
  ? { kind: "libCall", fn: "tls.createServerDyn", args: [opts.dyn], type: NETSERVER_T, loc }
2597
2601
  : { kind: "libCall", fn: "tls.createServer", args: [opts.cert, opts.key], type: NETSERVER_T, loc };
2598
2602
  }
2599
- const { cb } = lowerCallbackArg(L, args[1], "secureConnection listeners", 1, (p) => p.kind === "netSocket", "use (socket) or ()", [NETSOCKET_T]);
2603
+ const { cb } = lowerCallbackArg(lowerer, args[1], "secureConnection listeners", 1, (p) => p.kind === "netSocket", "use (socket) or ()", [NETSOCKET_T]);
2600
2604
  return opts.dyn !== undefined
2601
2605
  ? { kind: "libCall", fn: "tls.createServerDynCb", args: [opts.dyn, cb], type: NETSERVER_T, loc }
2602
2606
  : { kind: "libCall", fn: "tls.createServerCb", args: [opts.cert, opts.key, cb], type: NETSERVER_T, loc };
2603
2607
  }
2604
2608
  if (bi.member === "connect") {
2605
- return lowerTlsConnectCall(L, expr, loc);
2609
+ return lowerTlsConnectCall(lowerer, expr, loc);
2606
2610
  }
2607
2611
  if (bi.member === "getCACertificates" && args.length === 1 && !args.some(ts.isSpreadElement) &&
2608
2612
  isJsSourceFile(expr.getSourceFile())) {
2609
2613
  // The type-argument ladder (validateString + the documented name
2610
2614
  // set); the real CA list has no lowering, so a valid name meets the
2611
2615
  // compiler-rendered fence after the validation.
2612
- const raw = L.lowerExpr(args[0]);
2613
- if (raw.type.kind === "dyn" || raw.kind === "unitLit" || L.dynConvertible(raw.type)) {
2616
+ const raw = lowerer.lowerExpr(args[0]);
2617
+ if (raw.type.kind === "dyn" || raw.kind === "unitLit" || lowerer.dynConvertible(raw.type)) {
2614
2618
  const t = raw.type.kind === "dyn" ? raw : { kind: "dynFrom", value: raw, type: DYN, loc };
2615
2619
  return {
2616
2620
  kind: "libCall",
2617
2621
  fn: "tls.caCertsChk",
2618
- args: [t, ladderFenceExpr(L, "tls.getCACertificates", expr)],
2619
- type: L.mapTypeOf(L.typeOf(expr)) ?? DYN,
2622
+ args: [t, ladderFenceExpr(lowerer, "tls.getCACertificates", expr)],
2623
+ type: lowerer.mapTypeOf(lowerer.typeOf(expr)) ?? DYN,
2620
2624
  loc,
2621
2625
  };
2622
2626
  }
@@ -2627,9 +2631,9 @@ function lowerTlsModuleCall(L, expr, bi, loc) {
2627
2631
  // cert/key pair (PEM strings or Buffers — the createServer options
2628
2632
  // walk, reused); ca/ciphers/etc. fence by name there.
2629
2633
  if (args.length !== 1) {
2630
- L.noLowering(`createSecureContext with ${args.length} arguments`, expr, "the supported form is createSecureContext({ cert, key })");
2634
+ lowerer.noLowering(`createSecureContext with ${args.length} arguments`, expr, "the supported form is createSecureContext({ cert, key })");
2631
2635
  }
2632
- const opts = lowerTlsServerOptionsOrDyn(L, args[0], "tls.createSecureContext");
2636
+ const opts = lowerTlsServerOptionsOrDyn(lowerer, args[0], "tls.createSecureContext");
2633
2637
  if (opts.dyn !== undefined) {
2634
2638
  return { kind: "libCall", fn: "tls.createSecureContextDyn", args: [opts.dyn], type: SECURECTX_T, loc };
2635
2639
  }
@@ -2644,49 +2648,49 @@ function lowerTlsModuleCall(L, expr, bi, loc) {
2644
2648
  // lowerTlsRootCertificates below.
2645
2649
  if (bi.member === "getCACertificates") {
2646
2650
  if (args.length > 1) {
2647
- L.noLowering(`getCACertificates with ${args.length} arguments`, expr);
2651
+ lowerer.noLowering(`getCACertificates with ${args.length} arguments`, expr);
2648
2652
  }
2649
2653
  const typeArg = args.length === 1
2650
- ? L.lowerExprExpecting(args[0], STRING)
2654
+ ? lowerer.lowerExprExpecting(args[0], STRING)
2651
2655
  : { kind: "strLit", value: "default", type: STRING, loc };
2652
2656
  return { kind: "libCall", fn: "tlsca.get", args: [typeArg], type: arrayOf(STRING), loc };
2653
2657
  }
2654
2658
  if (bi.member === "setDefaultCACertificates") {
2655
2659
  if (args.length !== 1) {
2656
- L.noLowering(`setDefaultCACertificates with ${args.length} arguments`, expr);
2660
+ lowerer.noLowering(`setDefaultCACertificates with ${args.length} arguments`, expr);
2657
2661
  }
2658
- const certs = L.lowerExpr(args[0]);
2662
+ const certs = lowerer.lowerExpr(args[0]);
2659
2663
  if (certs.type.kind !== "array" || certs.type.elem.kind !== "string") {
2660
- L.noLowering(`setDefaultCACertificates of a '${L.fmt(certs.type)}' value`, args[0], "a string[] of PEM certificates is the lowered shape — decode Buffer/typed-array entries to strings first");
2664
+ lowerer.noLowering(`setDefaultCACertificates of a '${lowerer.fmt(certs.type)}' value`, args[0], "a string[] of PEM certificates is the lowered shape — decode Buffer/typed-array entries to strings first");
2661
2665
  }
2662
2666
  return { kind: "libCall", fn: "tlsca.set", args: [certs], type: VOID, loc };
2663
2667
  }
2664
- L.noLowering(`tls.${bi.member}`, expr, builtinFenceHintOf("tls", bi.member) ??
2665
- "createServer({ cert, key }, handler) and createSecureContext({ cert, key }) are the lowered tls module functions", L.resolveValueSymbol(expr.expression));
2668
+ lowerer.noLowering(`tls.${bi.member}`, expr, builtinFenceHintOf("tls", bi.member) ??
2669
+ "createServer({ cert, key }, handler) and createSecureContext({ cert, key }) are the lowered tls module functions", lowerer.resolveValueSymbol(expr.expression));
2666
2670
  }
2667
2671
  /** The tls.rootCertificates VALUE read (any import spelling): the same
2668
2672
  * cached array getCACertificates("bundled") answers — Node's own
2669
2673
  * equality (test-tls-get-ca-certificates-bundled pins certs ===
2670
2674
  * rootCertificates). Null for other members (the property chains keep
2671
2675
  * trying). */
2672
- export function lowerTlsRootCertificates(L, bi, loc) {
2676
+ export function lowerTlsRootCertificates(lowerer, bi, loc) {
2673
2677
  if (bi.module !== "tls" || bi.member !== "rootCertificates")
2674
2678
  return null;
2675
2679
  return { kind: "libCall", fn: "tlsca.root", args: [], type: arrayOf(STRING), loc };
2676
2680
  }
2677
2681
  const httpClientFnBindings = new WeakMap();
2678
- export function httpClientFnBindingOf(L, sym) {
2679
- return httpClientFnBindings.get(L)?.get(sym);
2682
+ export function httpClientFnBindingOf(lowerer, sym) {
2683
+ return httpClientFnBindings.get(lowerer)?.get(sym);
2680
2684
  }
2681
2685
  /** The { module, member } of an http/https client-function REFERENCE
2682
2686
  * (`https.request` through a namespace import, or a named `request`
2683
2687
  * import binding) — null for anything else. */
2684
- function clientFnRefOf(L, node) {
2688
+ function clientFnRefOf(lowerer, node) {
2685
2689
  const e = node;
2686
2690
  const bi = ts.isPropertyAccessExpression(e)
2687
- ? L.builtinMemberOf(e)
2691
+ ? lowerer.builtinMemberOf(e)
2688
2692
  : ts.isIdentifier(e)
2689
- ? L.builtinImportOf(e)
2693
+ ? lowerer.builtinImportOf(e)
2690
2694
  : null;
2691
2695
  if (!bi)
2692
2696
  return null;
@@ -2698,8 +2702,8 @@ function clientFnRefOf(L, node) {
2698
2702
  /** True when `sym`'s binding is never written after initialization: a
2699
2703
  * `const` declaration, or a parameter/let whose enclosing scope contains
2700
2704
  * no assignment or ++/-- targeting it. */
2701
- function neverReassigned(L, sym) {
2702
- const decl = L.checker.declarationsOf(sym)[0];
2705
+ function neverReassigned(lowerer, sym) {
2706
+ const decl = lowerer.checker.declarationsOf(sym)[0];
2703
2707
  if (!decl)
2704
2708
  return false;
2705
2709
  if (ts.isVariableDeclaration(decl) && (ts.getCombinedNodeFlags(decl) & ts.NodeFlags.Const) !== 0) {
@@ -2716,7 +2720,7 @@ function neverReassigned(L, sym) {
2716
2720
  const root = ts.isFunctionLike(scope.parent) ? scope.parent : scope.parent;
2717
2721
  let written = false;
2718
2722
  const hitsSym = (n) => {
2719
- if (ts.isIdentifier(n) && L.checker.getSymbolAtLocation(n) === sym)
2723
+ if (ts.isIdentifier(n) && lowerer.checker.getSymbolAtLocation(n) === sym)
2720
2724
  return true;
2721
2725
  let hit = false;
2722
2726
  ts.forEachChild(n, (c) => {
@@ -2739,7 +2743,7 @@ function neverReassigned(L, sym) {
2739
2743
  }
2740
2744
  if ((ts.isPrefixUnaryExpression(n) || ts.isPostfixUnaryExpression(n)) &&
2741
2745
  (n.operator === ts.SyntaxKind.PlusPlusToken || n.operator === ts.SyntaxKind.MinusMinusToken) &&
2742
- ts.isIdentifier(n.operand) && L.checker.getSymbolAtLocation(n.operand) === sym) {
2746
+ ts.isIdentifier(n.operand) && lowerer.checker.getSymbolAtLocation(n.operand) === sym) {
2743
2747
  written = true;
2744
2748
  return;
2745
2749
  }
@@ -2754,7 +2758,7 @@ function neverReassigned(L, sym) {
2754
2758
  * nothing) and answers true. A matched ternary whose condition is not a
2755
2759
  * stable identifier fences pointedly; non-client ternaries answer false
2756
2760
  * (the ordinary decl path and its per-arm fences apply). */
2757
- export function registerHttpClientFnBinding(L, nameNode, init) {
2761
+ export function registerHttpClientFnBinding(lowerer, nameNode, init) {
2758
2762
  if (!init)
2759
2763
  return false;
2760
2764
  let e = init;
@@ -2768,24 +2772,24 @@ export function registerHttpClientFnBinding(L, nameNode, init) {
2768
2772
  x = x.expression;
2769
2773
  return x;
2770
2774
  };
2771
- const t = clientFnRefOf(L, unwrap(e.whenTrue));
2772
- const f = clientFnRefOf(L, unwrap(e.whenFalse));
2775
+ const t = clientFnRefOf(lowerer, unwrap(e.whenTrue));
2776
+ const f = clientFnRefOf(lowerer, unwrap(e.whenFalse));
2773
2777
  if (!t || !f)
2774
2778
  return false;
2775
2779
  if (t.member !== f.member || t.module === f.module) {
2776
- L.noLowering("a conditional between these two client functions", e, "the lowered shape is `cond ? https.request : http.request` (or the .get pair, either order) — the same member of both modules");
2780
+ lowerer.noLowering("a conditional between these two client functions", e, "the lowered shape is `cond ? https.request : http.request` (or the .get pair, either order) — the same member of both modules");
2777
2781
  }
2778
2782
  const cond = unwrap(e.condition);
2779
- const condSym = ts.isIdentifier(cond) ? L.resolveValueSymbol(cond) : null;
2780
- if (!condSym || !neverReassigned(L, condSym)) {
2781
- L.noLowering("a client-function conditional with this condition shape", e.condition, "the condition must be a bare identifier whose binding is never reassigned (it re-evaluates at each call through the binding)");
2783
+ const condSym = ts.isIdentifier(cond) ? lowerer.resolveValueSymbol(cond) : null;
2784
+ if (!condSym || !neverReassigned(lowerer, condSym)) {
2785
+ lowerer.noLowering("a client-function conditional with this condition shape", e.condition, "the condition must be a bare identifier whose binding is never reassigned (it re-evaluates at each call through the binding)");
2782
2786
  }
2783
- const symbol = L.checker.getSymbolAtLocation(nameNode);
2787
+ const symbol = lowerer.checker.getSymbolAtLocation(nameNode);
2784
2788
  if (symbol) {
2785
- let map = httpClientFnBindings.get(L);
2789
+ let map = httpClientFnBindings.get(lowerer);
2786
2790
  if (!map) {
2787
2791
  map = new Map();
2788
- httpClientFnBindings.set(L, map);
2792
+ httpClientFnBindings.set(lowerer, map);
2789
2793
  }
2790
2794
  map.set(symbol, { cond, trueSecure: t.module === "https", member: t.member });
2791
2795
  }
@@ -2793,19 +2797,19 @@ export function registerHttpClientFnBinding(L, nameNode, init) {
2793
2797
  }
2794
2798
  /** A call THROUGH a registered requestFn binding: the http client
2795
2799
  * lowering with the RUNTIME-secure extras (the binding mode). */
2796
- export function lowerHttpClientFnCall(L, expr, binding, loc) {
2797
- return lowerHttpClientCall(L, expr, binding.member, loc, binding);
2800
+ export function lowerHttpClientFnCall(lowerer, expr, binding, loc) {
2801
+ return lowerHttpClientCall(lowerer, expr, binding.member, loc, binding);
2798
2802
  }
2799
2803
  /** Module-function calls on https import bindings: createServer(options,
2800
2804
  * handler) and request/get — the http client lowering with the secure
2801
2805
  * extras (port 443 default, rejectUnauthorized, ca). */
2802
- function lowerHttpsModuleCall(L, expr, bi, loc) {
2806
+ function lowerHttpsModuleCall(lowerer, expr, bi, loc) {
2803
2807
  const args = expr.arguments;
2804
2808
  if (bi.member === "createServer") {
2805
2809
  if (args.length < 1 || args.length > 2) {
2806
- L.noLowering(`createServer with ${args.length} arguments`, expr, "the supported form is createServer({ cert, key }, (req, res) => ...)");
2810
+ lowerer.noLowering(`createServer with ${args.length} arguments`, expr, "the supported form is createServer({ cert, key }, (req, res) => ...)");
2807
2811
  }
2808
- const opts = lowerTlsServerOptionsOrDyn(L, args[0], "https.createServer", true);
2812
+ const opts = lowerTlsServerOptionsOrDyn(lowerer, args[0], "https.createServer", true);
2809
2813
  if (args.length === 1) {
2810
2814
  // The handler-less form: 'request' listeners arrive later via
2811
2815
  // server.on("request", ...) — the createSecureServer emission's
@@ -2814,17 +2818,17 @@ function lowerHttpsModuleCall(L, expr, bi, loc) {
2814
2818
  if (opts.dyn !== undefined) {
2815
2819
  return { kind: "libCall", fn: "https.createServerDyn", args: [opts.dyn], type: NETSERVER_T, loc };
2816
2820
  }
2817
- L.noLowering("createServer with 1 arguments", expr, "the supported form is createServer({ cert, key }, (req, res) => ...)");
2821
+ lowerer.noLowering("createServer with 1 arguments", expr, "the supported form is createServer({ cert, key }, (req, res) => ...)");
2818
2822
  }
2819
- const cb = lowerRequestHandlerArg(L, args[1]);
2823
+ const cb = lowerRequestHandlerArg(lowerer, args[1]);
2820
2824
  return opts.dyn !== undefined
2821
2825
  ? { kind: "libCall", fn: "https.createServerDynCb", args: [opts.dyn, cb], type: NETSERVER_T, loc }
2822
2826
  : { kind: "libCall", fn: "https.createServer", args: [opts.cert, opts.key, cb], type: NETSERVER_T, loc };
2823
2827
  }
2824
2828
  if (bi.member === "request" || bi.member === "get") {
2825
- return lowerHttpClientCall(L, expr, bi.member, loc, true);
2829
+ return lowerHttpClientCall(lowerer, expr, bi.member, loc, true);
2826
2830
  }
2827
- L.noLowering(`https.${bi.member}`, expr, "createServer, request, and get are the lowered https module functions", L.resolveValueSymbol(expr.expression));
2831
+ lowerer.noLowering(`https.${bi.member}`, expr, "createServer, request, and get are the lowered https module functions", lowerer.resolveValueSymbol(expr.expression));
2828
2832
  }
2829
2833
  /** The h2 SESSION-tuning options of http2.createSecureServer. This slice
2830
2834
  * runs most at their defaults, so they are accepted and ignored only with
@@ -2862,7 +2866,7 @@ function stripParensAndCasts(node) {
2862
2866
  /** Module-function calls on http2 import bindings. createServer lowers h2c;
2863
2867
  * createSecureServer lowers h2 over TLS, with allowHTTP1 selecting one
2864
2868
  * dual-ALPN server whose request/connect listeners mirror across parsers. */
2865
- function lowerHttp2ModuleCall(L, expr, bi, loc) {
2869
+ function lowerHttp2ModuleCall(lowerer, expr, bi, loc) {
2866
2870
  const args = expr.arguments;
2867
2871
  if (bi.member === "createServer") {
2868
2872
  // The REAL h2c server (scr_http2.c). An options object literal is
@@ -2882,8 +2886,8 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
2882
2886
  // anything else is a tuning-options VALUE — accepted and never
2883
2887
  // evaluated (h2 knobs this core runs at defaults; the options
2884
2888
  // expression is a pure read in every suite shape).
2885
- const t = L.typeOf(a);
2886
- if (L.checker.getCallSignatures(t).length > 0 ||
2889
+ const t = lowerer.typeOf(a);
2890
+ if (lowerer.checker.getCallSignatures(t).length > 0 ||
2887
2891
  (t.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) !== 0) {
2888
2892
  handlerNode = a;
2889
2893
  }
@@ -2895,18 +2899,18 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
2895
2899
  // becomes the first 'request' listener (Node's exact route), and the
2896
2900
  // pair it receives ARE the http req/res handles — Http2ServerRequest/
2897
2901
  // Http2ServerResponse over h2 streams (scr_http2.c's compat layer).
2898
- const cb = lowerRequestHandlerArg(L, handlerNode);
2902
+ const cb = lowerRequestHandlerArg(lowerer, handlerNode);
2899
2903
  return { kind: "libCall", fn: "http2.createServerReq", args: [cb], type: NETSERVER_T, loc };
2900
2904
  }
2901
2905
  if (bi.member === "connect") {
2902
2906
  // http2.connect(authority[, listener]) — the h2c client. The
2903
2907
  // authority is a string (URL objects and an options record fence).
2904
2908
  if (args.length < 1 || args.length > 3) {
2905
- L.noLowering(`http2.connect with ${args.length} arguments`, expr, "the supported form is connect(authority[, options][, listener]) with a string authority");
2909
+ lowerer.noLowering(`http2.connect with ${args.length} arguments`, expr, "the supported form is connect(authority[, options][, listener]) with a string authority");
2906
2910
  }
2907
- const auth = L.lowerExpr(args[0]);
2911
+ const auth = lowerer.lowerExpr(args[0]);
2908
2912
  if (auth.type.kind !== "string") {
2909
- L.noLowering(`http2.connect with a '${L.fmt(auth.type)}' authority`, args[0], "the authority is a string here (\"http://host:port\")");
2913
+ lowerer.noLowering(`http2.connect with a '${lowerer.fmt(auth.type)}' authority`, args[0], "the authority is a string here (\"http://host:port\")");
2910
2914
  }
2911
2915
  // connect(authority, options[, listener]): session-tuning options
2912
2916
  // are accepted and never evaluated (the core runs at defaults) —
@@ -2922,9 +2926,9 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
2922
2926
  let reject = { kind: "boolLit", value: true, type: BOOL, loc };
2923
2927
  let ca = { kind: "strLit", value: "", type: STRING, loc };
2924
2928
  const arg1IsDyn = args.length >= 2 &&
2925
- (L.typeOf(args[1]).flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) !== 0;
2929
+ (lowerer.typeOf(args[1]).flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) !== 0;
2926
2930
  if (args.length >= 2 && !arg1IsDyn &&
2927
- L.checker.getCallSignatures(L.typeOf(args[1])).length === 0) {
2931
+ lowerer.checker.getCallSignatures(lowerer.typeOf(args[1])).length === 0) {
2928
2932
  if (ts.isObjectLiteralExpression(args[1])) {
2929
2933
  for (const pr of args[1].properties) {
2930
2934
  // Plain `name: value` and shorthand `{ ca }` both carry the
@@ -2943,18 +2947,18 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
2943
2947
  continue;
2944
2948
  }
2945
2949
  if (name === "createConnection") {
2946
- L.noLowering("http2.connect with a createConnection option", args[1], "custom transports are not modeled — connect dials TCP itself");
2950
+ lowerer.noLowering("http2.connect with a createConnection option", args[1], "custom transports are not modeled — connect dials TCP itself");
2947
2951
  }
2948
2952
  if (name === "rejectUnauthorized") {
2949
2953
  if (valueNode.kind === ts.SyntaxKind.FalseKeyword) {
2950
2954
  reject = { kind: "boolLit", value: false, type: BOOL, loc };
2951
2955
  }
2952
2956
  else if (valueNode.kind !== ts.SyntaxKind.TrueKeyword) {
2953
- L.noLowering("http2.connect with a non-literal rejectUnauthorized option", pr, "spell it true or false — it gates the https authority's certificate verification");
2957
+ lowerer.noLowering("http2.connect with a non-literal rejectUnauthorized option", pr, "spell it true or false — it gates the https authority's certificate verification");
2954
2958
  }
2955
2959
  }
2956
2960
  if (name === "ca") {
2957
- const v = L.lowerExpr(valueNode);
2961
+ const v = lowerer.lowerExpr(valueNode);
2958
2962
  if (v.type.kind === "string" || (v.type.kind === "bytes" && v.type.elem === "u8")) {
2959
2963
  ca = v;
2960
2964
  }
@@ -2968,7 +2972,7 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
2968
2972
  };
2969
2973
  }
2970
2974
  else {
2971
- L.noLowering(`an http2.connect 'ca' option of '${L.fmt(v.type)}' values`, pr, "ca is a PEM string or Buffer here");
2975
+ lowerer.noLowering(`an http2.connect 'ca' option of '${lowerer.fmt(v.type)}' values`, pr, "ca is a PEM string or Buffer here");
2972
2976
  }
2973
2977
  }
2974
2978
  }
@@ -2981,7 +2985,7 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
2981
2985
  if (listenerNode !== undefined) {
2982
2986
  // The listener is the 'connect' once-listener: (session, socket) or
2983
2987
  // fewer. Its result is ignored (voidized); handles pass by ref.
2984
- const { cb } = lowerCallbackArg(L, listenerNode, "connect listeners", 2, (p) => p.kind === "http2Session" || p.kind === "netSocket", "use (session, socket), (session), or ()", [HTTP2SESSION_T, NETSOCKET_T]);
2988
+ const { cb } = lowerCallbackArg(lowerer, listenerNode, "connect listeners", 2, (p) => p.kind === "http2Session" || p.kind === "netSocket", "use (session, socket), (session), or ()", [HTTP2SESSION_T, NETSOCKET_T]);
2985
2989
  return { kind: "libCall", fn: "http2.connectCb", args: [auth, reject, ca, cb], type: HTTP2SESSION_T, loc };
2986
2990
  }
2987
2991
  return { kind: "libCall", fn: "http2.connect", args: [auth, reject, ca], type: HTTP2SESSION_T, loc };
@@ -2993,7 +2997,7 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
2993
2997
  }
2994
2998
  if (bi.member === "createSecureServer") {
2995
2999
  if (args.length < 1 || args.length > 2) {
2996
- L.noLowering(`createSecureServer with ${args.length} arguments`, expr, "the supported forms are createSecureServer(options[, onRequestHandler]) with options { allowHTTP1?, cert, key }");
3000
+ lowerer.noLowering(`createSecureServer with ${args.length} arguments`, expr, "the supported forms are createSecureServer(options[, onRequestHandler]) with options { allowHTTP1?, cert, key }");
2997
3001
  }
2998
3002
  const optsNode = args[0];
2999
3003
  // The eager (req, res) handler — Node routes it as the first
@@ -3007,21 +3011,21 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
3007
3011
  // at runtime, out-of-bounds TLS members throw the catchable
3008
3012
  // runtime fence, h2 session-tuning keys drop exactly like the
3009
3013
  // literal walk ignores them.
3010
- const v = L.lowerExpr(optsNode);
3014
+ const v = lowerer.lowerExpr(optsNode);
3011
3015
  let dynOpts;
3012
3016
  if (v.type.kind === "dyn") {
3013
3017
  dynOpts = v;
3014
3018
  }
3015
- else if (canConvertToDyn(v.type, (id) => L.shapes.get(id), (id) => L.unions.get(id))) {
3019
+ else if (canConvertToDyn(v.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
3016
3020
  dynOpts = { kind: "dynFrom", value: v, type: DYN, loc: locOf(optsNode) };
3017
3021
  }
3018
3022
  else {
3019
- L.noLowering("createSecureServer with a non-literal options argument", optsNode, "pass the options as an object literal ({ allowHTTP1: true, cert, key }) or a runtime record of those members");
3023
+ lowerer.noLowering("createSecureServer with a non-literal options argument", optsNode, "pass the options as an object literal ({ allowHTTP1: true, cert, key }) or a runtime record of those members");
3020
3024
  }
3021
3025
  if (handlerNode === null) {
3022
3026
  return { kind: "libCall", fn: "http2.createSecureServerDyn", args: [dynOpts], type: NETSERVER_T, loc };
3023
3027
  }
3024
- const cb = lowerRequestHandlerArg(L, handlerNode);
3028
+ const cb = lowerRequestHandlerArg(lowerer, handlerNode);
3025
3029
  return { kind: "libCall", fn: "http2.createSecureServerDynCb", args: [dynOpts, cb], type: NETSERVER_T, loc };
3026
3030
  }
3027
3031
  let cert = null;
@@ -3041,7 +3045,7 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
3041
3045
  const cbT = t.params[1];
3042
3046
  if (cbT.kind !== "func" || cbT.ret.kind !== "void" || cbT.params.length > 2)
3043
3047
  return false;
3044
- const armKinds = (u) => u.kind === "union" ? (L.unions.get(u.unionId)?.arms ?? []).map((a) => a.kind) : [];
3048
+ const armKinds = (u) => u.kind === "union" ? (lowerer.unions.get(u.unionId)?.arms ?? []).map((a) => a.kind) : [];
3045
3049
  const p0 = cbT.params[0];
3046
3050
  if (p0 !== undefined && !armKinds(p0).includes("nullT"))
3047
3051
  return false;
@@ -3051,17 +3055,17 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
3051
3055
  return true;
3052
3056
  };
3053
3057
  const lowerSniValue = (node, blame) => {
3054
- const v = L.lowerExpr(node);
3058
+ const v = lowerer.lowerExpr(node);
3055
3059
  const funcArm = v.type.kind === "func"
3056
3060
  ? v.type
3057
3061
  : v.type.kind === "union"
3058
- ? (L.unions.get(v.type.unionId)?.arms ?? []).find((a) => a.kind === "func")
3062
+ ? (lowerer.unions.get(v.type.unionId)?.arms ?? []).find((a) => a.kind === "func")
3059
3063
  : undefined;
3060
3064
  const unionOk = v.type.kind !== "union" ||
3061
- ((L.unions.get(v.type.unionId)?.arms ?? []).length === 2 &&
3062
- (L.unions.get(v.type.unionId)?.arms ?? []).some((a) => a.kind === "undefinedT"));
3065
+ ((lowerer.unions.get(v.type.unionId)?.arms ?? []).length === 2 &&
3066
+ (lowerer.unions.get(v.type.unionId)?.arms ?? []).some((a) => a.kind === "undefinedT"));
3063
3067
  if (funcArm === undefined || !unionOk || !sniShapeOk(funcArm)) {
3064
- L.noLowering(`a createSecureServer SNICallback of '${L.fmt(v.type)}' values`, blame, SNI_HINT);
3068
+ lowerer.noLowering(`a createSecureServer SNICallback of '${lowerer.fmt(v.type)}' values`, blame, SNI_HINT);
3065
3069
  }
3066
3070
  sni = v;
3067
3071
  };
@@ -3093,13 +3097,13 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
3093
3097
  whenTrue.properties[0].name.text === "SNICallback" &&
3094
3098
  whenTrue.properties[0].initializer.getText() === condText;
3095
3099
  if (!ok) {
3096
- L.noLowering("createSecureServer options with a conditional spread", prop, "the lowered conditional spread is exactly ...(x ? { SNICallback: x } : {}) — the included value must BE the condition");
3100
+ lowerer.noLowering("createSecureServer options with a conditional spread", prop, "the lowered conditional spread is exactly ...(x ? { SNICallback: x } : {}) — the included value must BE the condition");
3097
3101
  }
3098
3102
  lowerSniValue(inner.condition, prop);
3099
3103
  return;
3100
3104
  }
3101
3105
  if (!ts.isObjectLiteralExpression(inner)) {
3102
- L.noLowering("createSecureServer options with a computed spread", prop, `spreads must be inline object literals here; ${SNI_HINT}`);
3106
+ lowerer.noLowering("createSecureServer options with a computed spread", prop, `spreads must be inline object literals here; ${SNI_HINT}`);
3103
3107
  }
3104
3108
  for (const p of inner.properties)
3105
3109
  lowerOption(p);
@@ -3114,7 +3118,7 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
3114
3118
  initializer = null;
3115
3119
  }
3116
3120
  else {
3117
- L.noLowering("createSecureServer options with computed keys", prop, "each option must be a plain `name: value` (or shorthand) entry with a literal key");
3121
+ lowerer.noLowering("createSecureServer options with computed keys", prop, "each option must be a plain `name: value` (or shorthand) entry with a literal key");
3118
3122
  }
3119
3123
  const k = prop.name.text;
3120
3124
  if (k === "allowHTTP1") {
@@ -3124,15 +3128,15 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
3124
3128
  if (initializer !== null && initializer.kind === ts.SyntaxKind.FalseKeyword)
3125
3129
  return;
3126
3130
  if (initializer === null || initializer.kind !== ts.SyntaxKind.TrueKeyword) {
3127
- L.noLowering("createSecureServer with a non-literal allowHTTP1 option", prop, "allowHTTP1 picks the protocol stack (true: dual h2/http1; false/absent: ALPN=h2 only) — spell it as a literal");
3131
+ lowerer.noLowering("createSecureServer with a non-literal allowHTTP1 option", prop, "allowHTTP1 picks the protocol stack (true: dual h2/http1; false/absent: ALPN=h2 only) — spell it as a literal");
3128
3132
  }
3129
3133
  allowHttp1 = true;
3130
3134
  return;
3131
3135
  }
3132
3136
  if (k === "cert" || k === "key") {
3133
3137
  let v = initializer !== null
3134
- ? L.lowerExpr(initializer)
3135
- : L.lowerShorthandValue(prop);
3138
+ ? lowerer.lowerExpr(initializer)
3139
+ : lowerer.lowerShorthandValue(prop);
3136
3140
  if (v.type.kind === "dyn") {
3137
3141
  // A runtime PEM value (fixtures.readKey(...)): the tls walk's
3138
3142
  // runtime extraction, same fences at runtime.
@@ -3145,7 +3149,7 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
3145
3149
  };
3146
3150
  }
3147
3151
  else if (v.type.kind !== "string" && !(v.type.kind === "bytes" && v.type.elem === "u8")) {
3148
- L.noLowering(`a createSecureServer '${k}' option of '${L.fmt(v.type)}' values`, prop, "cert/key are PEM strings or Buffers here");
3152
+ lowerer.noLowering(`a createSecureServer '${k}' option of '${lowerer.fmt(v.type)}' values`, prop, "cert/key are PEM strings or Buffers here");
3149
3153
  }
3150
3154
  if (k === "cert")
3151
3155
  cert = v;
@@ -3169,7 +3173,7 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
3169
3173
  setting.name.text === "enableConnectProtocol") {
3170
3174
  if (setting.initializer.kind !== ts.SyntaxKind.TrueKeyword &&
3171
3175
  setting.initializer.kind !== ts.SyntaxKind.FalseKeyword) {
3172
- L.noLowering("settings.enableConnectProtocol with a non-boolean literal", setting, "spell enableConnectProtocol as true or false");
3176
+ lowerer.noLowering("settings.enableConnectProtocol with a non-boolean literal", setting, "spell enableConnectProtocol as true or false");
3173
3177
  }
3174
3178
  enableConnectProtocol = setting.initializer.kind === ts.SyntaxKind.TrueKeyword;
3175
3179
  }
@@ -3179,25 +3183,25 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
3179
3183
  (isScalarLiteral(initializer) || isLiteralObjectOfLiterals(initializer))) {
3180
3184
  return;
3181
3185
  }
3182
- L.noLowering(`createSecureServer option '${k}' with a non-literal value`, prop, "h2 session-tuning options are accepted with literal values but are not applied yet");
3186
+ lowerer.noLowering(`createSecureServer option '${k}' with a non-literal value`, prop, "h2 session-tuning options are accepted with literal values but are not applied yet");
3183
3187
  }
3184
3188
  if (k === "SNICallback") {
3185
3189
  if (initializer === null) {
3186
- L.noLowering("createSecureServer with a shorthand SNICallback option", prop, "spell it out: SNICallback: theCallback");
3190
+ lowerer.noLowering("createSecureServer with a shorthand SNICallback option", prop, "spell it out: SNICallback: theCallback");
3187
3191
  }
3188
3192
  lowerSniValue(initializer, prop);
3189
3193
  return;
3190
3194
  }
3191
- fenceOrDropOptionKey(L, prop, k, "createSecureServer", HTTP2_SECURE_SERVER_DOCUMENTED_OPTIONS, "allowHTTP1: true, cert, key, and SNICallback are the supported options (h2 session-tuning options are accepted as literals and ignored)");
3195
+ fenceOrDropOptionKey(lowerer, prop, k, "createSecureServer", HTTP2_SECURE_SERVER_DOCUMENTED_OPTIONS, "allowHTTP1: true, cert, key, and SNICallback are the supported options (h2 session-tuning options are accepted as literals and ignored)");
3192
3196
  // An undocumented key, dropped like Node drops it.
3193
3197
  };
3194
3198
  for (const prop of optsNode.properties)
3195
3199
  lowerOption(prop);
3196
3200
  if (cert === null || key === null) {
3197
- L.noLowering("createSecureServer without both cert and key", optsNode, "the supported options object is { allowHTTP1?, cert, key } (PEM strings or Buffers)");
3201
+ lowerer.noLowering("createSecureServer without both cert and key", optsNode, "the supported options object is { allowHTTP1?, cert, key } (PEM strings or Buffers)");
3198
3202
  }
3199
3203
  if (sni !== null && handlerNode !== null) {
3200
- L.noLowering("createSecureServer with both an SNICallback and an eager handler", expr, "register the handler separately: server.on(\"request\", (req, res) => ...)");
3204
+ lowerer.noLowering("createSecureServer with both an SNICallback and an eager handler", expr, "register the handler separately: server.on(\"request\", (req, res) => ...)");
3201
3205
  }
3202
3206
  if (!allowHttp1) {
3203
3207
  // The REAL h2-over-TLS server (scr_http2.c + scr_tls.c): ALPN
@@ -3206,10 +3210,10 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
3206
3210
  // SNI callbacks are an https-path feature; the h2 stack serves one
3207
3211
  // cert/key pair.
3208
3212
  if (sni !== null) {
3209
- L.noLowering("createSecureServer with an SNICallback and no allowHTTP1", optsNode, "SNICallback lowers on the dual allowHTTP1 server — the h2-only server serves one cert/key pair");
3213
+ lowerer.noLowering("createSecureServer with an SNICallback and no allowHTTP1", optsNode, "SNICallback lowers on the dual allowHTTP1 server — the h2-only server serves one cert/key pair");
3210
3214
  }
3211
3215
  if (handlerNode !== null) {
3212
- const cb = lowerRequestHandlerArg(L, handlerNode);
3216
+ const cb = lowerRequestHandlerArg(lowerer, handlerNode);
3213
3217
  return { kind: "libCall", fn: "http2.createSecureServerH2Req", args: [cert, key, cb, boolLit(enableConnectProtocol, loc)], type: NETSERVER_T, loc };
3214
3218
  }
3215
3219
  return { kind: "libCall", fn: "http2.createSecureServerH2", args: [cert, key, boolLit(enableConnectProtocol, loc)], type: NETSERVER_T, loc };
@@ -3218,13 +3222,13 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
3218
3222
  return { kind: "libCall", fn: "http2.createSecureServerSni", args: [cert, key, sni, boolLit(enableConnectProtocol, loc)], type: NETSERVER_T, loc };
3219
3223
  }
3220
3224
  if (handlerNode !== null) {
3221
- const cb = lowerRequestHandlerArg(L, handlerNode);
3225
+ const cb = lowerRequestHandlerArg(lowerer, handlerNode);
3222
3226
  return { kind: "libCall", fn: "http2.createSecureServerReq", args: [cert, key, cb, boolLit(enableConnectProtocol, loc)], type: NETSERVER_T, loc };
3223
3227
  }
3224
3228
  return { kind: "libCall", fn: "http2.createSecureServer", args: [cert, key, boolLit(enableConnectProtocol, loc)], type: NETSERVER_T, loc };
3225
3229
  }
3226
- L.noLowering(`http2.${bi.member}`, expr, builtinFenceHintOf("http2", bi.member) ??
3227
- "createSecureServer({ allowHTTP1: true, cert, key }) and the h2-only form are lowered", L.resolveValueSymbol(expr.expression));
3230
+ lowerer.noLowering(`http2.${bi.member}`, expr, builtinFenceHintOf("http2", bi.member) ??
3231
+ "createSecureServer({ allowHTTP1: true, cert, key }) and the h2-only form are lowered", lowerer.resolveValueSymbol(expr.expression));
3228
3232
  }
3229
3233
  /** http.request(options[, cb]) / http.get(options[, cb]) — the client.
3230
3234
  * The options argument must be an OBJECT LITERAL; the lowered keys are
@@ -3244,24 +3248,24 @@ function lowerHttp2ModuleCall(L, expr, bi, loc) {
3244
3248
  * supported options SPREAD is the conditional `...(c ? {
3245
3249
  * rejectUnauthorized: <bool> } : {})` (either orientation) — the
3246
3250
  * portless isProxyRunning shape. */
3247
- function lowerHttpClientCall(L, expr, member, loc, secure = false) {
3251
+ function lowerHttpClientCall(lowerer, expr, member, loc, secure = false) {
3248
3252
  const binding = typeof secure === "object" ? secure : null;
3249
3253
  const secureish = binding !== null || secure === true;
3250
3254
  /** A FRESH lowering of the binding's secure condition (pure identifier
3251
3255
  * read — each use is its own IR). */
3252
3256
  const secureExpr = () => {
3253
- const c = L.lowerCondition(binding.cond);
3257
+ const c = lowerer.lowerCondition(binding.cond);
3254
3258
  return binding.trueSecure
3255
3259
  ? c
3256
3260
  : { kind: "unary", op: "!", operand: c, type: BOOL, loc };
3257
3261
  };
3258
3262
  const args = expr.arguments;
3259
3263
  if (args.length < 1 || args.length > 2) {
3260
- L.noLowering(`${member} with ${args.length} arguments`, expr, `the supported form is ${member}(options[, callback])`);
3264
+ lowerer.noLowering(`${member} with ${args.length} arguments`, expr, `the supported form is ${member}(options[, callback])`);
3261
3265
  }
3262
3266
  const optsNode = args[0];
3263
3267
  if (!ts.isObjectLiteralExpression(optsNode)) {
3264
- const t = L.mapTypeOf(L.typeOf(optsNode));
3268
+ const t = lowerer.mapTypeOf(lowerer.typeOf(optsNode));
3265
3269
  if ((t?.kind === "string" || t?.kind === "url") && binding === null) {
3266
3270
  // The URL-string form — http.get(`http://127.0.0.1:${port}/x`[, cb])
3267
3271
  // and its https spelling: the runtime parses through the WHATWG unit
@@ -3274,8 +3278,8 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
3274
3278
  // A URL OBJECT is its href through the same parse — Node's own
3275
3279
  // reading of the argument, and the serialization round-trips.
3276
3280
  const url = t.kind === "url"
3277
- ? { kind: "libCall", fn: "url.href", args: [L.lowerExpr(optsNode)], type: STRING, loc }
3278
- : L.lowerExprExpecting(optsNode, STRING);
3281
+ ? { kind: "libCall", fn: "url.href", args: [lowerer.lowerExpr(optsNode)], type: STRING, loc }
3282
+ : lowerer.lowerExprExpecting(optsNode, STRING);
3279
3283
  const methodLit = { kind: "strLit", value: "GET", type: STRING, loc };
3280
3284
  const autoEnd = boolLit(member === "get", loc);
3281
3285
  const isTls = secure === true;
@@ -3283,11 +3287,11 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
3283
3287
  const fn = isTls ? "https.requestUrl" : "http.requestUrl";
3284
3288
  return { kind: "libCall", fn, args: [url, methodLit, autoEnd], type: HTTPCLIENTREQ_T, loc };
3285
3289
  }
3286
- const { cb } = lowerCallbackArg(L, args[1], "response callbacks", 1, (p) => p.kind === "httpReq", "use (res) or ()", [HTTPREQ_T]);
3290
+ const { cb } = lowerCallbackArg(lowerer, args[1], "response callbacks", 1, (p) => p.kind === "httpReq", "use (res) or ()", [HTTPREQ_T]);
3287
3291
  const fn = isTls ? "https.requestUrlCb" : "http.requestUrlCb";
3288
3292
  return { kind: "libCall", fn, args: [url, methodLit, autoEnd, cb], type: HTTPCLIENTREQ_T, loc };
3289
3293
  }
3290
- L.noLowering(t?.kind === "string"
3294
+ lowerer.noLowering(t?.kind === "string"
3291
3295
  ? `a URL-string first argument through a request-function binding`
3292
3296
  : `${member} with a non-literal options argument`, optsNode, t?.kind === "string"
3293
3297
  // Only the binding mode reaches here now: the scheme would have to
@@ -3324,10 +3328,10 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
3324
3328
  if (cs !== null && cs !== "unsupported" && cs.props.length === 1 &&
3325
3329
  cs.props[0].name.text === "rejectUnauthorized" &&
3326
3330
  ts.isPropertyAssignment(cs.props[0]) && secureish) {
3327
- const cond = L.lowerCondition(cs.cond);
3328
- const v = L.lowerExpr(cs.props[0].initializer);
3331
+ const cond = lowerer.lowerCondition(cs.cond);
3332
+ const v = lowerer.lowerExpr(cs.props[0].initializer);
3329
3333
  if (v.type.kind !== "bool") {
3330
- L.noLowering(`a ${member} 'rejectUnauthorized' option of '${L.fmt(v.type)}' values`, cs.props[0], "the option value must be a boolean");
3334
+ lowerer.noLowering(`a ${member} 'rejectUnauthorized' option of '${lowerer.fmt(v.type)}' values`, cs.props[0], "the option value must be a boolean");
3331
3335
  }
3332
3336
  const dflt = boolLit(true, loc); /* Node's default: verify */
3333
3337
  reject = {
@@ -3340,7 +3344,7 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
3340
3344
  };
3341
3345
  continue;
3342
3346
  }
3343
- L.noLowering(`${member} with this options spread`, prop, secureish
3347
+ lowerer.noLowering(`${member} with this options spread`, prop, secureish
3344
3348
  ? "the one supported spread is the conditional `...(c ? { rejectUnauthorized: <bool> } : {})` (either orientation) — write other members inline"
3345
3349
  : "spreads have no lowering here — write each option inline");
3346
3350
  }
@@ -3353,13 +3357,13 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
3353
3357
  initializer = null;
3354
3358
  }
3355
3359
  else {
3356
- L.noLowering(`${member} options with computed keys`, prop, "each option must be a plain `name: value` (or shorthand) entry with a literal key");
3360
+ lowerer.noLowering(`${member} options with computed keys`, prop, "each option must be a plain `name: value` (or shorthand) entry with a literal key");
3357
3361
  }
3358
3362
  const key = prop.name.text;
3359
3363
  const lowerVal = (want) => {
3360
3364
  const v = initializer !== null
3361
- ? L.lowerExpr(initializer)
3362
- : L.lowerShorthandValue(prop);
3365
+ ? lowerer.lowerExpr(initializer)
3366
+ : lowerer.lowerShorthandValue(prop);
3363
3367
  // A checked-dynamic value (an untyped JS binding carrying the
3364
3368
  // port/path through a helper): dynCheck validates it into the
3365
3369
  // option's type — a mismatch is the catchable path-annotated
@@ -3368,7 +3372,7 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
3368
3372
  return { kind: "dynCheck", value: v, type: want === "string" ? STRING : F64, loc: locOf(prop) };
3369
3373
  }
3370
3374
  if (v.type.kind !== want) {
3371
- L.noLowering(`a ${member} '${key}' option of '${L.fmt(v.type)}' values`, prop, want === "string" ? "the option value must be a string" : "the option value must be a number");
3375
+ lowerer.noLowering(`a ${member} '${key}' option of '${lowerer.fmt(v.type)}' values`, prop, want === "string" ? "the option value must be a string" : "the option value must be a number");
3372
3376
  }
3373
3377
  return v;
3374
3378
  };
@@ -3391,9 +3395,9 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
3391
3395
  break;
3392
3396
  case "headers":
3393
3397
  if (initializer === null) {
3394
- L.noLowering(`${member} with a shorthand headers option`, prop, "spell it out: headers: theHeaders");
3398
+ lowerer.noLowering(`${member} with a shorthand headers option`, prop, "spell it out: headers: theHeaders");
3395
3399
  }
3396
- headers = lowerClientHeadersOption(L, initializer);
3400
+ headers = lowerClientHeadersOption(lowerer, initializer);
3397
3401
  break;
3398
3402
  case "createConnection": {
3399
3403
  // The caller's own dialer: a `() => net.Socket` closure the
@@ -3401,40 +3405,40 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
3401
3405
  // dial). https keeps the fence — the TLS client owns its socket —
3402
3406
  // and the binding mode inherits it (its https arm would).
3403
3407
  if (secureish) {
3404
- L.noLowering(`${member} with a createConnection option`, prop, "the https client dials its own TLS socket — pass hostname/port");
3408
+ lowerer.noLowering(`${member} with a createConnection option`, prop, "the https client dials its own TLS socket — pass hostname/port");
3405
3409
  }
3406
3410
  if (initializer === null) {
3407
- L.noLowering(`${member} with a shorthand createConnection option`, prop, "spell it out: createConnection: theDialer");
3411
+ lowerer.noLowering(`${member} with a shorthand createConnection option`, prop, "spell it out: createConnection: theDialer");
3408
3412
  }
3409
- const v = L.lowerExpr(initializer);
3413
+ const v = lowerer.lowerExpr(initializer);
3410
3414
  if (v.type.kind !== "func" || v.type.params.length !== 0 || v.type.ret.kind !== "netSocket") {
3411
- L.noLowering(`a ${member} 'createConnection' option of '${L.fmt(v.type)}' values`, prop, "the dialer is () => net.Socket — no arguments, returning the socket to use");
3415
+ lowerer.noLowering(`a ${member} 'createConnection' option of '${lowerer.fmt(v.type)}' values`, prop, "the dialer is () => net.Socket — no arguments, returning the socket to use");
3412
3416
  }
3413
3417
  connCb = v;
3414
3418
  break;
3415
3419
  }
3416
3420
  case "rejectUnauthorized": {
3417
3421
  if (!secureish) {
3418
- L.noLowering(`${member} option 'rejectUnauthorized'`, prop, "rejectUnauthorized is an https.request option — the plain http client has no TLS layer");
3422
+ lowerer.noLowering(`${member} option 'rejectUnauthorized'`, prop, "rejectUnauthorized is an https.request option — the plain http client has no TLS layer");
3419
3423
  }
3420
3424
  const v = initializer !== null
3421
- ? L.lowerExpr(initializer)
3422
- : L.lowerShorthandValue(prop);
3425
+ ? lowerer.lowerExpr(initializer)
3426
+ : lowerer.lowerShorthandValue(prop);
3423
3427
  if (v.type.kind !== "bool") {
3424
- L.noLowering(`a ${member} 'rejectUnauthorized' option of '${L.fmt(v.type)}' values`, prop, "the option value must be a boolean");
3428
+ lowerer.noLowering(`a ${member} 'rejectUnauthorized' option of '${lowerer.fmt(v.type)}' values`, prop, "the option value must be a boolean");
3425
3429
  }
3426
3430
  reject = v;
3427
3431
  break;
3428
3432
  }
3429
3433
  case "ca": {
3430
3434
  if (!secureish) {
3431
- L.noLowering(`${member} option 'ca'`, prop, "ca is an https.request option — the plain http client has no TLS layer");
3435
+ lowerer.noLowering(`${member} option 'ca'`, prop, "ca is an https.request option — the plain http client has no TLS layer");
3432
3436
  }
3433
3437
  const v = initializer !== null
3434
- ? L.lowerExpr(initializer)
3435
- : L.lowerShorthandValue(prop);
3438
+ ? lowerer.lowerExpr(initializer)
3439
+ : lowerer.lowerShorthandValue(prop);
3436
3440
  if (v.type.kind !== "string" && !(v.type.kind === "bytes" && v.type.elem === "u8")) {
3437
- L.noLowering(`a ${member} 'ca' option of '${L.fmt(v.type)}' values`, prop, "the ca is a PEM string or Buffer here");
3441
+ lowerer.noLowering(`a ${member} 'ca' option of '${lowerer.fmt(v.type)}' values`, prop, "the ca is a PEM string or Buffer here");
3438
3442
  }
3439
3443
  ca = v;
3440
3444
  break;
@@ -3461,17 +3465,17 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
3461
3465
  break; // the default agent: what the agent-free call compiles
3462
3466
  }
3463
3467
  const v = initializer !== null
3464
- ? L.lowerExpr(initializer)
3465
- : L.lowerShorthandValue(prop);
3468
+ ? lowerer.lowerExpr(initializer)
3469
+ : lowerer.lowerShorthandValue(prop);
3466
3470
  if (v.type.kind !== "dyn") {
3467
- L.noLowering(`a ${member} 'agent' option of '${L.fmt(v.type)}' values`, prop, "the agent is the checked-dynamic Agent handle new http.Agent(...) answers " +
3471
+ lowerer.noLowering(`a ${member} 'agent' option of '${lowerer.fmt(v.type)}' values`, prop, "the agent is the checked-dynamic Agent handle new http.Agent(...) answers " +
3468
3472
  "(or false / null / undefined)");
3469
3473
  }
3470
3474
  agentVal = v;
3471
3475
  break;
3472
3476
  }
3473
3477
  default:
3474
- fenceOrDropOptionKey(L, prop, key, member, secureish ? HTTPS_CLIENT_DOCUMENTED_OPTIONS : HTTP_CLIENT_DOCUMENTED_OPTIONS, secureish
3478
+ fenceOrDropOptionKey(lowerer, prop, key, member, secureish ? HTTPS_CLIENT_DOCUMENTED_OPTIONS : HTTP_CLIENT_DOCUMENTED_OPTIONS, secureish
3475
3479
  ? "hostname/host, port, path, method, timeout, headers, agent, rejectUnauthorized, and ca are the supported options"
3476
3480
  : "hostname/host, port, path, method, timeout, headers, and agent are the supported options");
3477
3481
  }
@@ -3483,46 +3487,43 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
3483
3487
  // lowering. A user-set connection header wins, Node's rule; a
3484
3488
  // non-literal headers record cannot be checked for one, so the combo
3485
3489
  // fences instead of double-sending.
3486
- const strLitAt = (value) => ({ kind: "strLit", value, type: STRING, loc });
3487
3490
  if (headers === null) {
3488
- headers = { kind: "arrayLit", elems: [strLitAt("Connection"), strLitAt("close")], type: arrayOf(STRING), loc };
3491
+ headers = { kind: "arrayLit", elems: [strLit("Connection", loc), strLit("close", loc)], type: arrayOf(STRING), loc };
3489
3492
  }
3490
3493
  else if (headers.kind === "arrayLit") {
3491
3494
  const hasConnection = headers.elems.some((el, i) => i % 2 === 0 && el.kind === "strLit" && el.value.toLowerCase() === "connection");
3492
3495
  if (!hasConnection) {
3493
- headers = { ...headers, elems: [...headers.elems, strLitAt("Connection"), strLitAt("close")] };
3496
+ headers = { ...headers, elems: [...headers.elems, strLit("Connection", loc), strLit("close", loc)] };
3494
3497
  }
3495
3498
  }
3496
3499
  else {
3497
- L.noLowering(`${member} with agent: false and a non-literal headers record`, agentClose, "agent: false lowers by injecting Connection: close into a LITERAL headers object — " +
3500
+ lowerer.noLowering(`${member} with agent: false and a non-literal headers record`, agentClose, "agent: false lowers by injecting Connection: close into a LITERAL headers object — " +
3498
3501
  "add connection: \"close\" to the record instead, or write the headers inline");
3499
3502
  }
3500
3503
  }
3501
- const strLit = (value) => ({ kind: "strLit", value, type: STRING, loc });
3502
- const numLit = (value) => ({ kind: "numLit", value, type: F64, loc });
3503
3504
  if (connCb !== null && (host !== null || port !== null)) {
3504
3505
  // Node would use host/port only for the Host header once a dialer
3505
3506
  // exists — a silent half-use; set headers.host instead.
3506
- L.noLowering(`${member} mixing createConnection with hostname/host/port`, optsNode, "the dialer supplies the socket — set the Host header via headers: { host: ... } instead");
3507
+ lowerer.noLowering(`${member} mixing createConnection with hostname/host/port`, optsNode, "the dialer supplies the socket — set the Host header via headers: { host: ... } instead");
3507
3508
  }
3508
3509
  if (agentVal !== null && connCb !== null) {
3509
- L.noLowering(`${member} mixing an agent value with createConnection`, optsNode, "both own the dial — pass one or the other");
3510
+ lowerer.noLowering(`${member} mixing an agent value with createConnection`, optsNode, "both own the dial — pass one or the other");
3510
3511
  }
3511
3512
  if (agentVal !== null && binding !== null) {
3512
- L.noLowering(`${member} through a module-function binding with an agent value`, optsNode, "call http.request/https.request directly when passing an Agent");
3513
+ lowerer.noLowering(`${member} through a module-function binding with an agent value`, optsNode, "call http.request/https.request directly when passing an Agent");
3513
3514
  }
3514
- host ??= strLit("localhost");
3515
+ host ??= strLit("localhost", loc);
3515
3516
  // The binding mode's default port follows the runtime dial: 443 on the
3516
3517
  // TLS arm, 80 on the plain one — exactly each client's own default.
3517
3518
  // With an AGENT the sentinel -1 says "no port option": the runtime
3518
3519
  // consults the agent's (settable) defaultPort first, Node's merge.
3519
3520
  port ??= binding !== null
3520
- ? { kind: "ternary", cond: secureExpr(), then: numLit(443), else_: numLit(80), type: F64, loc }
3521
- : agentVal !== null ? numLit(-1)
3522
- : numLit(secure === true ? 443 : 80);
3523
- path ??= strLit("/");
3524
- method ??= strLit("GET");
3525
- timeout ??= numLit(0);
3521
+ ? { kind: "ternary", cond: secureExpr(), then: numLit(443, loc), else_: numLit(80, loc), type: F64, loc }
3522
+ : agentVal !== null ? numLit(-1, loc)
3523
+ : numLit(secure === true ? 443 : 80, loc);
3524
+ path ??= strLit("/", loc);
3525
+ method ??= strLit("GET", loc);
3526
+ timeout ??= numLit(0, loc);
3526
3527
  headers ??= { kind: "arrayLit", elems: [], type: arrayOf(STRING), loc };
3527
3528
  const autoEnd = boolLit(member === "get", loc);
3528
3529
  if (connCb !== null) {
@@ -3530,13 +3531,13 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
3530
3531
  if (args.length === 1) {
3531
3532
  return { kind: "libCall", fn: "http.requestConn", args: base, type: HTTPCLIENTREQ_T, loc };
3532
3533
  }
3533
- const { cb } = lowerCallbackArg(L, args[1], "response callbacks", 1, (p) => p.kind === "httpReq", "use (res) or ()", [HTTPREQ_T]);
3534
+ const { cb } = lowerCallbackArg(lowerer, args[1], "response callbacks", 1, (p) => p.kind === "httpReq", "use (res) or ()", [HTTPREQ_T]);
3534
3535
  return { kind: "libCall", fn: "http.requestConnCb", args: [...base, cb], type: HTTPCLIENTREQ_T, loc };
3535
3536
  }
3536
3537
  const base = [host, port, path, method, timeout, headers, autoEnd];
3537
3538
  if (secureish) {
3538
3539
  reject ??= boolLit(true, loc); /* Node's default: verify */
3539
- ca ??= strLit(""); /* none: /etc/ssl/cert.pem stands in for Node's roots */
3540
+ ca ??= strLit("", loc); /* none: /etc/ssl/cert.pem stands in for Node's roots */
3540
3541
  base.push(reject, ca);
3541
3542
  }
3542
3543
  if (agentVal !== null)
@@ -3549,7 +3550,7 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
3549
3550
  : agentVal !== null ? "http.requestAgent" : "http.request";
3550
3551
  return { kind: "libCall", fn, args: base, type: HTTPCLIENTREQ_T, loc };
3551
3552
  }
3552
- const { cb } = lowerCallbackArg(L, args[1], "response callbacks", 1, (p) => p.kind === "httpReq", "use (res) or ()", [HTTPREQ_T]);
3553
+ const { cb } = lowerCallbackArg(lowerer, args[1], "response callbacks", 1, (p) => p.kind === "httpReq", "use (res) or ()", [HTTPREQ_T]);
3553
3554
  const fn = binding !== null ? "https.requestFnCb"
3554
3555
  : secure === true ? (agentVal !== null ? "https.requestAgentCb" : "https.requestCb")
3555
3556
  : agentVal !== null ? "http.requestAgentCb" : "http.requestCb";
@@ -3560,60 +3561,60 @@ function lowerHttpClientCall(L, expr, member, loc, secure = false) {
3560
3561
  * array directly; any other expression must be a Record whose values are
3561
3562
  * strings (or `string | undefined` — absent entries drop, the env-option
3562
3563
  * rule), flattened by the interned env.pairs helper. */
3563
- function lowerClientHeadersOption(L, node) {
3564
+ function lowerClientHeadersOption(lowerer, node) {
3564
3565
  const loc = locOf(node);
3565
3566
  if (ts.isObjectLiteralExpression(node)) {
3566
3567
  const elems = [];
3567
3568
  for (const prop of node.properties) {
3568
- const key = ts.isPropertyAssignment(prop) ? staticHeaderKeyOf(L, prop) : null;
3569
+ const key = ts.isPropertyAssignment(prop) ? staticHeaderKeyOf(lowerer, prop) : null;
3569
3570
  if (!ts.isPropertyAssignment(prop) || key === null) {
3570
- L.noLowering("request headers with dynamic keys, spreads, or shorthand entries", prop, "each header must be a `name: value` entry whose key is a literal (or a string-literal-typed const: [PORTLESS_HEADER])");
3571
+ lowerer.noLowering("request headers with dynamic keys, spreads, or shorthand entries", prop, "each header must be a `name: value` entry whose key is a literal (or a string-literal-typed const: [PORTLESS_HEADER])");
3571
3572
  }
3572
- let value = L.lowerExpr(prop.initializer);
3573
+ let value = lowerer.lowerExpr(prop.initializer);
3573
3574
  if (value.type.kind === "f64") {
3574
3575
  // Node formats number values via String(n) — the same ToString.
3575
3576
  value = { kind: "toString", operand: value, type: STRING, loc };
3576
3577
  }
3577
3578
  if (value.type.kind !== "string") {
3578
- L.noLowering(`request header values of type '${L.fmt(value.type)}'`, prop.initializer, "header values are strings or numbers here");
3579
+ lowerer.noLowering(`request header values of type '${lowerer.fmt(value.type)}'`, prop.initializer, "header values are strings or numbers here");
3579
3580
  }
3580
3581
  elems.push({ kind: "strLit", value: key, type: STRING, loc });
3581
3582
  elems.push(value);
3582
3583
  }
3583
3584
  return { kind: "arrayLit", elems, type: arrayOf(STRING), loc };
3584
3585
  }
3585
- const v = L.lowerExpr(node);
3586
+ const v = lowerer.lowerExpr(node);
3586
3587
  if (v.type.kind !== "record") {
3587
- L.noLowering(`request headers of '${L.fmt(v.type)}' values`, node, "pass an object literal or a Record<string, string>");
3588
+ lowerer.noLowering(`request headers of '${lowerer.fmt(v.type)}' values`, node, "pass an object literal or a Record<string, string>");
3588
3589
  }
3589
- const helper = L.envToPairsHelper(v.type.shapeId, loc);
3590
+ const helper = lowerer.envToPairsHelper(v.type.shapeId, loc);
3590
3591
  if (helper === null) {
3591
- L.noLowering(`request headers of '${L.fmt(v.type)}' values`, node, "header values must be strings (or string | undefined)");
3592
+ lowerer.noLowering(`request headers of '${lowerer.fmt(v.type)}' values`, node, "header values must be strings (or string | undefined)");
3592
3593
  }
3593
3594
  return { kind: "call", callee: helper, args: [v], type: arrayOf(STRING), loc };
3594
3595
  }
3595
3596
  /** Method calls on ClientRequest receivers: write/end/destroy and
3596
3597
  * on/once("response" | "error" | "timeout" | "close"). Null for other
3597
3598
  * receivers. */
3598
- function lowerHttpClientMethodCall(L, call, access) {
3599
- if (L.mapTypeOf(L.typeOf(access.expression))?.kind !== "httpClientReq")
3599
+ function lowerHttpClientMethodCall(lowerer, call, access) {
3600
+ if (lowerer.mapTypeOf(lowerer.typeOf(access.expression))?.kind !== "httpClientReq")
3600
3601
  return null;
3601
- if (!L.isStdlibMember(access))
3602
+ if (!lowerer.isStdlibMember(access))
3602
3603
  return null;
3603
3604
  const name = access.name.text;
3604
3605
  const loc = locOf(call);
3605
3606
  const args = call.arguments;
3606
3607
  if (name === "write" || name === "end") {
3607
- requireStatementPosition(L, call, `request.${name}(...)`);
3608
+ requireStatementPosition(lowerer, call, `request.${name}(...)`);
3608
3609
  const minArgs = name === "write" ? 1 : 0;
3609
3610
  if (args.length < minArgs || args.length > 1) {
3610
- L.noLowering(`${name} with ${args.length} arguments`, call, name === "write" ? "the supported form is write(data)" : "the supported forms are end() and end(data)");
3611
+ lowerer.noLowering(`${name} with ${args.length} arguments`, call, name === "write" ? "the supported form is write(data)" : "the supported forms are end() and end(data)");
3611
3612
  }
3612
- const receiver = L.lowerExpr(access.expression);
3613
+ const receiver = lowerer.lowerExpr(access.expression);
3613
3614
  if (args.length === 0) {
3614
3615
  return { kind: "libCall", fn: "http.clientEnd", args: [receiver], type: VOID, loc };
3615
3616
  }
3616
- const data = L.lowerExpr(args[0]);
3617
+ const data = lowerer.lowerExpr(args[0]);
3617
3618
  if (data.type.kind === "string") {
3618
3619
  const fn = name === "write" ? "http.clientWrite" : "http.clientEndStr";
3619
3620
  return { kind: "libCall", fn, args: [receiver, data], type: VOID, loc };
@@ -3627,32 +3628,32 @@ function lowerHttpClientMethodCall(L, call, access) {
3627
3628
  const fn = name === "write" ? "http.clientWriteBytes" : "http.clientEndBytes";
3628
3629
  return { kind: "libCall", fn, args: [receiver, data], type: VOID, loc };
3629
3630
  }
3630
- L.noLowering(`${name} of '${L.fmt(data.type)}' data`, args[0] ?? call, NARROW_DATA_HINT);
3631
+ lowerer.noLowering(`${name} of '${lowerer.fmt(data.type)}' data`, args[0] ?? call, NARROW_DATA_HINT);
3631
3632
  }
3632
3633
  if (name === "destroy") {
3633
- requireStatementPosition(L, call, "request.destroy()");
3634
+ requireStatementPosition(lowerer, call, "request.destroy()");
3634
3635
  if (args.length !== 0) {
3635
- L.noLowering(`destroy with ${args.length} arguments`, call, "destroy() takes no arguments here");
3636
+ lowerer.noLowering(`destroy with ${args.length} arguments`, call, "destroy() takes no arguments here");
3636
3637
  }
3637
- const receiver = L.lowerExpr(access.expression);
3638
+ const receiver = lowerer.lowerExpr(access.expression);
3638
3639
  return { kind: "libCall", fn: "http.clientDestroy", args: [receiver], type: VOID, loc };
3639
3640
  }
3640
3641
  if ((name === "on" || name === "once" || name === "addListener") && args.length === 2) {
3641
- requireStatementPosition(L, call, `request.${name}(...)`);
3642
+ requireStatementPosition(lowerer, call, `request.${name}(...)`);
3642
3643
  const once = boolLit(name === "once", loc);
3643
- const evT = L.typeOf(args[0]);
3644
+ const evT = lowerer.typeOf(args[0]);
3644
3645
  const event = evT.isStringLiteralType() ? evT.value : null;
3645
- const receiver = L.lowerExpr(access.expression);
3646
+ const receiver = lowerer.lowerExpr(access.expression);
3646
3647
  if (event === "response") {
3647
- const { cb } = lowerCallbackArg(L, args[1], "response listeners", 1, (p) => p.kind === "httpReq", "use (res) or ()", [HTTPREQ_T]);
3648
+ const { cb } = lowerCallbackArg(lowerer, args[1], "response listeners", 1, (p) => p.kind === "httpReq", "use (res) or ()", [HTTPREQ_T]);
3648
3649
  return { kind: "libCall", fn: "http.clientOnResponse", args: [receiver, cb, once], type: VOID, loc };
3649
3650
  }
3650
3651
  if (event === "error") {
3651
- const { cb } = lowerCallbackArg(L, args[1], "error listeners", 1, (p) => p.kind === "object" && p.className === "%Error", "use (err) or ()", [ERROR_T]);
3652
+ const { cb } = lowerCallbackArg(lowerer, args[1], "error listeners", 1, (p) => p.kind === "object" && p.className === "%Error", "use (err) or ()", [ERROR_T]);
3652
3653
  return { kind: "libCall", fn: "http.clientOnError", args: [receiver, cb, once], type: VOID, loc };
3653
3654
  }
3654
3655
  if (event === "timeout" || event === "close") {
3655
- const { cb } = lowerCallbackArg(L, args[1], `${event} listeners`, 0, () => false, "use ()", []);
3656
+ const { cb } = lowerCallbackArg(lowerer, args[1], `${event} listeners`, 0, () => false, "use ()", []);
3656
3657
  const fn = event === "timeout" ? "http.clientOnTimeout" : "http.clientOnClose";
3657
3658
  return { kind: "libCall", fn, args: [receiver, cb, once], type: VOID, loc };
3658
3659
  }
@@ -3660,24 +3661,24 @@ function lowerHttpClientMethodCall(L, call, access) {
3660
3661
  // The client half of the WebSocket handover: a 101 response fires
3661
3662
  // (res, socket, head) INSTEAD of 'response'; no listener destroys
3662
3663
  // the connection, Node's default.
3663
- const cb = L.lowerExpr(args[1]);
3664
+ const cb = lowerer.lowerExpr(args[1]);
3664
3665
  if (cb.type.kind !== "func" || cb.type.params.length > 3) {
3665
- L.unsupported("SC1090", args[1], "upgrade listeners with more than three parameters (use (res, socket, head))");
3666
+ lowerer.unsupported("SC1090", args[1], "upgrade listeners with more than three parameters (use (res, socket, head))");
3666
3667
  }
3667
3668
  if (cb.type.ret.kind !== "void") {
3668
- L.unsupported("SC1090", args[1], "upgrade listeners returning a value (make the callback body a block)");
3669
+ lowerer.unsupported("SC1090", args[1], "upgrade listeners returning a value (make the callback body a block)");
3669
3670
  }
3670
3671
  const [p0, p1, p2] = cb.type.params;
3671
3672
  if ((p0 !== undefined && p0.kind !== "httpReq") ||
3672
3673
  (p1 !== undefined && p1.kind !== "netSocket") ||
3673
3674
  (p2 !== undefined && !(p2.kind === "bytes" && p2.elem === "u8"))) {
3674
- L.unsupported("SC1090", args[1], "upgrade listeners whose parameters are not (res: IncomingMessage, socket: Socket, head: Buffer)");
3675
+ lowerer.unsupported("SC1090", args[1], "upgrade listeners whose parameters are not (res: IncomingMessage, socket: Socket, head: Buffer)");
3675
3676
  }
3676
3677
  return { kind: "libCall", fn: "http.clientOnUpgrade", args: [receiver, cb, once], type: VOID, loc };
3677
3678
  }
3678
- L.noLowering(`request.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, args[0], '"response", "upgrade", "error", "timeout", and "close" are the supported request events (as literals)');
3679
+ lowerer.noLowering(`request.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, args[0], '"response", "upgrade", "error", "timeout", and "close" are the supported request events (as literals)');
3679
3680
  }
3680
- L.noLowering(`ClientRequest.${name}`, call, "write, end, destroy, destroyed, and on/once of response/error/timeout/close are the supported ClientRequest members", L.checker.getSymbolAtLocation(access.name));
3681
+ lowerer.noLowering(`ClientRequest.${name}`, call, "write, end, destroy, destroyed, and on/once of response/error/timeout/close are the supported ClientRequest members", lowerer.checker.getSymbolAtLocation(access.name));
3681
3682
  }
3682
3683
  /** True when `node` is the h2-only stream/session CALL shape —
3683
3684
  * `req.stream.destroy()` / `req.session.m(...)` on an identifier
@@ -3687,7 +3688,7 @@ function lowerHttpClientMethodCall(L, call, access) {
3687
3688
  * req.stream.destroy()`) is a throw-only body whose declared return type
3688
3689
  * (ServerHttp2Stream, unmappable) must not decide the lambda's ABI.
3689
3690
  * lambdaSignature consults this and takes void, the `never` stance. */
3690
- export function isStreamUndefCallExpr(L, node) {
3691
+ export function isStreamUndefCallExpr(lowerer, node) {
3691
3692
  return (ts.isCallExpression(node) &&
3692
3693
  ts.isPropertyAccessExpression(node.expression) &&
3693
3694
  ts.isPropertyAccessExpression(node.expression.expression) &&
@@ -3696,81 +3697,81 @@ export function isStreamUndefCallExpr(L, node) {
3696
3697
  (node.expression.expression.name.text === "stream" ||
3697
3698
  node.expression.expression.name.text === "session") &&
3698
3699
  ts.isIdentifier(node.expression.expression.expression) &&
3699
- L.mapTypeOf(L.typeOf(node.expression.expression.expression))?.kind === "httpReq" &&
3700
- L.isStdlibMember(node.expression.expression));
3700
+ lowerer.mapTypeOf(lowerer.typeOf(node.expression.expression.expression))?.kind === "httpReq" &&
3701
+ lowerer.isStdlibMember(node.expression.expression));
3701
3702
  }
3702
3703
  /** `x instanceof net.Socket` over a UNION-typed x with a netSocket arm —
3703
3704
  * the h2 compat 'connect' listener's narrowing (`resOrSocket instanceof
3704
3705
  * net.Socket`): one runtime tag test; tsc's control-flow narrowing types
3705
3706
  * the branches and reads bridge through maybeNarrow's unionNarrow. Null
3706
3707
  * for every other shape (lower-exprs' fences stand). */
3707
- export function lowerSocketInstanceOf(L, expr, loc) {
3708
+ export function lowerSocketInstanceOf(lowerer, expr, loc) {
3708
3709
  const rhs = expr.right;
3709
3710
  const isNetSocketRef = (ts.isPropertyAccessExpression(rhs) &&
3710
3711
  rhs.name.text === "Socket" &&
3711
- L.builtinMemberOf(rhs)?.module === "net") ||
3712
- (ts.isIdentifier(rhs) && L.builtinImportOf(rhs)?.module === "net" &&
3713
- L.builtinImportOf(rhs)?.member === "Socket");
3712
+ lowerer.builtinMemberOf(rhs)?.module === "net") ||
3713
+ (ts.isIdentifier(rhs) && lowerer.builtinImportOf(rhs)?.module === "net" &&
3714
+ lowerer.builtinImportOf(rhs)?.member === "Socket");
3714
3715
  if (!isNetSocketRef)
3715
3716
  return null;
3716
- const leftT = L.mapTypeOf(L.typeOf(expr.left));
3717
+ const leftT = lowerer.mapTypeOf(lowerer.typeOf(expr.left));
3717
3718
  if (leftT?.kind !== "union")
3718
3719
  return null;
3719
- const def = L.unions.get(leftT.unionId);
3720
+ const def = lowerer.unions.get(leftT.unionId);
3720
3721
  const tag = def ? def.arms.findIndex((a) => a.kind === "netSocket") : -1;
3721
3722
  if (tag < 0)
3722
3723
  return null;
3723
- const left = L.lowerExpr(expr.left);
3724
+ const left = lowerer.lowerExpr(expr.left);
3724
3725
  if (left.type.kind !== "union" || left.type.unionId !== leftT.unionId)
3725
3726
  return null;
3726
3727
  return { kind: "unionIsTag", unionId: leftT.unionId, tag, negated: false, value: left, type: BOOL, loc };
3727
3728
  }
3728
3729
  /** True when `node` reads `.headers` off an IncomingMessage — the
3729
3730
  * receiver shape of both header-read forms. */
3730
- export function isHttpReqHeaders(L, node) {
3731
+ function isHttpReqHeaders(lowerer, node) {
3731
3732
  return (ts.isPropertyAccessExpression(node) &&
3732
3733
  !node.questionDotToken &&
3733
3734
  node.name.text === "headers" &&
3734
- L.mapTypeOf(L.typeOf(node.expression))?.kind === "httpReq" &&
3735
- L.isStdlibMember(node));
3735
+ lowerer.mapTypeOf(lowerer.typeOf(node.expression))?.kind === "httpReq" &&
3736
+ lowerer.isStdlibMember(node));
3736
3737
  }
3737
3738
  /** `req.headers["x-name"]` — the element twin of the property read below;
3738
3739
  * called from lowerElementAccess (the process.env precedent). Answers the
3739
3740
  * interned `string | undefined` union; names match case-insensitively
3740
3741
  * (the runtime stores them lowercased, like Node). */
3741
- export function lowerHttpHeadersElement(L, expr) {
3742
- if (!isHttpReqHeaders(L, expr.expression))
3742
+ export function lowerHttpHeadersElement(lowerer, expr) {
3743
+ if (!isHttpReqHeaders(lowerer, expr.expression))
3743
3744
  return null;
3744
3745
  const recv = expr.expression.expression;
3745
- const key = L.lowerExpr(expr.argumentExpression);
3746
+ const key = lowerer.lowerExpr(expr.argumentExpression);
3746
3747
  if (key.type.kind !== "string") {
3747
- L.unsupported("SC1090", expr.argumentExpression, "indexing req.headers with non-string keys");
3748
+ lowerer.unsupported("SC1090", expr.argumentExpression, "indexing req.headers with non-string keys");
3748
3749
  }
3749
- const receiver = L.lowerExpr(recv);
3750
+ const receiver = lowerer.lowerExpr(recv);
3750
3751
  return {
3751
3752
  kind: "libCall",
3752
3753
  fn: "http.reqHeader",
3753
3754
  args: [receiver, key],
3754
- type: L.envValueType(),
3755
+ type: lowerer.envValueType(),
3755
3756
  loc: locOf(expr),
3756
3757
  };
3757
3758
  }
3758
3759
  /** Method calls on IncomingMessage receivers: on/once("data" | "end").
3759
3760
  * Null for other receivers. */
3760
- function lowerHttpReqMethodCall(L, call, access) {
3761
- if (L.mapTypeOf(L.typeOf(access.expression))?.kind !== "httpReq")
3761
+ function lowerHttpReqMethodCall(lowerer, call, access) {
3762
+ if (lowerer.mapTypeOf(lowerer.typeOf(access.expression))?.kind !== "httpReq")
3762
3763
  return null;
3763
- if (!L.isStdlibMember(access))
3764
+ if (!lowerer.isStdlibMember(access))
3764
3765
  return null;
3765
3766
  const name = access.name.text;
3766
3767
  const loc = locOf(call);
3767
3768
  const args = call.arguments;
3768
3769
  if (name === "resume" || name === "destroy") {
3769
- requireStatementPosition(L, call, `req.${name}()`);
3770
+ requireStatementPosition(lowerer, call, `req.${name}()`);
3770
3771
  if (args.length !== 0) {
3771
- L.noLowering(`${name} with ${args.length} arguments`, call, `${name}() takes no arguments here`);
3772
+ lowerer.noLowering(`${name} with ${args.length} arguments`, call, `${name}() takes no arguments here`);
3772
3773
  }
3773
- const receiver = handleReceiver(L, access.expression, HTTPREQ_T);
3774
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPREQ_T);
3774
3775
  const fn = name === "resume" ? "http.reqResume" : "http.reqDestroy";
3775
3776
  return { kind: "libCall", fn, args: [receiver], type: VOID, loc };
3776
3777
  }
@@ -3778,111 +3779,121 @@ function lowerHttpReqMethodCall(L, call, access) {
3778
3779
  // setEncoding('utf8') — 'data' delivers strings (the chunk-encoding
3779
3780
  // window); other real encodings fence loudly at runtime, unknown
3780
3781
  // names throw Node's ERR_UNKNOWN_ENCODING.
3781
- requireStatementPosition(L, call, "req.setEncoding(...)");
3782
+ requireStatementPosition(lowerer, call, "req.setEncoding(...)");
3782
3783
  if (args.length !== 1) {
3783
- L.noLowering(`setEncoding with ${args.length} arguments`, call, "the supported form is setEncoding(encoding)");
3784
+ lowerer.noLowering(`setEncoding with ${args.length} arguments`, call, "the supported form is setEncoding(encoding)");
3784
3785
  }
3785
- const receiver = handleReceiver(L, access.expression, HTTPREQ_T);
3786
- const enc = L.lowerExprExpecting(args[0], STRING);
3786
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPREQ_T);
3787
+ const enc = lowerer.lowerExprExpecting(args[0], STRING);
3787
3788
  return { kind: "libCall", fn: "http.reqSetEncoding", args: [receiver, enc], type: VOID, loc };
3788
3789
  }
3789
3790
  if (name === "pipe") {
3790
3791
  // The proxy legs: req→res (the response body forward), req→clientReq
3791
3792
  // (the request body forward), req→socket (the upgrade-rejection
3792
3793
  // write) — plus socket→socket, which lives on the socket receiver.
3793
- requireStatementPosition(L, call, "req.pipe(...)");
3794
+ requireStatementPosition(lowerer, call, "req.pipe(...)");
3794
3795
  if (args.length !== 1) {
3795
- L.noLowering(`pipe with ${args.length} arguments`, call, "the supported form is pipe(destination)");
3796
+ lowerer.noLowering(`pipe with ${args.length} arguments`, call, "the supported form is pipe(destination)");
3796
3797
  }
3797
- const receiver = handleReceiver(L, access.expression, HTTPREQ_T);
3798
- const dst = L.lowerExpr(args[0]);
3798
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPREQ_T);
3799
+ const dst = lowerer.lowerExpr(args[0]);
3799
3800
  const fn = dst.type.kind === "httpRes" ? "http.reqPipeRes"
3800
3801
  : dst.type.kind === "httpClientReq" ? "http.reqPipeClient"
3801
3802
  : dst.type.kind === "netSocket" ? "http.reqPipeSock"
3802
3803
  : null;
3803
3804
  if (fn === null) {
3804
- L.noLowering(`pipe into '${L.fmt(dst.type)}' destinations`, args[0], "an IncomingMessage pipes into a ServerResponse, a ClientRequest, or a Socket");
3805
+ lowerer.noLowering(`pipe into '${lowerer.fmt(dst.type)}' destinations`, args[0], "an IncomingMessage pipes into a ServerResponse, a ClientRequest, or a Socket");
3805
3806
  }
3806
3807
  return { kind: "libCall", fn, args: [receiver, dst], type: VOID, loc };
3807
3808
  }
3808
3809
  if ((name === "on" || name === "once" || name === "addListener") && args.length === 2) {
3809
- requireStatementPosition(L, call, `req.${name}(...)`);
3810
+ requireStatementPosition(lowerer, call, `req.${name}(...)`);
3810
3811
  const once = boolLit(name === "once", loc);
3811
- const evT = L.typeOf(args[0]);
3812
+ const evT = lowerer.typeOf(args[0]);
3812
3813
  const event = evT.isStringLiteralType() ? evT.value : null;
3813
- const receiver = handleReceiver(L, access.expression, HTTPREQ_T);
3814
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPREQ_T);
3814
3815
  if (event === "data") {
3815
- const { cb } = lowerCallbackArg(L, args[1], "data listeners", 1, (p) => p.kind === "bytes" && p.elem === "u8", "use (chunk: Buffer) or ()", [DYN]);
3816
+ const { cb } = lowerCallbackArg(lowerer, args[1], "data listeners", 1, (p) => p.kind === "bytes" && p.elem === "u8", "use (chunk: Buffer) or ()", [DYN]);
3816
3817
  return { kind: "libCall", fn: "http.reqOnData", args: [receiver, cb, once], type: VOID, loc };
3817
3818
  }
3818
3819
  if (event === "end") {
3819
- const { cb } = lowerCallbackArg(L, args[1], "end listeners", 0, () => false, "use ()", []);
3820
+ const { cb } = lowerCallbackArg(lowerer, args[1], "end listeners", 0, () => false, "use ()", []);
3820
3821
  return { kind: "libCall", fn: "http.reqOnEnd", args: [receiver, cb, once], type: VOID, loc };
3821
3822
  }
3822
3823
  if (event === "error") {
3823
- const { cb } = lowerCallbackArg(L, args[1], "error listeners", 1, (p) => p.kind === "object" && p.className === "%Error", "use (err) or ()", [ERROR_T]);
3824
+ const { cb } = lowerCallbackArg(lowerer, args[1], "error listeners", 1, (p) => p.kind === "object" && p.className === "%Error", "use (err) or ()", [ERROR_T]);
3824
3825
  return { kind: "libCall", fn: "http.reqOnError", args: [receiver, cb, once], type: VOID, loc };
3825
3826
  }
3826
3827
  if (event === "close") {
3827
- const { cb } = lowerCallbackArg(L, args[1], "close listeners", 0, () => false, "use ()", []);
3828
+ const { cb } = lowerCallbackArg(lowerer, args[1], "close listeners", 0, () => false, "use ()", []);
3828
3829
  return { kind: "libCall", fn: "http.reqOnClose", args: [receiver, cb, once], type: VOID, loc };
3829
3830
  }
3830
3831
  if (event === "aborted") {
3831
3832
  // The h2 compat event (Http2ServerRequest 'aborted'); an http/1
3832
3833
  // request registers too and never fires — the parser lane's story.
3833
- const { cb } = lowerCallbackArg(L, args[1], "aborted listeners", 0, () => false, "use ()", []);
3834
+ const { cb } = lowerCallbackArg(lowerer, args[1], "aborted listeners", 0, () => false, "use ()", []);
3834
3835
  return { kind: "libCall", fn: "http.reqOnAborted", args: [receiver, cb, once], type: VOID, loc };
3835
3836
  }
3836
- L.noLowering(`req.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, args[0], '"data", "end", "error", "close", and "aborted" are the supported request events (as literals)');
3837
+ lowerer.noLowering(`req.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, args[0], '"data", "end", "error", "close", and "aborted" are the supported request events (as literals)');
3837
3838
  }
3838
- L.noLowering(`IncomingMessage.${name}`, call, "url, method, statusCode, statusMessage, socket, headers/rawHeaders reads, resume, destroy, pipe, and on/once of data/end/error/close are the supported IncomingMessage members", L.checker.getSymbolAtLocation(access.name));
3839
+ lowerer.noLowering(`IncomingMessage.${name}`, call, "url, method, statusCode, statusMessage, socket, headers/rawHeaders reads, resume, destroy, pipe, and on/once of data/end/error/close are the supported IncomingMessage members", lowerer.checker.getSymbolAtLocation(access.name));
3839
3840
  }
3840
3841
  /** Method calls on ServerResponse receivers: setHeader/writeHead/write/
3841
3842
  * end. Null for other receivers. */
3842
- function lowerHttpResMethodCall(L, call, access) {
3843
- if (L.mapTypeOf(L.typeOf(access.expression))?.kind !== "httpRes")
3843
+ function lowerHttpResMethodCall(lowerer, call, access) {
3844
+ if (lowerer.mapTypeOf(lowerer.typeOf(access.expression))?.kind !== "httpRes")
3844
3845
  return null;
3845
- if (!L.isStdlibMember(access))
3846
+ if (!lowerer.isStdlibMember(access))
3846
3847
  return null;
3847
3848
  const name = access.name.text;
3848
3849
  const loc = locOf(call);
3849
3850
  const args = call.arguments;
3850
3851
  if (name === "setHeader") {
3851
- requireStatementPosition(L, call, "res.setHeader(...)");
3852
+ requireStatementPosition(lowerer, call, "res.setHeader(...)");
3852
3853
  if (args.length !== 2) {
3853
- L.noLowering(`setHeader with ${args.length} arguments`, call, "the supported form is setHeader(name, value)");
3854
+ lowerer.noLowering(`setHeader with ${args.length} arguments`, call, "the supported form is setHeader(name, value)");
3855
+ }
3856
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPRES_T);
3857
+ const header = lowerer.lowerExprExpecting(args[0], STRING);
3858
+ let value = lowerer.lowerExpr(args[1]);
3859
+ if (lowerer.mapTypeOf(lowerer.typeOf(args[1]))?.kind === "string" &&
3860
+ lowerer.runtimeOptionalWidening(value.type, STRING) !== null) {
3861
+ // Missing-value propagation keeps an indexed/header read's storage
3862
+ // as string | undefined after TypeScript narrows this call site to
3863
+ // string. Treat setHeader's string overload as the typed consumer it
3864
+ // is: extract the proven arm through the ordinary checked coercion.
3865
+ // An unguarded optional value remains union-typed to the checker and
3866
+ // retains the setHeader refusal below.
3867
+ value = lowerer.coerceInto(args[1], value, STRING);
3854
3868
  }
3855
- const receiver = handleReceiver(L, access.expression, HTTPRES_T);
3856
- const header = L.lowerExprExpecting(args[0], STRING);
3857
- let value = L.lowerExpr(args[1]);
3858
3869
  if (value.type.kind === "f64") {
3859
3870
  // Node formats number values via String(n) — the same ToString.
3860
3871
  value = { kind: "toString", operand: value, type: STRING, loc };
3861
3872
  }
3862
3873
  if (value.type.kind !== "string") {
3863
- L.noLowering(`setHeader with a '${L.fmt(value.type)}' value`, args[1], "header values are strings or numbers here");
3874
+ lowerer.noLowering(`setHeader with a '${lowerer.fmt(value.type)}' value`, args[1], "header values are strings or numbers here");
3864
3875
  }
3865
3876
  return { kind: "libCall", fn: "http.resSetHeader", args: [receiver, header, value], type: VOID, loc };
3866
3877
  }
3867
3878
  if (name === "writeHead") {
3868
3879
  if (args.length < 1 || args.length > 3) {
3869
- L.noLowering(`writeHead with ${args.length} arguments`, call, "the supported forms are writeHead(status[, statusMessage][, headers]) — headers as a literal object, a Record, or a flat [name, value, ...] array");
3880
+ lowerer.noLowering(`writeHead with ${args.length} arguments`, call, "the supported forms are writeHead(status[, statusMessage][, headers]) — headers as a literal object, a Record, or a flat [name, value, ...] array");
3870
3881
  }
3871
- const receiver = handleReceiver(L, access.expression, HTTPRES_T);
3872
- const status = L.lowerExprExpecting(args[0], F64);
3882
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPRES_T);
3883
+ const status = lowerer.lowerExprExpecting(args[0], F64);
3873
3884
  // The optional statusMessage: a string-typed second argument is the
3874
3885
  // reason phrase (Node's overload split); it rides the composing
3875
3886
  // helper as a resStatusMsgSet prefix before the head goes out.
3876
3887
  let msg = null;
3877
3888
  let headersNode;
3878
3889
  if (args.length === 2) {
3879
- if (L.mapTypeOf(L.typeOf(args[1]))?.kind === "string")
3880
- msg = L.lowerExprExpecting(args[1], STRING);
3890
+ if (lowerer.mapTypeOf(lowerer.typeOf(args[1]))?.kind === "string")
3891
+ msg = lowerer.lowerExprExpecting(args[1], STRING);
3881
3892
  else
3882
3893
  headersNode = args[1];
3883
3894
  }
3884
3895
  else if (args.length === 3) {
3885
- msg = L.lowerExprExpecting(args[1], STRING);
3896
+ msg = lowerer.lowerExprExpecting(args[1], STRING);
3886
3897
  headersNode = args[2];
3887
3898
  }
3888
3899
  // Node answers the response (`return this` — the chaining shape
@@ -3894,12 +3905,12 @@ function lowerHttpResMethodCall(L, call, access) {
3894
3905
  return { kind: "libCall", fn, args: callArgs, type: VOID, loc };
3895
3906
  }
3896
3907
  if (msg === null)
3897
- return receiverReturningCall(L, fn, callArgs, HTTPRES_T, loc);
3908
+ return receiverReturningCall(lowerer, fn, callArgs, HTTPRES_T, loc);
3898
3909
  // With a message the helper's parameter list gains the msg at slot
3899
3910
  // 1 (feeding the resStatusMsgSet prefix); the head call itself
3900
3911
  // re-selects around it.
3901
3912
  const withMsg = [callArgs[0], msg, ...callArgs.slice(1)];
3902
- return receiverReturningCall(L, fn, withMsg, HTTPRES_T, loc, {
3913
+ return receiverReturningCall(lowerer, fn, withMsg, HTTPRES_T, loc, {
3903
3914
  prefix: { fn: "http.resStatusMsgSet", argIndices: [0, 1] },
3904
3915
  mainArgIndices: [0, ...callArgs.slice(1).map((_, i) => i + 2)],
3905
3916
  });
@@ -3915,7 +3926,7 @@ function lowerHttpResMethodCall(L, call, access) {
3915
3926
  // or Node's FLAT ARRAY form ([name, value, name, value, ...]: a
3916
3927
  // string[] value, repeated names writing one line each).
3917
3928
  if (!ts.isObjectLiteralExpression(headersNode)) {
3918
- const v = L.lowerExpr(headersNode);
3929
+ const v = lowerer.lowerExpr(headersNode);
3919
3930
  if (v.type.kind === "array" && v.type.elem.kind === "string") {
3920
3931
  return headResult("http.resWriteHeadPairs", [receiver, status, v]);
3921
3932
  }
@@ -3926,11 +3937,11 @@ function lowerHttpResMethodCall(L, call, access) {
3926
3937
  return headResult("http.resWriteHeadDyn", [receiver, status, v]);
3927
3938
  }
3928
3939
  if (v.type.kind !== "record") {
3929
- L.noLowering(`writeHead with a '${L.fmt(v.type)}' headers argument`, headersNode, "pass an object literal, a Record<string, string>, or a flat [name, value, ...] string array — or call setHeader per entry before writeHead(status)");
3940
+ lowerer.noLowering(`writeHead with a '${lowerer.fmt(v.type)}' headers argument`, headersNode, "pass an object literal, a Record<string, string>, or a flat [name, value, ...] string array — or call setHeader per entry before writeHead(status)");
3930
3941
  }
3931
- const helper = L.envToPairsHelper(v.type.shapeId, locOf(headersNode));
3942
+ const helper = lowerer.envToPairsHelper(v.type.shapeId, locOf(headersNode));
3932
3943
  if (helper === null) {
3933
- L.noLowering(`writeHead headers of '${L.fmt(v.type)}' values`, headersNode, "header values must be strings (or string | undefined) — convert numbers with String(n)");
3944
+ lowerer.noLowering(`writeHead headers of '${lowerer.fmt(v.type)}' values`, headersNode, "header values must be strings (or string | undefined) — convert numbers with String(n)");
3934
3945
  }
3935
3946
  const pairs = { kind: "call", callee: helper, args: [v], type: arrayOf(STRING), loc };
3936
3947
  return headResult("http.resWriteHeadPairs", [receiver, status, pairs]);
@@ -3938,17 +3949,17 @@ function lowerHttpResMethodCall(L, call, access) {
3938
3949
  const names = [];
3939
3950
  const values = [];
3940
3951
  for (const prop of headersNode.properties) {
3941
- const key = ts.isPropertyAssignment(prop) ? staticHeaderKeyOf(L, prop) : null;
3952
+ const key = ts.isPropertyAssignment(prop) ? staticHeaderKeyOf(lowerer, prop) : null;
3942
3953
  if (!ts.isPropertyAssignment(prop) || key === null) {
3943
- L.noLowering("writeHead headers with dynamic keys, spreads, or shorthand entries", prop, "each header must be a `name: value` entry whose key is a literal (or a string-literal-typed const: [PORTLESS_HEADER])");
3954
+ lowerer.noLowering("writeHead headers with dynamic keys, spreads, or shorthand entries", prop, "each header must be a `name: value` entry whose key is a literal (or a string-literal-typed const: [PORTLESS_HEADER])");
3944
3955
  }
3945
- let value = L.lowerExpr(prop.initializer);
3956
+ let value = lowerer.lowerExpr(prop.initializer);
3946
3957
  if (value.type.kind === "f64") {
3947
3958
  // Node formats number values via String(n) — the same ToString.
3948
3959
  value = { kind: "toString", operand: value, type: STRING, loc };
3949
3960
  }
3950
3961
  if (value.type.kind !== "string") {
3951
- L.noLowering(`writeHead header values of type '${L.fmt(value.type)}'`, prop.initializer, "header values are strings or numbers here");
3962
+ lowerer.noLowering(`writeHead header values of type '${lowerer.fmt(value.type)}'`, prop.initializer, "header values are strings or numbers here");
3952
3963
  }
3953
3964
  names.push({ kind: "strLit", value: key, type: STRING, loc });
3954
3965
  values.push(value);
@@ -3958,15 +3969,15 @@ function lowerHttpResMethodCall(L, call, access) {
3958
3969
  return headResult("http.resWriteHeadN", [receiver, status, namesArr, valuesArr]);
3959
3970
  }
3960
3971
  if (name === "write" || name === "end") {
3961
- requireStatementPosition(L, call, `res.${name}(...)`);
3972
+ requireStatementPosition(lowerer, call, `res.${name}(...)`);
3962
3973
  const minArgs = name === "write" ? 1 : 0;
3963
3974
  const maxArgs = name === "write" ? 1 : 2;
3964
3975
  if (args.length < minArgs || args.length > maxArgs) {
3965
- L.noLowering(`${name} with ${args.length} arguments`, call, name === "write"
3976
+ lowerer.noLowering(`${name} with ${args.length} arguments`, call, name === "write"
3966
3977
  ? "the supported form is write(data)"
3967
3978
  : "the supported forms are end(), end(data), end(callback), and end(data, callback)");
3968
3979
  }
3969
- const receiver = handleReceiver(L, access.expression, HTTPRES_T);
3980
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPRES_T);
3970
3981
  // end's callback forms — end(cb) / end(data, cb): the callback fires
3971
3982
  // deferred once the body went out (Node's 'finish' emit), through
3972
3983
  // the resOnFinish slot registered just before the end call in an
@@ -3974,15 +3985,15 @@ function lowerHttpResMethodCall(L, call, access) {
3974
3985
  let cbArg = null;
3975
3986
  let dataNode = args[0];
3976
3987
  if (name === "end" && args.length === 2) {
3977
- const { cb } = lowerCallbackArg(L, args[1], "end callbacks", 0, () => false, "use ()", []);
3988
+ const { cb } = lowerCallbackArg(lowerer, args[1], "end callbacks", 0, () => false, "use ()", []);
3978
3989
  cbArg = cb;
3979
3990
  }
3980
3991
  else if (name === "end" && args.length === 1 &&
3981
- L.mapTypeOf(L.typeOf(args[0]))?.kind !== "string" &&
3982
- L.mapTypeOf(L.typeOf(args[0]))?.kind !== "bytes") {
3983
- const probe = L.typeOf(args[0]);
3984
- if (L.mapTypeOf(probe)?.kind === "func" || L.mapTypeOf(probe) === null || L.mapTypeOf(probe)?.kind === "dyn") {
3985
- const { cb } = lowerCallbackArg(L, args[0], "end callbacks", 0, () => false, "use ()", []);
3992
+ lowerer.mapTypeOf(lowerer.typeOf(args[0]))?.kind !== "string" &&
3993
+ lowerer.mapTypeOf(lowerer.typeOf(args[0]))?.kind !== "bytes") {
3994
+ const probe = lowerer.typeOf(args[0]);
3995
+ if (lowerer.mapTypeOf(probe)?.kind === "func" || lowerer.mapTypeOf(probe) === null || lowerer.mapTypeOf(probe)?.kind === "dyn") {
3996
+ const { cb } = lowerCallbackArg(lowerer, args[0], "end callbacks", 0, () => false, "use ()", []);
3986
3997
  cbArg = cb;
3987
3998
  dataNode = undefined;
3988
3999
  }
@@ -3990,13 +4001,12 @@ function lowerHttpResMethodCall(L, call, access) {
3990
4001
  const endWithCb = (fn, callArgs, cb) => {
3991
4002
  const all = [...callArgs, cb];
3992
4003
  const key = `server.endcb:${fn}:${all.map((a) => typeKey(a.type)).join(",")}`;
3993
- const existing = L.arrHofHelpers.get(key);
3994
- const helper = existing ?? `%server.endcb.${L.arrHofHelpers.size}`;
4004
+ const existing = lowerer.arrHofHelpers.get(key);
4005
+ const helper = existing ?? `%server.endcb.${lowerer.arrHofHelpers.size}`;
3995
4006
  if (!existing) {
3996
- L.arrHofHelpers.set(key, helper);
4007
+ lowerer.arrHofHelpers.set(key, helper);
3997
4008
  const params = all.map((a, i) => ({ localId: `p${i}.0`, name: `p${i}`, type: a.type }));
3998
- const ref = (i) => ({ kind: "varRef", localId: params[i].localId, type: params[i].type, loc });
3999
- L.liftedFns.push({
4009
+ lowerer.liftedFns.push({
4000
4010
  name: helper,
4001
4011
  params,
4002
4012
  returnType: VOID,
@@ -4004,12 +4014,12 @@ function lowerHttpResMethodCall(L, call, access) {
4004
4014
  body: [
4005
4015
  {
4006
4016
  kind: "exprStmt",
4007
- expr: { kind: "libCall", fn: "http.resOnFinish", args: [ref(0), ref(all.length - 1)], type: VOID, loc },
4017
+ expr: { kind: "libCall", fn: "http.resOnFinish", args: [varRef(params[0].localId, params[0].type, loc), varRef(params[all.length - 1].localId, params[all.length - 1].type, loc)], type: VOID, loc },
4008
4018
  loc,
4009
4019
  },
4010
4020
  {
4011
4021
  kind: "exprStmt",
4012
- expr: { kind: "libCall", fn, args: callArgs.map((_, i) => ref(i)), type: VOID, loc },
4022
+ expr: { kind: "libCall", fn, args: callArgs.map((_, i) => varRef(params[i].localId, params[i].type, loc)), type: VOID, loc },
4013
4023
  loc,
4014
4024
  },
4015
4025
  ],
@@ -4023,7 +4033,7 @@ function lowerHttpResMethodCall(L, call, access) {
4023
4033
  return endWithCb("http.resEnd", [receiver], cbArg);
4024
4034
  return { kind: "libCall", fn: "http.resEnd", args: [receiver], type: VOID, loc };
4025
4035
  }
4026
- const data = L.lowerExpr(dataNode);
4036
+ const data = lowerer.lowerExpr(dataNode);
4027
4037
  if (data.type.kind === "string") {
4028
4038
  const fn = name === "write" ? "http.resWrite" : "http.resEndStr";
4029
4039
  if (cbArg !== null)
@@ -4043,7 +4053,7 @@ function lowerHttpResMethodCall(L, call, access) {
4043
4053
  return endWithCb(fn, [receiver, data], cbArg);
4044
4054
  return { kind: "libCall", fn, args: [receiver, data], type: VOID, loc };
4045
4055
  }
4046
- L.noLowering(`${name} of '${L.fmt(data.type)}' data`, dataNode ?? call, NARROW_DATA_HINT);
4056
+ lowerer.noLowering(`${name} of '${lowerer.fmt(data.type)}' data`, dataNode ?? call, NARROW_DATA_HINT);
4047
4057
  }
4048
4058
  if (name === "getHeader" || name === "hasHeader" || name === "removeHeader") {
4049
4059
  // The header CRUD trio (setHeader's readers): getHeader answers the
@@ -4052,14 +4062,14 @@ function lowerHttpResMethodCall(L, call, access) {
4052
4062
  // removeHeader drops every case-insensitive match before the head
4053
4063
  // goes out; hasHeader is the boolean probe.
4054
4064
  if (name === "removeHeader")
4055
- requireStatementPosition(L, call, "res.removeHeader(...)");
4065
+ requireStatementPosition(lowerer, call, "res.removeHeader(...)");
4056
4066
  if (args.length !== 1) {
4057
- L.noLowering(`${name} with ${args.length} arguments`, call, `the supported form is ${name}(name)`);
4067
+ lowerer.noLowering(`${name} with ${args.length} arguments`, call, `the supported form is ${name}(name)`);
4058
4068
  }
4059
- const receiver = handleReceiver(L, access.expression, HTTPRES_T);
4060
- const header = L.lowerExprExpecting(args[0], STRING);
4069
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPRES_T);
4070
+ const header = lowerer.lowerExprExpecting(args[0], STRING);
4061
4071
  if (name === "getHeader") {
4062
- return { kind: "libCall", fn: "http.resGetHeader", args: [receiver, header], type: L.envValueType(), loc };
4072
+ return { kind: "libCall", fn: "http.resGetHeader", args: [receiver, header], type: lowerer.envValueType(), loc };
4063
4073
  }
4064
4074
  if (name === "hasHeader") {
4065
4075
  return { kind: "libCall", fn: "http.resHasHeader", args: [receiver, header], type: BOOL, loc };
@@ -4067,25 +4077,25 @@ function lowerHttpResMethodCall(L, call, access) {
4067
4077
  return { kind: "libCall", fn: "http.resRemoveHeader", args: [receiver, header], type: VOID, loc };
4068
4078
  }
4069
4079
  if (name === "destroy") {
4070
- requireStatementPosition(L, call, "res.destroy()");
4080
+ requireStatementPosition(lowerer, call, "res.destroy()");
4071
4081
  if (args.length !== 0) {
4072
- L.noLowering(`destroy with ${args.length} arguments`, call, "destroy() takes no arguments here");
4082
+ lowerer.noLowering(`destroy with ${args.length} arguments`, call, "destroy() takes no arguments here");
4073
4083
  }
4074
- const receiver = handleReceiver(L, access.expression, HTTPRES_T);
4084
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPRES_T);
4075
4085
  return { kind: "libCall", fn: "http.resDestroy", args: [receiver], type: VOID, loc };
4076
4086
  }
4077
4087
  if ((name === "on" || name === "once" || name === "addListener") && args.length === 2) {
4078
- requireStatementPosition(L, call, `res.${name}(...)`);
4088
+ requireStatementPosition(lowerer, call, `res.${name}(...)`);
4079
4089
  const once = boolLit(name === "once", loc);
4080
- const evT = L.typeOf(args[0]);
4090
+ const evT = lowerer.typeOf(args[0]);
4081
4091
  const event = evT.isStringLiteralType() ? evT.value : null;
4082
- const receiver = handleReceiver(L, access.expression, HTTPRES_T);
4092
+ const receiver = coerceToHandle(lowerer, access.expression, HTTPRES_T);
4083
4093
  if (event === "close") {
4084
- const { cb } = lowerCallbackArg(L, args[1], "close listeners", 0, () => false, "use ()", []);
4094
+ const { cb } = lowerCallbackArg(lowerer, args[1], "close listeners", 0, () => false, "use ()", []);
4085
4095
  return { kind: "libCall", fn: "http.resOnClose", args: [receiver, cb, once], type: VOID, loc };
4086
4096
  }
4087
- L.noLowering(`res.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, args[0], '"close" is the supported response event (as a literal)');
4097
+ lowerer.noLowering(`res.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, args[0], '"close" is the supported response event (as a literal)');
4088
4098
  }
4089
- L.noLowering(`ServerResponse.${name}`, call, "setHeader, getHeader, hasHeader, removeHeader, writeHead, write, end, destroy, headersSent, statusCode, statusMessage, and on/once of close are the supported ServerResponse members", L.checker.getSymbolAtLocation(access.name));
4099
+ lowerer.noLowering(`ServerResponse.${name}`, call, "setHeader, getHeader, hasHeader, removeHeader, writeHead, write, end, destroy, headersSent, statusCode, statusMessage, and on/once of close are the supported ServerResponse members", lowerer.checker.getSymbolAtLocation(access.name));
4090
4100
  }
4091
4101
  //# sourceMappingURL=lower-server.js.map