@scriptc/compiler 0.3.2 → 0.3.4

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 (454) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +1202 -64
  2. package/dist/backend/cycle-analysis.js +6 -1
  3. package/dist/backend/cycle-analysis.js.map +1 -1
  4. package/dist/backend/cycle-mutability.d.ts +5 -0
  5. package/dist/backend/cycle-mutability.js +62 -3
  6. package/dist/backend/cycle-mutability.js.map +1 -1
  7. package/dist/backend/executable-features.js +1 -0
  8. package/dist/backend/executable-features.js.map +1 -1
  9. package/dist/backend/library-pack.js +1 -0
  10. package/dist/backend/library-pack.js.map +1 -1
  11. package/dist/backend/llvm/alloc.js +24 -10
  12. package/dist/backend/llvm/alloc.js.map +1 -1
  13. package/dist/backend/llvm/alloc.test.js +47 -1
  14. package/dist/backend/llvm/alloc.test.js.map +1 -1
  15. package/dist/backend/llvm/array-search.d.ts +8 -0
  16. package/dist/backend/llvm/array-search.js +52 -0
  17. package/dist/backend/llvm/array-search.js.map +1 -0
  18. package/dist/backend/llvm/array-search.test.d.ts +1 -0
  19. package/dist/backend/llvm/array-search.test.js +72 -0
  20. package/dist/backend/llvm/array-search.test.js.map +1 -0
  21. package/dist/backend/llvm/call-lifetimes.d.ts +12 -1
  22. package/dist/backend/llvm/call-lifetimes.js +41 -11
  23. package/dist/backend/llvm/call-lifetimes.js.map +1 -1
  24. package/dist/backend/llvm/call-lifetimes.test.js +85 -1
  25. package/dist/backend/llvm/call-lifetimes.test.js.map +1 -1
  26. package/dist/backend/llvm/classes.js +87 -36
  27. package/dist/backend/llvm/classes.js.map +1 -1
  28. package/dist/backend/llvm/common.d.ts +6 -1
  29. package/dist/backend/llvm/common.js +8 -1
  30. package/dist/backend/llvm/common.js.map +1 -1
  31. package/dist/backend/llvm/dense-array-access.d.ts +5 -0
  32. package/dist/backend/llvm/dense-array-access.js +3 -3
  33. package/dist/backend/llvm/dense-array-access.js.map +1 -1
  34. package/dist/backend/llvm/dyn.d.ts +44 -1
  35. package/dist/backend/llvm/dyn.js +251 -36
  36. package/dist/backend/llvm/dyn.js.map +1 -1
  37. package/dist/backend/llvm/emitter.d.ts +77 -14
  38. package/dist/backend/llvm/emitter.js +461 -108
  39. package/dist/backend/llvm/emitter.js.map +1 -1
  40. package/dist/backend/llvm/emitter.test.js +26 -3
  41. package/dist/backend/llvm/emitter.test.js.map +1 -1
  42. package/dist/backend/llvm/expr-async.js +52 -1
  43. package/dist/backend/llvm/expr-async.js.map +1 -1
  44. package/dist/backend/llvm/expr-bytes.d.ts +9 -0
  45. package/dist/backend/llvm/expr-bytes.js +169 -63
  46. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  47. package/dist/backend/llvm/expr-callbacks.js +16 -2
  48. package/dist/backend/llvm/expr-callbacks.js.map +1 -1
  49. package/dist/backend/llvm/expr-calls.d.ts +3 -1
  50. package/dist/backend/llvm/expr-calls.js +57 -2
  51. package/dist/backend/llvm/expr-calls.js.map +1 -1
  52. package/dist/backend/llvm/expr-containers.js +57 -19
  53. package/dist/backend/llvm/expr-containers.js.map +1 -1
  54. package/dist/backend/llvm/expr-dynamic.js +19 -8
  55. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  56. package/dist/backend/llvm/expr-primitives.js +28 -30
  57. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  58. package/dist/backend/llvm/expr-records.js +8 -4
  59. package/dist/backend/llvm/expr-records.js.map +1 -1
  60. package/dist/backend/llvm/expr-stream-bridges.js +35 -32
  61. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  62. package/dist/backend/llvm/expr-stream-callbacks.d.ts +13 -2
  63. package/dist/backend/llvm/expr-stream-callbacks.js +80 -5
  64. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  65. package/dist/backend/llvm/inline-unions.d.ts +48 -0
  66. package/dist/backend/llvm/inline-unions.js +134 -0
  67. package/dist/backend/llvm/inline-unions.js.map +1 -0
  68. package/dist/backend/llvm/inline-unions.test.d.ts +1 -0
  69. package/dist/backend/llvm/inline-unions.test.js +124 -0
  70. package/dist/backend/llvm/inline-unions.test.js.map +1 -0
  71. package/dist/backend/llvm/integer-remainder.d.ts +28 -5
  72. package/dist/backend/llvm/integer-remainder.js +80 -9
  73. package/dist/backend/llvm/integer-remainder.js.map +1 -1
  74. package/dist/backend/llvm/intern-tables.test.d.ts +1 -0
  75. package/dist/backend/llvm/intern-tables.test.js +77 -0
  76. package/dist/backend/llvm/intern-tables.test.js.map +1 -0
  77. package/dist/backend/llvm/lib-datagram.js +10 -0
  78. package/dist/backend/llvm/lib-datagram.js.map +1 -1
  79. package/dist/backend/llvm/lib-dispatch.js +255 -29
  80. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  81. package/dist/backend/llvm/lib-filesystem.js +176 -7
  82. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  83. package/dist/backend/llvm/lib-network.js +25 -6
  84. package/dist/backend/llvm/lib-network.js.map +1 -1
  85. package/dist/backend/llvm/lib-process.js +2 -2
  86. package/dist/backend/llvm/lib-process.js.map +1 -1
  87. package/dist/backend/llvm/lib-shared.d.ts +5 -0
  88. package/dist/backend/llvm/lib-shared.js +212 -1
  89. package/dist/backend/llvm/lib-shared.js.map +1 -1
  90. package/dist/backend/llvm/lib-stream.js +184 -0
  91. package/dist/backend/llvm/lib-stream.js.map +1 -1
  92. package/dist/backend/llvm/lib-test.js +9 -0
  93. package/dist/backend/llvm/lib-test.js.map +1 -1
  94. package/dist/backend/llvm/local-array-reads.js +7 -3
  95. package/dist/backend/llvm/local-array-reads.js.map +1 -1
  96. package/dist/backend/llvm/local-array-reads.test.js +6 -3
  97. package/dist/backend/llvm/local-array-reads.test.js.map +1 -1
  98. package/dist/backend/llvm/local-union-storage.d.ts +2 -0
  99. package/dist/backend/llvm/local-union-storage.js +5 -0
  100. package/dist/backend/llvm/local-union-storage.js.map +1 -1
  101. package/dist/backend/llvm/local-union-storage.test.js +1 -0
  102. package/dist/backend/llvm/local-union-storage.test.js.map +1 -1
  103. package/dist/backend/llvm/loop-array-borrows.d.ts +8 -2
  104. package/dist/backend/llvm/loop-array-borrows.js +93 -13
  105. package/dist/backend/llvm/loop-array-borrows.js.map +1 -1
  106. package/dist/backend/llvm/map-number-lookup.d.ts +24 -0
  107. package/dist/backend/llvm/map-number-lookup.js +88 -0
  108. package/dist/backend/llvm/map-number-lookup.js.map +1 -1
  109. package/dist/backend/llvm/map-number-lookup.test.d.ts +1 -0
  110. package/dist/backend/llvm/map-number-lookup.test.js +158 -0
  111. package/dist/backend/llvm/map-number-lookup.test.js.map +1 -0
  112. package/dist/backend/llvm/map-read-lifetimes.d.ts +9 -0
  113. package/dist/backend/llvm/map-read-lifetimes.js +90 -1
  114. package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
  115. package/dist/backend/llvm/map-read-lifetimes.test.js +129 -1
  116. package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -1
  117. package/dist/backend/llvm/publish.d.ts +9 -0
  118. package/dist/backend/llvm/publish.js +25 -4
  119. package/dist/backend/llvm/publish.js.map +1 -1
  120. package/dist/backend/llvm/record-results.d.ts +8 -5
  121. package/dist/backend/llvm/record-results.js +20 -12
  122. package/dist/backend/llvm/record-results.js.map +1 -1
  123. package/dist/backend/llvm/reference-effects.js +13 -0
  124. package/dist/backend/llvm/reference-effects.js.map +1 -1
  125. package/dist/backend/llvm/reference-writes.js +19 -2
  126. package/dist/backend/llvm/reference-writes.js.map +1 -1
  127. package/dist/backend/llvm/regions.d.ts +5 -1
  128. package/dist/backend/llvm/regions.js +24 -10
  129. package/dist/backend/llvm/regions.js.map +1 -1
  130. package/dist/backend/llvm/serialized-ir-emission.test.js +2 -0
  131. package/dist/backend/llvm/serialized-ir-emission.test.js.map +1 -1
  132. package/dist/backend/llvm/shapes.d.ts +56 -10
  133. package/dist/backend/llvm/shapes.js +178 -39
  134. package/dist/backend/llvm/shapes.js.map +1 -1
  135. package/dist/backend/llvm/shapes.test.js +61 -3
  136. package/dist/backend/llvm/shapes.test.js.map +1 -1
  137. package/dist/backend/llvm/stack-objects.js +16 -4
  138. package/dist/backend/llvm/stack-objects.js.map +1 -1
  139. package/dist/backend/llvm/stack-objects.test.js +3 -0
  140. package/dist/backend/llvm/stack-objects.test.js.map +1 -1
  141. package/dist/backend/llvm/string-reads.js +2 -2
  142. package/dist/backend/llvm/string-reads.js.map +1 -1
  143. package/dist/backend/llvm/string-slices.js +2 -2
  144. package/dist/backend/llvm/string-slices.js.map +1 -1
  145. package/dist/backend/llvm/walkers.d.ts +11 -0
  146. package/dist/backend/llvm/walkers.js +106 -10
  147. package/dist/backend/llvm/walkers.js.map +1 -1
  148. package/dist/backend/may-throw.js +13 -4
  149. package/dist/backend/may-throw.js.map +1 -1
  150. package/dist/backend/native/contracts.d.ts +5 -2
  151. package/dist/backend/native/executable.js +27 -8
  152. package/dist/backend/native/executable.js.map +1 -1
  153. package/dist/backend/native/runtime-inputs.d.ts +1 -1
  154. package/dist/backend/native/runtime-inputs.js +2 -0
  155. package/dist/backend/native/runtime-inputs.js.map +1 -1
  156. package/dist/backend/native-codegen-core.d.ts +4 -4
  157. package/dist/backend/native-codegen-core.js +4 -6
  158. package/dist/backend/native-codegen-core.js.map +1 -1
  159. package/dist/backend/native-codegen.test.js +7 -8
  160. package/dist/backend/native-codegen.test.js.map +1 -1
  161. package/dist/backend/native-link-info-core.d.ts +3 -0
  162. package/dist/backend/native-link-info-core.js.map +1 -1
  163. package/dist/backend/native-toolchain.test.js +1 -1
  164. package/dist/backend/native-toolchain.test.js.map +1 -1
  165. package/dist/backend/publication.js +3 -1
  166. package/dist/backend/publication.js.map +1 -1
  167. package/dist/backend/runtime-abi.d.ts +2 -2
  168. package/dist/backend/runtime-abi.js +2 -2
  169. package/dist/backend/runtime-pack-targets.test.js +2 -1
  170. package/dist/backend/runtime-pack-targets.test.js.map +1 -1
  171. package/dist/backend/runtime-pack.test.js +2 -1
  172. package/dist/backend/runtime-pack.test.js.map +1 -1
  173. package/dist/backend/target-diagnostics.js +11 -1
  174. package/dist/backend/target-diagnostics.js.map +1 -1
  175. package/dist/backend/target-diagnostics.test.js +4 -1
  176. package/dist/backend/target-diagnostics.test.js.map +1 -1
  177. package/dist/backend/warm-cache.js +1 -0
  178. package/dist/backend/warm-cache.js.map +1 -1
  179. package/dist/compat/fetch-profile.js +4 -4
  180. package/dist/compat/fetch-profile.js.map +1 -1
  181. package/dist/contracts/check.js +2 -0
  182. package/dist/contracts/check.js.map +1 -1
  183. package/dist/coverage/report.js +1 -1
  184. package/dist/coverage/report.js.map +1 -1
  185. package/dist/diagnostics/diagnostic.d.ts +6 -5
  186. package/dist/diagnostics/diagnostic.js +7 -6
  187. package/dist/diagnostics/diagnostic.js.map +1 -1
  188. package/dist/executable/executable-cache.d.ts +1 -0
  189. package/dist/executable/executable-cache.js +1 -0
  190. package/dist/executable/executable-cache.js.map +1 -1
  191. package/dist/executable/executable-cache.test.js +1 -0
  192. package/dist/executable/executable-cache.test.js.map +1 -1
  193. package/dist/frontend/builtin-modules.d.ts +1 -1
  194. package/dist/frontend/builtin-modules.js +1 -0
  195. package/dist/frontend/builtin-modules.js.map +1 -1
  196. package/dist/frontend/comptime-node.js +2 -2
  197. package/dist/frontend/comptime-node.js.map +1 -1
  198. package/dist/frontend/experimental-import.d.ts +5 -1
  199. package/dist/frontend/experimental-import.js +28 -3
  200. package/dist/frontend/experimental-import.js.map +1 -1
  201. package/dist/frontend/lowering/assert-instances.d.ts +38 -0
  202. package/dist/frontend/lowering/assert-instances.js +269 -0
  203. package/dist/frontend/lowering/assert-instances.js.map +1 -0
  204. package/dist/frontend/lowering/binding-analysis.d.ts +1 -1
  205. package/dist/frontend/lowering/binding-analysis.js +1 -1
  206. package/dist/frontend/lowering/builtins/arguments.d.ts +4 -0
  207. package/dist/frontend/lowering/builtins/arguments.js +8 -4
  208. package/dist/frontend/lowering/builtins/arguments.js.map +1 -1
  209. package/dist/frontend/lowering/builtins/blob.d.ts +20 -0
  210. package/dist/frontend/lowering/builtins/blob.js +167 -0
  211. package/dist/frontend/lowering/builtins/blob.js.map +1 -0
  212. package/dist/frontend/lowering/builtins/child-process-async.d.ts +2 -2
  213. package/dist/frontend/lowering/builtins/child-process-async.js +2 -2
  214. package/dist/frontend/lowering/builtins/child-process-methods.js +1 -1
  215. package/dist/frontend/lowering/builtins/child-process-methods.js.map +1 -1
  216. package/dist/frontend/lowering/builtins/child-process-sync.js +1 -1
  217. package/dist/frontend/lowering/builtins/child-process-sync.js.map +1 -1
  218. package/dist/frontend/lowering/builtins/compression.d.ts +18 -0
  219. package/dist/frontend/lowering/builtins/compression.js +178 -4
  220. package/dist/frontend/lowering/builtins/compression.js.map +1 -1
  221. package/dist/frontend/lowering/builtins/constants.js +7 -2
  222. package/dist/frontend/lowering/builtins/constants.js.map +1 -1
  223. package/dist/frontend/lowering/builtins/crypto.d.ts +6 -0
  224. package/dist/frontend/lowering/builtins/crypto.js +526 -121
  225. package/dist/frontend/lowering/builtins/crypto.js.map +1 -1
  226. package/dist/frontend/lowering/builtins/errors.js +23 -0
  227. package/dist/frontend/lowering/builtins/errors.js.map +1 -1
  228. package/dist/frontend/lowering/builtins/filesystem-calls.d.ts +10 -0
  229. package/dist/frontend/lowering/builtins/filesystem-calls.js +89 -1
  230. package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -1
  231. package/dist/frontend/lowering/builtins/filesystem.d.ts +16 -7
  232. package/dist/frontend/lowering/builtins/filesystem.js +97 -15
  233. package/dist/frontend/lowering/builtins/filesystem.js.map +1 -1
  234. package/dist/frontend/lowering/builtins/fs-glob.d.ts +23 -0
  235. package/dist/frontend/lowering/builtins/fs-glob.js +224 -0
  236. package/dist/frontend/lowering/builtins/fs-glob.js.map +1 -0
  237. package/dist/frontend/lowering/builtins/key-object.d.ts +13 -0
  238. package/dist/frontend/lowering/builtins/key-object.js +56 -0
  239. package/dist/frontend/lowering/builtins/key-object.js.map +1 -0
  240. package/dist/frontend/lowering/builtins/module-calls.js +44 -11
  241. package/dist/frontend/lowering/builtins/module-calls.js.map +1 -1
  242. package/dist/frontend/lowering/builtins/performance.d.ts +25 -3
  243. package/dist/frontend/lowering/builtins/performance.js +340 -5
  244. package/dist/frontend/lowering/builtins/performance.js.map +1 -1
  245. package/dist/frontend/lowering/builtins/process.d.ts +2 -2
  246. package/dist/frontend/lowering/builtins/process.js +107 -14
  247. package/dist/frontend/lowering/builtins/process.js.map +1 -1
  248. package/dist/frontend/lowering/builtins/properties.d.ts +0 -7
  249. package/dist/frontend/lowering/builtins/properties.js +39 -11
  250. package/dist/frontend/lowering/builtins/properties.js.map +1 -1
  251. package/dist/frontend/lowering/builtins/readline.d.ts +23 -8
  252. package/dist/frontend/lowering/builtins/readline.js +266 -90
  253. package/dist/frontend/lowering/builtins/readline.js.map +1 -1
  254. package/dist/frontend/lowering/builtins/timers.d.ts +3 -0
  255. package/dist/frontend/lowering/builtins/timers.js +109 -23
  256. package/dist/frontend/lowering/builtins/timers.js.map +1 -1
  257. package/dist/frontend/lowering/builtins/url.d.ts +8 -0
  258. package/dist/frontend/lowering/builtins/url.js +36 -0
  259. package/dist/frontend/lowering/builtins/url.js.map +1 -1
  260. package/dist/frontend/lowering/call-arguments.js +1 -1
  261. package/dist/frontend/lowering/call-arguments.js.map +1 -1
  262. package/dist/frontend/lowering/call-signatures.js +26 -2
  263. package/dist/frontend/lowering/call-signatures.js.map +1 -1
  264. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +2 -0
  265. package/dist/frontend/lowering/class-dynamic-dispatch.js +171 -13
  266. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  267. package/dist/frontend/lowering/class-dynamic-dispatch.test.js +1 -0
  268. package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
  269. package/dist/frontend/lowering/class-protocol-dispatch.d.ts +45 -0
  270. package/dist/frontend/lowering/class-protocol-dispatch.js +516 -0
  271. package/dist/frontend/lowering/class-protocol-dispatch.js.map +1 -0
  272. package/dist/frontend/lowering/coercions/structural-plans.js +2 -1
  273. package/dist/frontend/lowering/coercions/structural-plans.js.map +1 -1
  274. package/dist/frontend/lowering/coercions/structural.js +3 -3
  275. package/dist/frontend/lowering/coercions/structural.js.map +1 -1
  276. package/dist/frontend/lowering/collation-repertoire.js +6 -5
  277. package/dist/frontend/lowering/collation-repertoire.js.map +1 -1
  278. package/dist/frontend/lowering/containers/array-callbacks.js +4 -7
  279. package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
  280. package/dist/frontend/lowering/containers/array-methods.d.ts +0 -7
  281. package/dist/frontend/lowering/containers/array-methods.js +43 -2
  282. package/dist/frontend/lowering/containers/array-methods.js.map +1 -1
  283. package/dist/frontend/lowering/containers/bytes.js +38 -26
  284. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  285. package/dist/frontend/lowering/containers/for-of.d.ts +1 -1
  286. package/dist/frontend/lowering/containers/for-of.js +5 -1
  287. package/dist/frontend/lowering/containers/for-of.js.map +1 -1
  288. package/dist/frontend/lowering/containers/indexed-objects.js +1 -1
  289. package/dist/frontend/lowering/containers/indexed-objects.js.map +1 -1
  290. package/dist/frontend/lowering/crypto-tables.d.ts +3 -3
  291. package/dist/frontend/lowering/crypto-tables.js +77 -12
  292. package/dist/frontend/lowering/crypto-tables.js.map +1 -1
  293. package/dist/frontend/lowering/expressions/nullish-assignment.js +10 -0
  294. package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -1
  295. package/dist/frontend/lowering/expressions/object-literals.js +16 -12
  296. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  297. package/dist/frontend/lowering/generic-functions.d.ts +2 -2
  298. package/dist/frontend/lowering/generic-functions.js +2 -2
  299. package/dist/frontend/lowering/generic-functions.js.map +1 -1
  300. package/dist/frontend/lowering/http2-constants.js +1 -1
  301. package/dist/frontend/lowering/intern-tables.d.ts +13 -0
  302. package/dist/frontend/lowering/intern-tables.js +536 -0
  303. package/dist/frontend/lowering/intern-tables.js.map +1 -0
  304. package/dist/frontend/lowering/lower-array-sort.d.ts +12 -1
  305. package/dist/frontend/lowering/lower-array-sort.js +561 -191
  306. package/dist/frontend/lowering/lower-array-sort.js.map +1 -1
  307. package/dist/frontend/lowering/lower-array-sort.test.js +4 -2
  308. package/dist/frontend/lowering/lower-array-sort.test.js.map +1 -1
  309. package/dist/frontend/lowering/lower-assert.js +702 -63
  310. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  311. package/dist/frontend/lowering/lower-async-iteration.d.ts +6 -3
  312. package/dist/frontend/lowering/lower-async-iteration.js +259 -4
  313. package/dist/frontend/lowering/lower-async-iteration.js.map +1 -1
  314. package/dist/frontend/lowering/lower-calls.js +118 -12
  315. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  316. package/dist/frontend/lowering/lower-classes.d.ts +11 -2
  317. package/dist/frontend/lowering/lower-classes.js +76 -9
  318. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  319. package/dist/frontend/lowering/lower-comptime.d.ts +1 -1
  320. package/dist/frontend/lowering/lower-comptime.js +4 -4
  321. package/dist/frontend/lowering/lower-comptime.js.map +1 -1
  322. package/dist/frontend/lowering/lower-dgram.js +77 -52
  323. package/dist/frontend/lowering/lower-dgram.js.map +1 -1
  324. package/dist/frontend/lowering/lower-event-target.d.ts +63 -0
  325. package/dist/frontend/lowering/lower-event-target.js +362 -0
  326. package/dist/frontend/lowering/lower-event-target.js.map +1 -0
  327. package/dist/frontend/lowering/lower-expando.js +2 -2
  328. package/dist/frontend/lowering/lower-exprs.js +124 -22
  329. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  330. package/dist/frontend/lowering/lower-inspect.d.ts +6 -0
  331. package/dist/frontend/lowering/lower-inspect.js +240 -49
  332. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  333. package/dist/frontend/lowering/lower-mixins.js +1 -1
  334. package/dist/frontend/lowering/lower-mock.d.ts +11 -0
  335. package/dist/frontend/lowering/lower-mock.js +504 -0
  336. package/dist/frontend/lowering/lower-mock.js.map +1 -0
  337. package/dist/frontend/lowering/lower-modules.d.ts +1 -1
  338. package/dist/frontend/lowering/lower-modules.js +14 -3
  339. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  340. package/dist/frontend/lowering/lower-namespaces.d.ts +2 -2
  341. package/dist/frontend/lowering/lower-namespaces.js +2 -2
  342. package/dist/frontend/lowering/lower-server.d.ts +3 -0
  343. package/dist/frontend/lowering/lower-server.js +419 -44
  344. package/dist/frontend/lowering/lower-server.js.map +1 -1
  345. package/dist/frontend/lowering/lower-stdlib.d.ts +7 -1
  346. package/dist/frontend/lowering/lower-stdlib.js +10 -3
  347. package/dist/frontend/lowering/lower-stdlib.js.map +1 -1
  348. package/dist/frontend/lowering/lower-stmts.d.ts +2 -2
  349. package/dist/frontend/lowering/lower-stmts.js +69 -14
  350. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  351. package/dist/frontend/lowering/lower-stream.d.ts +10 -6
  352. package/dist/frontend/lowering/lower-stream.js +1020 -49
  353. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  354. package/dist/frontend/lowering/lower-test.js +86 -8
  355. package/dist/frontend/lowering/lower-test.js.map +1 -1
  356. package/dist/frontend/lowering/lower-timers.js +1 -1
  357. package/dist/frontend/lowering/lowerer.d.ts +45 -5
  358. package/dist/frontend/lowering/lowerer.js +317 -48
  359. package/dist/frontend/lowering/lowerer.js.map +1 -1
  360. package/dist/frontend/lowering/native-ffi.js +2 -2
  361. package/dist/frontend/lowering/native-ffi.js.map +1 -1
  362. package/dist/frontend/lowering/pairs-snapshot.d.ts +6 -0
  363. package/dist/frontend/lowering/pairs-snapshot.js +49 -0
  364. package/dist/frontend/lowering/pairs-snapshot.js.map +1 -1
  365. package/dist/frontend/lowering/runtime-optional-records.d.ts +115 -0
  366. package/dist/frontend/lowering/runtime-optional-records.js +715 -0
  367. package/dist/frontend/lowering/runtime-optional-records.js.map +1 -0
  368. package/dist/frontend/lowering/runtime-optional-records.test.d.ts +1 -0
  369. package/dist/frontend/lowering/runtime-optional-records.test.js +175 -0
  370. package/dist/frontend/lowering/runtime-optional-records.test.js.map +1 -0
  371. package/dist/frontend/lowering/surfaces.d.ts +11 -3
  372. package/dist/frontend/lowering/surfaces.js +334 -37
  373. package/dist/frontend/lowering/surfaces.js.map +1 -1
  374. package/dist/frontend/lowering/zlib-constants.d.ts +1 -0
  375. package/dist/frontend/lowering/zlib-constants.js +181 -0
  376. package/dist/frontend/lowering/zlib-constants.js.map +1 -0
  377. package/dist/frontend/mock-shapes.d.ts +10 -0
  378. package/dist/frontend/mock-shapes.js +76 -0
  379. package/dist/frontend/mock-shapes.js.map +1 -0
  380. package/dist/frontend/module-syntax.d.ts +1 -1
  381. package/dist/frontend/module-syntax.js +1 -1
  382. package/dist/frontend/npm-static-prune.js +1 -1
  383. package/dist/frontend/npm-static-prune.js.map +1 -1
  384. package/dist/frontend/npm-static-rewrite-syntax.js +4 -3
  385. package/dist/frontend/npm-static-rewrite-syntax.js.map +1 -1
  386. package/dist/frontend/pipeline.js +6 -4
  387. package/dist/frontend/pipeline.js.map +1 -1
  388. package/dist/frontend/program.d.ts +3 -3
  389. package/dist/frontend/program.js +25 -18
  390. package/dist/frontend/program.js.map +1 -1
  391. package/dist/frontend/resolve.d.ts +4 -0
  392. package/dist/frontend/resolve.js +15 -1
  393. package/dist/frontend/resolve.js.map +1 -1
  394. package/dist/frontend/ts7/adapter.js +1 -1
  395. package/dist/frontend/ts7/ast-bytes.d.ts +1 -1
  396. package/dist/frontend/ts7/ast-bytes.js +1 -1
  397. package/dist/frontend/ts7/semantic-json.d.ts +1 -1
  398. package/dist/frontend/ts7/semantic-json.js +1 -1
  399. package/dist/frontend/ts7/semantic-json.js.map +1 -1
  400. package/dist/frontend/ts7/world-check.js +1 -1
  401. package/dist/frontend/tsc-codes.js +3 -2
  402. package/dist/frontend/tsc-codes.js.map +1 -1
  403. package/dist/frontend/type-mapper.d.ts +21 -1
  404. package/dist/frontend/type-mapper.js +245 -27
  405. package/dist/frontend/type-mapper.js.map +1 -1
  406. package/dist/index.js +7 -5
  407. package/dist/index.js.map +1 -1
  408. package/dist/ir/analysis.d.ts +12 -6
  409. package/dist/ir/analysis.js +26 -10
  410. package/dist/ir/analysis.js.map +1 -1
  411. package/dist/ir/analysis.test.js +15 -3
  412. package/dist/ir/analysis.test.js.map +1 -1
  413. package/dist/ir/builtin-effects.js +115 -0
  414. package/dist/ir/builtin-effects.js.map +1 -1
  415. package/dist/ir/builtin-signatures.d.ts +1 -1
  416. package/dist/ir/builtin-signatures.js +438 -46
  417. package/dist/ir/builtin-signatures.js.map +1 -1
  418. package/dist/ir/int32-slots.js +1 -0
  419. package/dist/ir/int32-slots.js.map +1 -1
  420. package/dist/ir/ir.d.ts +84 -17
  421. package/dist/ir/ir.js +54 -1
  422. package/dist/ir/ir.js.map +1 -1
  423. package/dist/ir/runtime-features.d.ts +1 -0
  424. package/dist/ir/runtime-features.js +111 -7
  425. package/dist/ir/runtime-features.js.map +1 -1
  426. package/dist/ir/serialize.js +1 -1
  427. package/dist/ir/serialize.js.map +1 -1
  428. package/dist/ir/traverse.js +1 -0
  429. package/dist/ir/traverse.js.map +1 -1
  430. package/dist/ir/validate.js +295 -14
  431. package/dist/ir/validate.js.map +1 -1
  432. package/dist/ir/validate.test.js +60 -0
  433. package/dist/ir/validate.test.js.map +1 -1
  434. package/dist/library/fence-eval.d.ts +1 -1
  435. package/dist/library/fence-eval.js +5 -4
  436. package/dist/library/fence-eval.js.map +1 -1
  437. package/dist/library/ir-policy.js +11 -4
  438. package/dist/library/ir-policy.js.map +1 -1
  439. package/dist/library/library-profile.js +13 -13
  440. package/dist/library/library-profile.js.map +1 -1
  441. package/dist/library/prepare.js +1 -1
  442. package/dist/library/prepare.js.map +1 -1
  443. package/dist/library/sidecar.js +3 -3
  444. package/dist/library/sidecar.js.map +1 -1
  445. package/dist/native/cli.js +1 -0
  446. package/dist/native/cli.js.map +1 -1
  447. package/dist/native/compiler.js +1 -3
  448. package/dist/native/compiler.js.map +1 -1
  449. package/dist/native/prepare.js +4 -2
  450. package/dist/native/prepare.js.map +1 -1
  451. package/dist/native/sanitizer.test.js +1 -0
  452. package/dist/native/sanitizer.test.js.map +1 -1
  453. package/package.json +20 -20
  454. package/surface-manifest.json +1279 -221
@@ -27,10 +27,10 @@ import * as ts from "../ts7/adapter.js";
27
27
  import { resultIsDiscarded } from "./call-position.js";
28
28
  import { jsFuncNameOf, own } from "./lowerer.js";
29
29
  import { NARROW_FIRST } from "./surfaces.js";
30
- import { inspectExpr, typeReachesItself } from "./lower-inspect.js";
30
+ import { inspectExpr, typeReachesCycle, typeReachesFunction, typeReachesItself, } from "./lower-inspect.js";
31
31
  import { abstractEqualityExpr, abstractEqualitySupported } from "./abstract-equality.js";
32
32
  import { BOOL, CAUGHT, DYN, DYN_HANDLE_KINDS, F64, REGEX, RUNTIME_ERROR_CLASSES, STRING, VOID, isUnitType, typeEquals, typeKey, } from "../../ir/ir.js";
33
- import { boolLit, countedFor, numLit, strLit, varRef } from "../../ir/build.js";
33
+ import { boolLit, countedFor, dynUndefinedExpr, numLit, strLit, varRef } from "../../ir/build.js";
34
34
  /** node:assert/strict binds the loose NAMES to the strict comparisons —
35
35
  * Node's own aliasing (`strict.equal === assert.strictEqual`). */
36
36
  const STRICT_ALIASES = {
@@ -46,6 +46,68 @@ function canonicalAssertMember(module, member) {
46
46
  return own(STRICT_ALIASES, member) ?? member;
47
47
  return member;
48
48
  }
49
+ /* Node's AssertionError carries actual, expected and operator. Where the
50
+ * verdict is computed in compiled code, the failure branch records them
51
+ * (assert.record) before the throwing call, so a passing assertion boxes
52
+ * nothing. Values without a checked-dynamic form record undefined, and so
53
+ * do values whose type can be cyclic (the checked-dynamic form is a deep
54
+ * copy, which a cyclic value does not have) or can hold functions (their
55
+ * boxes carry no source names, which the failure message prints). */
56
+ /** A value as the dyn the record carries. */
57
+ function recordedValue(lowerer, value, loc) {
58
+ if (value === null)
59
+ return dynUndefinedExpr(loc);
60
+ if (value.type.kind === "dyn")
61
+ return value;
62
+ if (value.kind === "unitLit" ||
63
+ (lowerer.dynConvertible(value.type) &&
64
+ !typeReachesCycle(lowerer, value.type) &&
65
+ !typeReachesFunction(lowerer, value.type))) {
66
+ return { kind: "dynFrom", value, type: DYN, loc };
67
+ }
68
+ return dynUndefinedExpr(loc);
69
+ }
70
+ /** `if (failing) assert.record(actual, expected, operator)`. */
71
+ function recordOnFailure(lowerer, failing, actual, expected, operator, loc) {
72
+ return {
73
+ kind: "if",
74
+ cond: failing,
75
+ then: [
76
+ {
77
+ kind: "exprStmt",
78
+ expr: {
79
+ kind: "libCall",
80
+ fn: "assert.record",
81
+ args: [
82
+ recordedValue(lowerer, actual, loc),
83
+ recordedValue(lowerer, expected, loc),
84
+ strLit(operator, loc),
85
+ ],
86
+ type: VOID,
87
+ loc,
88
+ },
89
+ loc,
90
+ },
91
+ ],
92
+ else_: null,
93
+ loc,
94
+ };
95
+ }
96
+ /** A value held in a hidden local, so the verdict and the record read it once. */
97
+ function stableValue(lowerer, stmts, value, name, loc) {
98
+ if (value.kind === "varRef" ||
99
+ value.kind === "unitLit" ||
100
+ value.kind === "boolLit" ||
101
+ value.kind === "numLit" ||
102
+ value.kind === "strLit")
103
+ return value;
104
+ const local = lowerer.declareHiddenLocal(name, value.type);
105
+ stmts.push({ kind: "varDecl", localId: local.id, init: value, loc });
106
+ return varRef(local.id, value.type, loc);
107
+ }
108
+ function notExpr(value, loc) {
109
+ return { kind: "unary", op: "!", operand: value, type: BOOL, loc };
110
+ }
49
111
  /** VOID/never results are usable as statements and concise arrow bodies
50
112
  * only (the lower-dgram stance): nothing downstream can consume them. */
51
113
  function requireStatementPosition(lowerer, call, what) {
@@ -90,6 +152,12 @@ export function lowerAssertModuleCall(lowerer, expr, bi, loc) {
90
152
  return lowerAssertEqual(lowerer, expr, loc, false, true);
91
153
  case "notDeepStrictEqual":
92
154
  return lowerAssertEqual(lowerer, expr, loc, true, true);
155
+ case "deepEqual":
156
+ return lowerAssertLooseDeep(lowerer, expr, loc, false);
157
+ case "notDeepEqual":
158
+ return lowerAssertLooseDeep(lowerer, expr, loc, true);
159
+ case "partialDeepStrictEqual":
160
+ return lowerAssertPartialDeep(lowerer, expr, loc);
93
161
  case "fail":
94
162
  return lowerAssertFail(lowerer, expr, loc);
95
163
  case "match":
@@ -164,9 +232,20 @@ function lowerAssertLooseEqual(lowerer, expr, loc, negated) {
164
232
  };
165
233
  const a = stable(left, "%assertLooseA");
166
234
  const b = stable(right, "%assertLooseB");
167
- const equal = abstractEqualityExpr(lowerer, a, b, loc, true);
168
- const actual = inspectExpr(lowerer, a.type, a, numLit(0, loc), numLit(2, loc), loc);
169
- const expected = inspectExpr(lowerer, b.type, b, numLit(0, loc), numLit(2, loc), loc);
235
+ const equal = stableValue(lowerer, stmts, abstractEqualityExpr(lowerer, a, b, loc, true), "%assertLooseEqual", loc);
236
+ const failing = negated ? equal : notExpr(equal, loc);
237
+ stmts.push(recordOnFailure(lowerer, failing, a, b, negated ? "!=" : "==", loc));
238
+ // The operands are inspected only for the failure message.
239
+ const inspectOnFailure = (value) => ({
240
+ kind: "ternary",
241
+ cond: failing,
242
+ then: inspectExpr(lowerer, value.type, value, numLit(0, loc), numLit(2, loc), loc),
243
+ else_: strLit("", loc),
244
+ type: STRING,
245
+ loc,
246
+ });
247
+ const actual = inspectOnFailure(a);
248
+ const expected = inspectOnFailure(b);
170
249
  const { msg, hasMsg } = lowerMessageArg(lowerer, expr.arguments[2], loc);
171
250
  const result = {
172
251
  kind: "libCall",
@@ -177,6 +256,437 @@ function lowerAssertLooseEqual(lowerer, expr, loc, negated) {
177
256
  };
178
257
  return { kind: "seqExpr", stmts, result, type: VOID, loc };
179
258
  }
259
+ /** The two compared operands. A context-free EMPTY array literal on
260
+ * either side has no element type of its own (`deepStrictEqual(
261
+ * ee.listeners('x'), [])` — the checker says any[]): it adopts the OTHER
262
+ * side's array type. Literals have no side effects, so lowering order is
263
+ * unobservable. */
264
+ function lowerComparedOperands(lowerer, aNode, bNode, loc) {
265
+ const emptyArrayLit = (n) => ts.isArrayLiteralExpression(n) && n.elements.length === 0;
266
+ const emptyOf = (t) => ({ kind: "arrayLit", elems: [], type: t, loc });
267
+ // A dyn other side adopts number[] — the dyn array a boxed empty
268
+ // literal builds is elementless, so any elem type serves.
269
+ const adoptedEmpty = (other) => other.kind === "array"
270
+ ? emptyOf(other)
271
+ : other.kind === "dyn"
272
+ ? emptyOf({ kind: "array", elem: F64 })
273
+ : null;
274
+ if (emptyArrayLit(aNode) && !emptyArrayLit(bNode)) {
275
+ const b = lowerer.lowerExpr(bNode);
276
+ return { a: adoptedEmpty(b.type) ?? lowerer.lowerExpr(aNode), b };
277
+ }
278
+ const a = lowerer.lowerExpr(aNode);
279
+ const b = emptyArrayLit(bNode)
280
+ ? (adoptedEmpty(a.type) ?? lowerer.lowerExpr(bNode))
281
+ : lowerer.lowerExpr(bNode);
282
+ return { a, b };
283
+ }
284
+ /** True when a union occurs anywhere in `t`'s value structure. */
285
+ function typeHasUnion(lowerer, t, visiting) {
286
+ switch (t.kind) {
287
+ case "union":
288
+ return true;
289
+ case "array":
290
+ case "set":
291
+ return typeHasUnion(lowerer, t.elem, visiting);
292
+ case "map":
293
+ return typeHasUnion(lowerer, t.key, visiting) || typeHasUnion(lowerer, t.value, visiting);
294
+ case "record": {
295
+ if (visiting.has(t.shapeId))
296
+ return false;
297
+ visiting.add(t.shapeId);
298
+ const shape = lowerer.shapes.get(t.shapeId);
299
+ return shape?.fields.some((f) => typeHasUnion(lowerer, f.type, visiting)) ?? false;
300
+ }
301
+ default:
302
+ return false;
303
+ }
304
+ }
305
+ /** assert.deepEqual / notDeepEqual: Node's loose deep comparison. Two
306
+ * operands of one union-free static type compare through the per-type
307
+ * helper in its loose mode (numbers under ==, typed arrays without the
308
+ * Buffer brand); everything else crosses into the checked-dynamic tree
309
+ * and compares there. Types that can be cyclic are refused: the failure
310
+ * message renders the values, which needs their checked-dynamic copy. */
311
+ function lowerAssertLooseDeep(lowerer, expr, loc, negated) {
312
+ const surface = negated ? "assert.notDeepEqual" : "assert.deepEqual";
313
+ requireStatementPosition(lowerer, expr, surface);
314
+ if (expr.arguments.length < 2 || expr.arguments.length > 3) {
315
+ lowerer.noLowering(`${surface} with ${expr.arguments.length} arguments`, expr);
316
+ }
317
+ const aNode = expr.arguments[0];
318
+ const bNode = expr.arguments[1];
319
+ const { a, b } = lowerComparedOperands(lowerer, aNode, bNode, loc);
320
+ const { msg, hasMsg } = lowerMessageArg(lowerer, expr.arguments[2], loc);
321
+ refuseUnrenderedDeepOperands(lowerer, surface, [
322
+ [a, aNode],
323
+ [b, bNode],
324
+ ], "loose");
325
+ if (typeEquals(a.type, b.type) &&
326
+ a.type.kind !== "dyn" &&
327
+ // Functions box with their source names for the message.
328
+ a.type.kind !== "func" &&
329
+ !isUnitType(a.type) &&
330
+ deepUnsupportedReason(lowerer, a.type, new Set()) === null &&
331
+ !typeHasUnion(lowerer, a.type, new Set())) {
332
+ const verdictOf = a.type.kind === "bytes"
333
+ ? (x, y) => ({
334
+ kind: "libCall",
335
+ fn: "assert.looseBytesEq",
336
+ args: [x, y],
337
+ type: BOOL,
338
+ loc,
339
+ })
340
+ : (x, y) => ({
341
+ kind: "call",
342
+ callee: deepEqHelper(lowerer, a.type, loc, true),
343
+ args: [x, y],
344
+ type: BOOL,
345
+ loc,
346
+ });
347
+ return deepCheckCall(lowerer, a, b, "loose", verdictOf, negated, msg, hasMsg, loc, "loose");
348
+ }
349
+ return {
350
+ kind: "libCall",
351
+ fn: "assert.looseDeepDyn",
352
+ args: [
353
+ boxDeepOperand(lowerer, surface, a, aNode, a, b),
354
+ boxDeepOperand(lowerer, surface, b, bNode, a, b),
355
+ boolLit(negated, loc),
356
+ msg,
357
+ hasMsg,
358
+ ],
359
+ type: VOID,
360
+ loc,
361
+ };
362
+ }
363
+ /** The operand types the checked-dynamic deep comparisons refuse: types
364
+ * that can be cyclic, and structures holding functions. Their failure
365
+ * messages render the checked-dynamic copy, which a cyclic value does not
366
+ * have and in which a nested function loses its source name. */
367
+ function refuseUnrenderedDeepOperands(lowerer, surface, operands, hintFor) {
368
+ for (const [value, node] of operands) {
369
+ if (value.type.kind !== "dyn" && typeReachesCycle(lowerer, value.type)) {
370
+ lowerer.noLowering(`${surface} of '${lowerer.fmt(value.type)}' values`, node, `recursive types have no ${hintFor} deep comparison — deepStrictEqual compares them`);
371
+ }
372
+ if (value.type.kind !== "func" && typeReachesFunction(lowerer, value.type)) {
373
+ lowerer.noLowering(`${surface} of '${lowerer.fmt(value.type)}' values`, node, `structures holding functions have no ${hintFor} deep comparison — compare the functions with strictEqual`);
374
+ }
375
+ }
376
+ }
377
+ /** An operand as the checked-dynamic value the runtime comparisons take;
378
+ * a function boxes with its source name for the message. */
379
+ function boxDeepOperand(lowerer, surface, e, node, a, b) {
380
+ if (e.type.kind === "dyn")
381
+ return e;
382
+ const convertible = e.kind === "unitLit" ||
383
+ (e.type.kind === "object" && e.type.className === "%Error") ||
384
+ lowerer.dynConvertible(e.type);
385
+ if (!convertible) {
386
+ lowerer.noLowering(`${surface} of '${lowerer.fmt(a.type)}' and '${lowerer.fmt(b.type)}' values`, node, "both sides must convert into the checked-dynamic tree (primitives, functions, arrays, records, Maps, Sets, typed arrays and errors)");
387
+ }
388
+ const fnName = e.type.kind === "func" ? jsFuncNameOf(node) : null;
389
+ return {
390
+ kind: "dynFrom",
391
+ value: e,
392
+ ...(fnName !== null ? { fnName } : {}),
393
+ type: DYN,
394
+ loc: e.loc,
395
+ };
396
+ }
397
+ /** assert.partialDeepStrictEqual: Node's partial deep comparison (the
398
+ * expected value contained in the actual one), over the checked-dynamic
399
+ * copies of both operands. */
400
+ function lowerAssertPartialDeep(lowerer, expr, loc) {
401
+ const surface = "assert.partialDeepStrictEqual";
402
+ requireStatementPosition(lowerer, expr, surface);
403
+ if (expr.arguments.length < 2 || expr.arguments.length > 3) {
404
+ lowerer.noLowering(`${surface} with ${expr.arguments.length} arguments`, expr);
405
+ }
406
+ const aNode = expr.arguments[0];
407
+ const bNode = expr.arguments[1];
408
+ const { a, b } = lowerComparedOperands(lowerer, aNode, bNode, loc);
409
+ const { msg, hasMsg } = lowerMessageArg(lowerer, expr.arguments[2], loc);
410
+ refuseUnrenderedDeepOperands(lowerer, surface, [
411
+ [a, aNode],
412
+ [b, bNode],
413
+ ], "partial");
414
+ const boxedA = boxDeepOperand(lowerer, surface, a, aNode, a, b);
415
+ const boxedB = boxDeepOperand(lowerer, surface, b, bNode, a, b);
416
+ // Functions box with their source names for the message.
417
+ if (a.type.kind !== "dyn" &&
418
+ b.type.kind !== "dyn" &&
419
+ a.type.kind !== "func" &&
420
+ b.type.kind !== "func") {
421
+ // Statically typed operands compare through the typed partial
422
+ // comparison; only subtrees it does not cover cross into the
423
+ // checked-dynamic tree.
424
+ return deepCheckCall(lowerer, a, b, "partial", (x, y) => partialEqExpr(lowerer, x, y, loc), false, msg, hasMsg, loc, "partial");
425
+ }
426
+ return {
427
+ kind: "libCall",
428
+ fn: "assert.partialDeepDyn",
429
+ args: [boxedA, boxedB, msg, hasMsg],
430
+ type: VOID,
431
+ loc,
432
+ };
433
+ }
434
+ const SCALAR_KINDS = new Set(["f64", "string", "bool", "bigint", "symbol"]);
435
+ /** Node's partial deep comparison of `x` (actual) and `y` (expected), two
436
+ * side-effect-free reads of statically typed values. Scalars compare by
437
+ * Object.is, mismatched primitive kinds are unequal, unions dispatch on
438
+ * their tags, and arrays and records compare through the lifted helper;
439
+ * every other pair compares as checked-dynamic values. */
440
+ function partialEqExpr(lowerer, x, y, loc) {
441
+ const ta = x.type;
442
+ const tb = y.type;
443
+ const helperCall = () => ({
444
+ kind: "call",
445
+ callee: partialEqHelper(lowerer, ta, tb, loc),
446
+ args: [x, y],
447
+ type: BOOL,
448
+ loc,
449
+ });
450
+ // A unit value against a union: equal exactly when the union holds it.
451
+ const unitAgainstUnion = (unit, union, value) => {
452
+ if (!isUnitType(unit) || union.kind !== "union")
453
+ return null;
454
+ const tag = lowerer.armTag(union.unionId, unit);
455
+ if (tag < 0)
456
+ return boolLit(false, loc);
457
+ return {
458
+ kind: "unionIsTag",
459
+ unionId: union.unionId,
460
+ tag,
461
+ negated: false,
462
+ value,
463
+ type: BOOL,
464
+ loc,
465
+ };
466
+ };
467
+ const unitCase = unitAgainstUnion(ta, tb, y) ?? unitAgainstUnion(tb, ta, x);
468
+ if (unitCase)
469
+ return unitCase;
470
+ if (ta.kind === "union" || tb.kind === "union")
471
+ return helperCall();
472
+ if (isUnitType(ta) || isUnitType(tb))
473
+ return boolLit(ta.kind === tb.kind, loc);
474
+ if (SCALAR_KINDS.has(ta.kind) && SCALAR_KINDS.has(tb.kind)) {
475
+ if (ta.kind !== tb.kind)
476
+ return boolLit(false, loc);
477
+ switch (ta.kind) {
478
+ case "f64":
479
+ return { kind: "libCall", fn: "assert.sameValue", args: [x, y], type: BOOL, loc };
480
+ case "bigint":
481
+ return { kind: "libCall", fn: "bigint.eq", args: [x, y], type: BOOL, loc };
482
+ case "string":
483
+ return { kind: "strEq", negated: false, left: x, right: y, type: BOOL, loc };
484
+ default:
485
+ return { kind: "bin", op: "===", left: x, right: y, type: BOOL, loc };
486
+ }
487
+ }
488
+ const composite = (t) => t.kind === "array" || t.kind === "record";
489
+ if ((ta.kind === "array" && tb.kind === "array") ||
490
+ (ta.kind === "record" &&
491
+ tb.kind === "record" &&
492
+ lowerer.shapes.get(ta.shapeId)?.indexValue === undefined &&
493
+ lowerer.shapes.get(tb.shapeId)?.indexValue === undefined)) {
494
+ return helperCall();
495
+ }
496
+ // A primitive never partially equals an array or a record.
497
+ if ((SCALAR_KINDS.has(ta.kind) && composite(tb)) ||
498
+ (composite(ta) && SCALAR_KINDS.has(tb.kind))) {
499
+ return boolLit(false, loc);
500
+ }
501
+ return {
502
+ kind: "libCall",
503
+ fn: "assert.partialEqDyn",
504
+ args: [
505
+ x.type.kind === "dyn" ? x : { kind: "dynFrom", value: x, type: DYN, loc },
506
+ y.type.kind === "dyn" ? y : { kind: "dynFrom", value: y, type: DYN, loc },
507
+ ],
508
+ type: BOOL,
509
+ loc,
510
+ };
511
+ }
512
+ /** The interned `%assert.pdeq.<n>(a, b): boolean` for one pair of static
513
+ * types: union tag dispatch, ordered-subsequence arrays (partialArrayEquiv),
514
+ * or records compared over the expected shape's present fields. */
515
+ function partialEqHelper(lowerer, ta, tb, loc) {
516
+ const key = `assert.pdeq:${typeKey(ta)}|${typeKey(tb)}`;
517
+ const existing = lowerer.assertHelpers.get(key);
518
+ if (existing)
519
+ return existing;
520
+ const name = `%assert.pdeq.${lowerer.assertHelpers.size}`;
521
+ lowerer.assertHelpers.set(key, name);
522
+ const a = () => varRef("a.0", ta, loc);
523
+ const b = () => varRef("b.0", tb, loc);
524
+ const ret = (value) => ({ kind: "return", value, loc });
525
+ const not = (operand) => notExpr(operand, loc);
526
+ const bailIf = (cond) => ({
527
+ kind: "if",
528
+ cond,
529
+ then: [ret(boolLit(false, loc))],
530
+ else_: null,
531
+ loc,
532
+ });
533
+ const locals = [
534
+ { id: "a.0", name: "a", type: ta, mutable: false },
535
+ { id: "b.0", name: "b", type: tb, mutable: false },
536
+ ];
537
+ let body;
538
+ const unionDispatch = (side) => {
539
+ const t = side === "a" ? ta : tb;
540
+ if (t.kind !== "union")
541
+ throw new InternalCompilerError("partial union dispatch over a non-union");
542
+ const def = lowerer.unions.get(t.unionId);
543
+ if (!def)
544
+ throw new InternalCompilerError(`partial deep-equal of unknown union ${t.unionId}`);
545
+ const value = side === "a" ? a() : b();
546
+ const stmts = def.arms.map((arm, tag) => {
547
+ const narrowed = {
548
+ kind: "unionNarrow",
549
+ unionId: t.unionId,
550
+ tag,
551
+ value,
552
+ type: arm,
553
+ loc,
554
+ };
555
+ return {
556
+ kind: "if",
557
+ cond: {
558
+ kind: "unionIsTag",
559
+ unionId: t.unionId,
560
+ tag,
561
+ negated: false,
562
+ value,
563
+ type: BOOL,
564
+ loc,
565
+ },
566
+ then: [
567
+ ret(side === "a"
568
+ ? partialEqExpr(lowerer, narrowed, b(), loc)
569
+ : partialEqExpr(lowerer, a(), narrowed, loc)),
570
+ ],
571
+ else_: null,
572
+ loc,
573
+ };
574
+ });
575
+ stmts.push(ret(boolLit(false, loc)));
576
+ return stmts;
577
+ };
578
+ if (ta.kind === "union") {
579
+ body = unionDispatch("a");
580
+ }
581
+ else if (tb.kind === "union") {
582
+ body = unionDispatch("b");
583
+ }
584
+ else if (ta.kind === "array" && tb.kind === "array") {
585
+ const len = (arr) => ({
586
+ kind: "arrIntrinsic",
587
+ method: "length",
588
+ receiver: arr,
589
+ args: [],
590
+ type: F64,
591
+ loc,
592
+ });
593
+ const pos = () => varRef("pos.0", F64, loc);
594
+ const bump = {
595
+ kind: "assign",
596
+ localId: "pos.0",
597
+ value: { kind: "bin", op: "+", left: pos(), right: numLit(1, loc), type: F64, loc },
598
+ loc,
599
+ };
600
+ locals.push({ id: "i.0", name: "i", type: F64, mutable: true }, { id: "pos.0", name: "pos", type: F64, mutable: true });
601
+ body = [
602
+ bailIf({ kind: "bin", op: "<", left: len(a()), right: len(b()), type: BOOL, loc }),
603
+ { kind: "varDecl", localId: "pos.0", init: numLit(0, loc), loc },
604
+ countedFor(loc, len(b()), (i) => [
605
+ {
606
+ kind: "while",
607
+ cond: not(partialEqExpr(lowerer, { kind: "arrayGet", arr: a(), index: pos(), type: ta.elem, loc }, { kind: "arrayGet", arr: b(), index: i, type: tb.elem, loc }, loc)),
608
+ body: [
609
+ bump,
610
+ // pos > la - lb + i: the rest of b no longer fits in a.
611
+ bailIf({
612
+ kind: "bin",
613
+ op: ">",
614
+ left: pos(),
615
+ right: {
616
+ kind: "bin",
617
+ op: "+",
618
+ left: { kind: "bin", op: "-", left: len(a()), right: len(b()), type: F64, loc },
619
+ right: i,
620
+ type: F64,
621
+ loc,
622
+ },
623
+ type: BOOL,
624
+ loc,
625
+ }),
626
+ ],
627
+ loc,
628
+ },
629
+ bump,
630
+ ]),
631
+ ret(boolLit(true, loc)),
632
+ ];
633
+ }
634
+ else if (ta.kind === "record" && tb.kind === "record") {
635
+ const shapeA = lowerer.shapes.get(ta.shapeId);
636
+ const shapeB = lowerer.shapes.get(tb.shapeId);
637
+ if (!shapeA || !shapeB)
638
+ throw new InternalCompilerError("partial deep-equal of an unknown shape");
639
+ body = [];
640
+ for (const fb of shapeB.fields) {
641
+ const presentB = lowerer.recordFieldPresent(b(), tb.shapeId, fb.name, loc);
642
+ const fa = shapeA.fields.find((f) => f.name === fb.name);
643
+ const checks = [];
644
+ if (!fa) {
645
+ checks.push(ret(boolLit(false, loc)));
646
+ }
647
+ else {
648
+ const presentA = lowerer.recordFieldPresent(a(), ta.shapeId, fa.name, loc);
649
+ if (presentA.kind !== "boolLit")
650
+ checks.push(bailIf(not(presentA)));
651
+ checks.push(bailIf(not(partialEqExpr(lowerer, {
652
+ kind: "recordGet",
653
+ obj: a(),
654
+ shapeId: ta.shapeId,
655
+ field: fa.name,
656
+ type: fa.type,
657
+ loc,
658
+ }, {
659
+ kind: "recordGet",
660
+ obj: b(),
661
+ shapeId: tb.shapeId,
662
+ field: fb.name,
663
+ type: fb.type,
664
+ loc,
665
+ }, loc))));
666
+ }
667
+ if (presentB.kind === "boolLit")
668
+ body.push(...checks);
669
+ else
670
+ body.push({ kind: "if", cond: presentB, then: checks, else_: null, loc });
671
+ }
672
+ body.push(ret(boolLit(true, loc)));
673
+ }
674
+ else {
675
+ throw new InternalCompilerError(`partial deep-equal helper over ${typeKey(ta)} and ${typeKey(tb)}`);
676
+ }
677
+ lowerer.liftedFns.push({
678
+ name,
679
+ params: [
680
+ { localId: "a.0", name: "a", type: ta },
681
+ { localId: "b.0", name: "b", type: tb },
682
+ ],
683
+ returnType: BOOL,
684
+ locals,
685
+ body,
686
+ loc,
687
+ });
688
+ return name;
689
+ }
180
690
  /** The callable-module form: `assert(x)` where the callee identifier IS
181
691
  * the assert module binding — a default import (`import assert from
182
692
  * "node:assert"`) or the CJS `const assert = require("assert")`. Node's
@@ -208,19 +718,34 @@ function lowerAssertOk(lowerer, expr, loc) {
208
718
  lowerer.noLowering(`${expr.expression.getText()} with ${expr.arguments.length} arguments`, expr, "the supported forms are assert(value) and assert(value, message)");
209
719
  }
210
720
  const valueNode = expr.arguments[0];
211
- const pass = lowerer.ensureBool(lowerer.lowerExpr(valueNode), valueNode);
721
+ const stmts = [];
722
+ const value = stableValue(lowerer, stmts, lowerer.lowerExpr(valueNode), "%assertOkValue", loc);
723
+ const pass = stableValue(lowerer, stmts, lowerer.ensureBool(value, valueNode), "%assertOkPass", loc);
212
724
  const msgNode = expr.arguments[1];
725
+ let msg;
726
+ let generated = false;
213
727
  if (!msgNode || (ts.isIdentifier(msgNode) && msgNode.text === "undefined")) {
214
728
  // Node reads the CALLSITE LINE and slices the expression out of it
215
729
  // (internal/errors/error_source.js) — a call spanning lines truncates
216
730
  // at the first newline, so the compile-time text does too.
217
731
  const source = expr.getText().split("\n", 1)[0];
218
- const generated = `The expression evaluated to a falsy value:\n\n ${source}\n`;
219
- const msg = { kind: "strLit", value: generated, type: STRING, loc };
220
- return { kind: "libCall", fn: "assert.ok", args: [pass, msg], type: VOID, loc };
732
+ const text = `The expression evaluated to a falsy value:\n\n ${source}\n`;
733
+ msg = { kind: "strLit", value: text, type: STRING, loc };
734
+ generated = true;
735
+ }
736
+ else {
737
+ msg = lowerMessageArg(lowerer, msgNode, loc).msg;
221
738
  }
222
- const { msg } = lowerMessageArg(lowerer, msgNode, loc);
223
- return { kind: "libCall", fn: "assert.ok", args: [pass, msg], type: VOID, loc };
739
+ // Node's actual is the value, expected true, operator "==".
740
+ stmts.push(recordOnFailure(lowerer, notExpr(pass, loc), value, boolLit(true, loc), "==", loc));
741
+ const result = {
742
+ kind: "libCall",
743
+ fn: "assert.ok",
744
+ args: [pass, msg, boolLit(generated, loc)],
745
+ type: VOID,
746
+ loc,
747
+ };
748
+ return { kind: "seqExpr", stmts, result, type: VOID, loc };
224
749
  }
225
750
  /** assert.fail([message]): an unconditional AssertionError — "Failed"
226
751
  * when the message is omitted (Node's internal default). Lowers as
@@ -231,15 +756,36 @@ function lowerAssertFail(lowerer, expr, loc) {
231
756
  lowerer.noLowering(`assert.fail with ${expr.arguments.length} arguments`, expr, "the supported form is fail(message?) — the deprecated fail(actual, expected, ...) has no lowering");
232
757
  }
233
758
  let msg;
759
+ let generated;
234
760
  const msgNode = expr.arguments[0];
761
+ const stmts = [];
235
762
  if (!msgNode || (ts.isIdentifier(msgNode) && msgNode.text === "undefined")) {
236
763
  msg = { kind: "strLit", value: "Failed", type: STRING, loc };
764
+ generated = boolLit(true, loc);
237
765
  }
238
766
  else {
239
- msg = lowerMessageArg(lowerer, msgNode, loc).msg;
767
+ // Node's AssertionError sets generatedMessage to !message, so an
768
+ // empty custom message counts as generated.
769
+ msg = stableValue(lowerer, stmts, lowerMessageArg(lowerer, msgNode, loc).msg, "%assertFailMessage", loc);
770
+ generated = {
771
+ kind: "strEq",
772
+ negated: false,
773
+ left: msg,
774
+ right: strLit("", loc),
775
+ type: BOOL,
776
+ loc,
777
+ };
240
778
  }
241
779
  const falseLit = { kind: "boolLit", value: false, type: BOOL, loc };
242
- return { kind: "libCall", fn: "assert.ok", args: [falseLit, msg], type: VOID, loc };
780
+ stmts.push(recordOnFailure(lowerer, boolLit(true, loc), null, null, "fail", loc));
781
+ const result = {
782
+ kind: "libCall",
783
+ fn: "assert.ok",
784
+ args: [falseLit, msg, generated],
785
+ type: VOID,
786
+ loc,
787
+ };
788
+ return { kind: "seqExpr", stmts, result, type: VOID, loc };
243
789
  }
244
790
  /** The equality quartet. Scalars (number/string/boolean) compare with
245
791
  * Object.is in the runtime (strictEqual and deepStrictEqual agree there —
@@ -253,34 +799,39 @@ function lowerAssertEqual(lowerer, expr, loc, negated, deep) {
253
799
  if (expr.arguments.length < 2 || expr.arguments.length > 3) {
254
800
  lowerer.noLowering(`${surface} with ${expr.arguments.length} arguments`, expr);
255
801
  }
256
- // A context-free EMPTY array literal on either side has no element type
257
- // of its own (`deepStrictEqual(ee.listeners('x'), [])` — the checker
258
- // says any[]): it adopts the OTHER side's array type. Literals have no
259
- // side effects, so lowering order is unobservable.
260
802
  const aNode = expr.arguments[0];
261
803
  const bNode = expr.arguments[1];
262
- const emptyArrayLit = (n) => ts.isArrayLiteralExpression(n) && n.elements.length === 0;
263
- const emptyOf = (t) => ({ kind: "arrayLit", elems: [], type: t, loc });
264
- // A dyn other side adopts number[] — the dyn array a boxed empty
265
- // literal builds is elementless, so any elem type serves.
266
- const adoptedEmpty = (other) => other.kind === "array"
267
- ? emptyOf(other)
268
- : other.kind === "dyn"
269
- ? emptyOf({ kind: "array", elem: F64 })
270
- : null;
271
- let a;
272
- let b;
273
- if (emptyArrayLit(aNode) && !emptyArrayLit(bNode)) {
274
- b = lowerer.lowerExpr(bNode);
275
- a = adoptedEmpty(b.type) ?? lowerer.lowerExpr(aNode);
276
- }
277
- else {
278
- a = lowerer.lowerExpr(aNode);
279
- b = emptyArrayLit(bNode)
280
- ? (adoptedEmpty(a.type) ?? lowerer.lowerExpr(bNode))
281
- : lowerer.lowerExpr(bNode);
282
- }
804
+ const { a, b } = lowerComparedOperands(lowerer, aNode, bNode, loc);
283
805
  const { msg, hasMsg } = lowerMessageArg(lowerer, expr.arguments[2], loc);
806
+ // An Assert instance with skipPrototype: Node compares own properties
807
+ // without the prototype check, so operands of different static types (two
808
+ // classes, a class and a record) can be equal. They compare as
809
+ // checked-dynamic values, and so do class instances, which have no typed
810
+ // deep comparison; the runtime walk skips the prototype check for the
811
+ // call (assert-instances.ts). Other same-typed operands keep their typed
812
+ // comparison.
813
+ const skipPrototype = deep && lowerer.assertCallOptions?.skipPrototype === true;
814
+ if (skipPrototype &&
815
+ a.type.kind !== "dyn" &&
816
+ b.type.kind !== "dyn" &&
817
+ (!typeEquals(a.type, b.type) || deepUnsupportedReason(lowerer, a.type, new Set()) !== null)) {
818
+ const box = (e, node) => {
819
+ if (e.kind !== "unitLit" &&
820
+ (!lowerer.dynConvertible(e.type) ||
821
+ typeReachesCycle(lowerer, e.type) ||
822
+ typeReachesFunction(lowerer, e.type))) {
823
+ lowerer.noLowering(`${surface} with skipPrototype of '${lowerer.fmt(a.type)}' and '${lowerer.fmt(b.type)}' values`, node, "operands of different static types compare as checked-dynamic values, which this operand does not convert to");
824
+ }
825
+ return { kind: "dynFrom", value: e, type: DYN, loc: e.loc };
826
+ };
827
+ return {
828
+ kind: "libCall",
829
+ fn: "assert.eqDyn",
830
+ args: [box(a, aNode), box(b, bNode), boolLit(negated, loc), boolLit(true, loc), msg, hasMsg],
831
+ type: VOID,
832
+ loc,
833
+ };
834
+ }
284
835
  // CHECKED-DYNAMIC operands (dyn-vs-dyn, dyn-vs-static): both sides
285
836
  // cross into the checked-dynamic tree and one runtime entry answers the whole quartet —
286
837
  // SameValue for the strict pair (boxed-closure identity for
@@ -321,7 +872,10 @@ function lowerAssertEqual(lowerer, expr, loc, negated, deep) {
321
872
  // same). The deep walk compares the retained error data without
322
873
  // re-encoding and losing identity (SEMANTICS.md).
323
874
  (k === "object" && e.type.kind === "object" && e.type.className === "%Error") ||
324
- (deep && k !== "bytes" && k !== "object" && lowerer.dynConvertible(e.type));
875
+ (deep && k !== "bytes" && k !== "object" && lowerer.dynConvertible(e.type)) ||
876
+ // Under skipPrototype the prototype a class instance or Buffer
877
+ // brand would carry is not compared.
878
+ (skipPrototype && lowerer.dynConvertible(e.type));
325
879
  if (!ok) {
326
880
  const hint = !deep && (k === "record" || k === "array" || k === "map" || k === "set" || k === "union")
327
881
  ? "strictEqual on objects is reference equality, which does not survive the unknown boundary (values copy when they cross) — deepStrictEqual compares structure, or narrow the unknown side first"
@@ -401,23 +955,18 @@ function lowerAssertEqual(lowerer, expr, loc, negated, deep) {
401
955
  loc,
402
956
  };
403
957
  }
404
- if (brandA === null || brandB === null) {
958
+ if (!skipPrototype && (brandA === null || brandB === null)) {
405
959
  lowerer.noLowering(`${surface} of typed-array values whose constructor is not in the static type`, brandA === null ? expr.arguments[0] : expr.arguments[1], "Node's deep equality compares prototypes (a Buffer is never deep-equal to a plain Uint8Array) — annotate the value so its constructor is visible");
406
960
  }
407
- const verdict = {
961
+ // The brand is the prototype; skipPrototype ignores it.
962
+ const sameBrand = skipPrototype || brandA === brandB;
963
+ return deepCheckCall(lowerer, a, b, `bytes:${sameBrand}`, (x, y) => ({
408
964
  kind: "libCall",
409
965
  fn: "assert.bytesDeepEq",
410
- args: [a, b, boolLit(brandA === brandB, loc)],
966
+ args: [x, y, boolLit(sameBrand, loc)],
411
967
  type: BOOL,
412
968
  loc,
413
- };
414
- return {
415
- kind: "libCall",
416
- fn: "assert.deepResult",
417
- args: [verdict, boolLit(negated, loc), msg, hasMsg],
418
- type: VOID,
419
- loc,
420
- };
969
+ }), negated, msg, hasMsg, loc);
421
970
  }
422
971
  // Function values (ANY two static signatures — a tuple-typed
423
972
  // listeners() element against a prefix-declared handler): strictEqual
@@ -461,11 +1010,62 @@ function lowerAssertEqual(lowerer, expr, loc, negated, deep) {
461
1010
  lowerer.noLowering(`${surface} of '${lowerer.fmt(a.type)}' values`, expr, unsupported);
462
1011
  }
463
1012
  const helper = deepEqHelper(lowerer, a.type, loc);
464
- const verdict = { kind: "call", callee: helper, args: [a, b], type: BOOL, loc };
1013
+ return deepCheckCall(lowerer, a, b, "deep", (x, y) => ({ kind: "call", callee: helper, args: [x, y], type: BOOL, loc }), negated, msg, hasMsg, loc);
1014
+ }
1015
+ /** `assert.deepResult(%assert.dcheck.<n>(a, b), negated, msg, hasMsg)`.
1016
+ * The wrapper returns the verdict and, on failure, records actual and
1017
+ * expected. The operands are its parameters, so the call site passes them
1018
+ * as temporaries and a passing assertion holds no extra reference. */
1019
+ function deepCheckCall(lowerer, a, b, variant, verdictOf, negated, msg, hasMsg, loc, mode = "strict") {
1020
+ const key = `assert.dcheck:${variant}:${negated}:${typeKey(a.type)}:${typeKey(b.type)}`;
1021
+ let name = lowerer.assertHelpers.get(key);
1022
+ if (!name) {
1023
+ name = `%assert.dcheck.${lowerer.assertHelpers.size}`;
1024
+ lowerer.assertHelpers.set(key, name);
1025
+ const pa = varRef("a.0", a.type, loc);
1026
+ const pb = varRef("b.0", b.type, loc);
1027
+ const verdict = varRef("v.0", BOOL, loc);
1028
+ lowerer.liftedFns.push({
1029
+ name,
1030
+ params: [
1031
+ { localId: "a.0", name: "a", type: a.type },
1032
+ { localId: "b.0", name: "b", type: b.type },
1033
+ ],
1034
+ returnType: BOOL,
1035
+ locals: [
1036
+ { id: "a.0", name: "a", type: a.type, mutable: false },
1037
+ { id: "b.0", name: "b", type: b.type, mutable: false },
1038
+ { id: "v.0", name: "verdict", type: BOOL, mutable: false },
1039
+ ],
1040
+ body: [
1041
+ { kind: "varDecl", localId: "v.0", init: verdictOf(pa, pb), loc },
1042
+ recordOnFailure(lowerer, negated ? verdict : notExpr(verdict, loc), pa, pb, mode === "partial"
1043
+ ? "partialDeepStrictEqual"
1044
+ : mode === "loose"
1045
+ ? negated
1046
+ ? "notDeepEqual"
1047
+ : "deepEqual"
1048
+ : negated
1049
+ ? "notDeepStrictEqual"
1050
+ : "deepStrictEqual", loc),
1051
+ { kind: "return", value: verdict, loc },
1052
+ ],
1053
+ loc,
1054
+ });
1055
+ }
465
1056
  return {
466
1057
  kind: "libCall",
467
- fn: "assert.deepResult",
468
- args: [verdict, boolLit(negated, loc), msg, hasMsg],
1058
+ fn: mode === "partial"
1059
+ ? "assert.partialDeepResult"
1060
+ : mode === "loose"
1061
+ ? "assert.looseDeepResult"
1062
+ : "assert.deepResult",
1063
+ args: [
1064
+ { kind: "call", callee: name, args: [a, b], type: BOOL, loc },
1065
+ boolLit(negated, loc),
1066
+ msg,
1067
+ hasMsg,
1068
+ ],
469
1069
  type: VOID,
470
1070
  loc,
471
1071
  };
@@ -893,7 +1493,20 @@ function assertThrowsHelper(lowerer, mode, recvType, recvIsPromise, expected, lo
893
1493
  let catchBody;
894
1494
  if (mode === "dnr" || mode === "dnt") {
895
1495
  const actual = () => ({ kind: "caughtToDyn", value: caughtRef(), type: DYN, loc });
896
- const unwanted = () => lib("assert.unwantedError", [
1496
+ // Node's actual is the caught value.
1497
+ const unwanted = () => ({
1498
+ kind: "block",
1499
+ body: [
1500
+ lib("assert.record", [
1501
+ actual(),
1502
+ dynUndefinedExpr(loc),
1503
+ strLit(mode === "dnr" ? "doesNotReject" : "doesNotThrow", loc),
1504
+ ]),
1505
+ unwantedCall(),
1506
+ ],
1507
+ loc,
1508
+ });
1509
+ const unwantedCall = () => lib("assert.unwantedError", [
897
1510
  {
898
1511
  kind: "libCall",
899
1512
  fn: "util.toUSVString",
@@ -1002,6 +1615,7 @@ function assertThrowsHelper(lowerer, mode, recvType, recvIsPromise, expected, lo
1002
1615
  narrowed(),
1003
1616
  m(),
1004
1617
  hm(),
1618
+ boolLit(mode === "rejects", loc),
1005
1619
  ]),
1006
1620
  ]),
1007
1621
  // A non-Error thrown value: propagate (SEMANTICS.md 104; the
@@ -1013,7 +1627,13 @@ function assertThrowsHelper(lowerer, mode, recvType, recvIsPromise, expected, lo
1013
1627
  case "regex":
1014
1628
  catchBody = [
1015
1629
  ifStmt(isInstance("%Error"), [
1016
- lib("assert.throwsRegex", [varRef("re.0", REGEX, loc), narrowed(), m(), hm()]),
1630
+ lib("assert.throwsRegex", [
1631
+ varRef("re.0", REGEX, loc),
1632
+ narrowed(),
1633
+ m(),
1634
+ hm(),
1635
+ boolLit(mode === "rejects", loc),
1636
+ ]),
1017
1637
  doReturn,
1018
1638
  ]),
1019
1639
  rethrow,
@@ -1023,7 +1643,7 @@ function assertThrowsHelper(lowerer, mode, recvType, recvIsPromise, expected, lo
1023
1643
  catchBody = [
1024
1644
  ifStmt(isInstance("%Error"), [
1025
1645
  ...shapeSlotStmts(),
1026
- lib("assert.shapeEnd", [m(), hm()]),
1646
+ lib("assert.shapeEnd", [m(), hm(), boolLit(mode === "rejects", loc)]),
1027
1647
  doReturn,
1028
1648
  ]),
1029
1649
  rethrow,
@@ -1150,6 +1770,7 @@ function lowerAssertIfError(lowerer, expr, loc) {
1150
1770
  args: [
1151
1771
  { kind: "boolLit", value: true, type: BOOL, loc },
1152
1772
  { kind: "strLit", value: "", type: STRING, loc },
1773
+ { kind: "boolLit", value: true, type: BOOL, loc },
1153
1774
  ],
1154
1775
  type: VOID,
1155
1776
  loc,
@@ -1168,6 +1789,7 @@ function lowerAssertIfError(lowerer, expr, loc) {
1168
1789
  args: [
1169
1790
  { kind: "boolLit", value: true, type: BOOL, loc },
1170
1791
  { kind: "strLit", value: "", type: STRING, loc },
1792
+ { kind: "boolLit", value: true, type: BOOL, loc },
1171
1793
  ],
1172
1794
  type: VOID,
1173
1795
  loc,
@@ -1289,8 +1911,8 @@ function bytesBrandOf(lowerer, node) {
1289
1911
  }
1290
1912
  /* ── deep equality (deepStrictEqual / notDeepStrictEqual) ──────────────── */
1291
1913
  /** Why `t` has no honest deep comparison, or null when it lowers. The
1292
- * fence names the FIRST unsupported constituent — never a silent
1293
- * miscompare. Recursive record shapes terminate through `visiting`
1914
+ * fence names the FIRST unsupported constituent instead of emitting a
1915
+ * wrong comparison. Recursive record shapes terminate through `visiting`
1294
1916
  * (a shape being checked is assumed fine; its own walk decides). */
1295
1917
  function deepUnsupportedReason(lowerer, t, visiting) {
1296
1918
  switch (t.kind) {
@@ -1367,12 +1989,15 @@ function deepUnsupportedReason(lowerer, t, visiting) {
1367
1989
  * tag+payload unions, SameValueZero-keyed Maps with deep values, scalar
1368
1990
  * Sets by membership. Registered in the cache BEFORE the body builds, so
1369
1991
  * recursive record shapes call themselves by name. */
1370
- function deepEqHelper(lowerer, t, loc) {
1371
- const key = `assert.deq:${typeKey(t)}`;
1992
+ function deepEqHelper(lowerer, t, loc, loose = false) {
1993
+ // The loose mode (deepEqual over one union-free type) differs only in
1994
+ // numbers: == with NaN equal to NaN.
1995
+ const prefix = loose ? "ldeq" : "deq";
1996
+ const key = `assert.${prefix}:${typeKey(t)}`;
1372
1997
  const existing = lowerer.assertHelpers.get(key);
1373
1998
  if (existing)
1374
1999
  return existing;
1375
- const name = `%assert.deq.${lowerer.assertHelpers.size}`;
2000
+ const name = `%assert.${prefix}.${lowerer.assertHelpers.size}`;
1376
2001
  lowerer.assertHelpers.set(key, name);
1377
2002
  const a = () => varRef("a.0", t, loc);
1378
2003
  const b = () => varRef("b.0", t, loc);
@@ -1398,7 +2023,13 @@ function deepEqHelper(lowerer, t, loc) {
1398
2023
  /** Deep-compare two same-typed exprs through the per-type helper. */
1399
2024
  const deq = (elemT, x, y) => isUnitType(elemT)
1400
2025
  ? boolLit(true, loc)
1401
- : { kind: "call", callee: deepEqHelper(lowerer, elemT, loc), args: [x, y], type: BOOL, loc };
2026
+ : {
2027
+ kind: "call",
2028
+ callee: deepEqHelper(lowerer, elemT, loc, loose),
2029
+ args: [x, y],
2030
+ type: BOOL,
2031
+ loc,
2032
+ };
1402
2033
  let locals = [
1403
2034
  { id: "a.0", name: "a", type: t, mutable: false },
1404
2035
  { id: "b.0", name: "b", type: t, mutable: false },
@@ -1406,7 +2037,15 @@ function deepEqHelper(lowerer, t, loc) {
1406
2037
  let body;
1407
2038
  switch (t.kind) {
1408
2039
  case "f64":
1409
- body = [ret({ kind: "libCall", fn: "assert.sameValue", args: [a(), b()], type: BOOL, loc })];
2040
+ body = [
2041
+ ret({
2042
+ kind: "libCall",
2043
+ fn: loose ? "assert.looseF64Eq" : "assert.sameValue",
2044
+ args: [a(), b()],
2045
+ type: BOOL,
2046
+ loc,
2047
+ }),
2048
+ ];
1410
2049
  break;
1411
2050
  case "bigint":
1412
2051
  body = [ret({ kind: "libCall", fn: "bigint.eq", args: [a(), b()], type: BOOL, loc })];