@scriptc/compiler 0.3.3 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (352) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +844 -36
  2. package/dist/backend/cycle-mutability.d.ts +5 -0
  3. package/dist/backend/cycle-mutability.js +62 -3
  4. package/dist/backend/cycle-mutability.js.map +1 -1
  5. package/dist/backend/executable-features.js +1 -0
  6. package/dist/backend/executable-features.js.map +1 -1
  7. package/dist/backend/library-pack.js +1 -0
  8. package/dist/backend/library-pack.js.map +1 -1
  9. package/dist/backend/llvm/array-search.js +1 -1
  10. package/dist/backend/llvm/array-search.js.map +1 -1
  11. package/dist/backend/llvm/call-lifetimes.d.ts +11 -1
  12. package/dist/backend/llvm/call-lifetimes.js +30 -3
  13. package/dist/backend/llvm/call-lifetimes.js.map +1 -1
  14. package/dist/backend/llvm/call-lifetimes.test.js +31 -1
  15. package/dist/backend/llvm/call-lifetimes.test.js.map +1 -1
  16. package/dist/backend/llvm/common.d.ts +5 -0
  17. package/dist/backend/llvm/common.js +7 -0
  18. package/dist/backend/llvm/common.js.map +1 -1
  19. package/dist/backend/llvm/constant-callbacks.d.ts +2 -21
  20. package/dist/backend/llvm/constant-callbacks.js +36 -219
  21. package/dist/backend/llvm/constant-callbacks.js.map +1 -1
  22. package/dist/backend/llvm/constant-callbacks.test.js +22 -0
  23. package/dist/backend/llvm/constant-callbacks.test.js.map +1 -1
  24. package/dist/backend/llvm/dense-array-access.d.ts +9 -0
  25. package/dist/backend/llvm/dense-array-access.js +29 -3
  26. package/dist/backend/llvm/dense-array-access.js.map +1 -1
  27. package/dist/backend/llvm/dyn.d.ts +46 -1
  28. package/dist/backend/llvm/dyn.js +218 -33
  29. package/dist/backend/llvm/dyn.js.map +1 -1
  30. package/dist/backend/llvm/emitter.d.ts +87 -1
  31. package/dist/backend/llvm/emitter.js +568 -61
  32. package/dist/backend/llvm/emitter.js.map +1 -1
  33. package/dist/backend/llvm/expr-async.js +17 -7
  34. package/dist/backend/llvm/expr-async.js.map +1 -1
  35. package/dist/backend/llvm/expr-bytes.d.ts +9 -0
  36. package/dist/backend/llvm/expr-bytes.js +159 -64
  37. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  38. package/dist/backend/llvm/expr-callbacks.d.ts +11 -0
  39. package/dist/backend/llvm/expr-callbacks.js +53 -0
  40. package/dist/backend/llvm/expr-callbacks.js.map +1 -1
  41. package/dist/backend/llvm/expr-calls.d.ts +3 -1
  42. package/dist/backend/llvm/expr-calls.js +137 -3
  43. package/dist/backend/llvm/expr-calls.js.map +1 -1
  44. package/dist/backend/llvm/expr-containers.js +63 -29
  45. package/dist/backend/llvm/expr-containers.js.map +1 -1
  46. package/dist/backend/llvm/expr-primitives.js +9 -1
  47. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  48. package/dist/backend/llvm/expr-stream-bridges.js +4 -0
  49. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  50. package/dist/backend/llvm/integer-clones.d.ts +103 -0
  51. package/dist/backend/llvm/integer-clones.js +1336 -0
  52. package/dist/backend/llvm/integer-clones.js.map +1 -0
  53. package/dist/backend/llvm/integer-clones.test.d.ts +1 -0
  54. package/dist/backend/llvm/integer-clones.test.js +219 -0
  55. package/dist/backend/llvm/integer-clones.test.js.map +1 -0
  56. package/dist/backend/llvm/intern-tables.test.d.ts +1 -0
  57. package/dist/backend/llvm/intern-tables.test.js +77 -0
  58. package/dist/backend/llvm/intern-tables.test.js.map +1 -0
  59. package/dist/backend/llvm/lib-datagram.js +24 -0
  60. package/dist/backend/llvm/lib-datagram.js.map +1 -1
  61. package/dist/backend/llvm/lib-dispatch.js +96 -1
  62. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  63. package/dist/backend/llvm/lib-filesystem.js +51 -0
  64. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  65. package/dist/backend/llvm/lib-network.js +16 -0
  66. package/dist/backend/llvm/lib-network.js.map +1 -1
  67. package/dist/backend/llvm/lib-process.js +24 -0
  68. package/dist/backend/llvm/lib-process.js.map +1 -1
  69. package/dist/backend/llvm/lib-shared.d.ts +5 -0
  70. package/dist/backend/llvm/lib-shared.js +114 -3
  71. package/dist/backend/llvm/lib-shared.js.map +1 -1
  72. package/dist/backend/llvm/lib-stream.js +87 -0
  73. package/dist/backend/llvm/lib-stream.js.map +1 -1
  74. package/dist/backend/llvm/lib-test.js +9 -0
  75. package/dist/backend/llvm/lib-test.js.map +1 -1
  76. package/dist/backend/llvm/lib-tls.js +6 -0
  77. package/dist/backend/llvm/lib-tls.js.map +1 -1
  78. package/dist/backend/llvm/local-array-reads.js +1 -1
  79. package/dist/backend/llvm/local-array-reads.js.map +1 -1
  80. package/dist/backend/llvm/map-entry-fusion.d.ts +28 -0
  81. package/dist/backend/llvm/map-entry-fusion.js +233 -0
  82. package/dist/backend/llvm/map-entry-fusion.js.map +1 -0
  83. package/dist/backend/llvm/map-entry-fusion.test.d.ts +1 -0
  84. package/dist/backend/llvm/map-entry-fusion.test.js +183 -0
  85. package/dist/backend/llvm/map-entry-fusion.test.js.map +1 -0
  86. package/dist/backend/llvm/map-number-lookup.d.ts +6 -0
  87. package/dist/backend/llvm/map-number-lookup.js +23 -1
  88. package/dist/backend/llvm/map-number-lookup.js.map +1 -1
  89. package/dist/backend/llvm/map-number-lookup.test.js +60 -5
  90. package/dist/backend/llvm/map-number-lookup.test.js.map +1 -1
  91. package/dist/backend/llvm/map-read-lifetimes.d.ts +11 -0
  92. package/dist/backend/llvm/map-read-lifetimes.js +92 -1
  93. package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
  94. package/dist/backend/llvm/map-read-lifetimes.test.js +131 -3
  95. package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -1
  96. package/dist/backend/llvm/publish.d.ts +21 -0
  97. package/dist/backend/llvm/publish.js +101 -11
  98. package/dist/backend/llvm/publish.js.map +1 -1
  99. package/dist/backend/llvm/publish.test.d.ts +1 -0
  100. package/dist/backend/llvm/publish.test.js +94 -0
  101. package/dist/backend/llvm/publish.test.js.map +1 -0
  102. package/dist/backend/llvm/record-results.js +76 -2
  103. package/dist/backend/llvm/record-results.js.map +1 -1
  104. package/dist/backend/llvm/record-sources.d.ts +7 -0
  105. package/dist/backend/llvm/record-sources.js +14 -0
  106. package/dist/backend/llvm/record-sources.js.map +1 -0
  107. package/dist/backend/llvm/reference-writes.js +5 -2
  108. package/dist/backend/llvm/reference-writes.js.map +1 -1
  109. package/dist/backend/llvm/regions.d.ts +4 -1
  110. package/dist/backend/llvm/regions.js +12 -3
  111. package/dist/backend/llvm/regions.js.map +1 -1
  112. package/dist/backend/llvm/shapes.d.ts +9 -3
  113. package/dist/backend/llvm/shapes.js +18 -14
  114. package/dist/backend/llvm/shapes.js.map +1 -1
  115. package/dist/backend/llvm/shapes.test.js +5 -3
  116. package/dist/backend/llvm/shapes.test.js.map +1 -1
  117. package/dist/backend/llvm/string-lifetimes.test.js +75 -1
  118. package/dist/backend/llvm/string-lifetimes.test.js.map +1 -1
  119. package/dist/backend/llvm/string-reads.js +2 -2
  120. package/dist/backend/llvm/string-reads.js.map +1 -1
  121. package/dist/backend/llvm/string-slices.js +2 -2
  122. package/dist/backend/llvm/string-slices.js.map +1 -1
  123. package/dist/backend/llvm/walkers.d.ts +17 -0
  124. package/dist/backend/llvm/walkers.js +123 -0
  125. package/dist/backend/llvm/walkers.js.map +1 -1
  126. package/dist/backend/may-throw.js +4 -0
  127. package/dist/backend/may-throw.js.map +1 -1
  128. package/dist/backend/native/contracts.d.ts +5 -1
  129. package/dist/backend/native/executable.js +16 -6
  130. package/dist/backend/native/executable.js.map +1 -1
  131. package/dist/backend/native/runtime-inputs.d.ts +1 -1
  132. package/dist/backend/native/runtime-inputs.js +1 -0
  133. package/dist/backend/native/runtime-inputs.js.map +1 -1
  134. package/dist/backend/native-codegen-core.d.ts +4 -4
  135. package/dist/backend/native-codegen-core.js +4 -6
  136. package/dist/backend/native-codegen-core.js.map +1 -1
  137. package/dist/backend/native-codegen.test.js +7 -8
  138. package/dist/backend/native-codegen.test.js.map +1 -1
  139. package/dist/backend/native-link-info-core.d.ts +3 -0
  140. package/dist/backend/native-link-info-core.js.map +1 -1
  141. package/dist/backend/publication.js +3 -1
  142. package/dist/backend/publication.js.map +1 -1
  143. package/dist/backend/runtime-abi.d.ts +2 -2
  144. package/dist/backend/runtime-abi.js +2 -2
  145. package/dist/backend/runtime-pack-targets.test.js +2 -1
  146. package/dist/backend/runtime-pack-targets.test.js.map +1 -1
  147. package/dist/backend/runtime-pack.test.js +2 -1
  148. package/dist/backend/runtime-pack.test.js.map +1 -1
  149. package/dist/backend/target-diagnostics.js +7 -0
  150. package/dist/backend/target-diagnostics.js.map +1 -1
  151. package/dist/backend/warm-cache.js +1 -0
  152. package/dist/backend/warm-cache.js.map +1 -1
  153. package/dist/executable/executable-cache.d.ts +1 -0
  154. package/dist/executable/executable-cache.js +1 -0
  155. package/dist/executable/executable-cache.js.map +1 -1
  156. package/dist/executable/executable-cache.test.js +1 -0
  157. package/dist/executable/executable-cache.test.js.map +1 -1
  158. package/dist/frontend/experimental-import.d.ts +5 -1
  159. package/dist/frontend/experimental-import.js +28 -3
  160. package/dist/frontend/experimental-import.js.map +1 -1
  161. package/dist/frontend/lowering/assert-instances.d.ts +38 -0
  162. package/dist/frontend/lowering/assert-instances.js +269 -0
  163. package/dist/frontend/lowering/assert-instances.js.map +1 -0
  164. package/dist/frontend/lowering/builtin-calls.js +3 -0
  165. package/dist/frontend/lowering/builtin-calls.js.map +1 -1
  166. package/dist/frontend/lowering/builtins/callable-aliases.js +54 -8
  167. package/dist/frontend/lowering/builtins/callable-aliases.js.map +1 -1
  168. package/dist/frontend/lowering/builtins/child-process-async.d.ts +8 -6
  169. package/dist/frontend/lowering/builtins/child-process-async.js +45 -29
  170. package/dist/frontend/lowering/builtins/child-process-async.js.map +1 -1
  171. package/dist/frontend/lowering/builtins/compression.d.ts +18 -0
  172. package/dist/frontend/lowering/builtins/compression.js +175 -2
  173. package/dist/frontend/lowering/builtins/compression.js.map +1 -1
  174. package/dist/frontend/lowering/builtins/constants.js +7 -2
  175. package/dist/frontend/lowering/builtins/constants.js.map +1 -1
  176. package/dist/frontend/lowering/builtins/crypto.d.ts +6 -0
  177. package/dist/frontend/lowering/builtins/crypto.js +111 -1
  178. package/dist/frontend/lowering/builtins/crypto.js.map +1 -1
  179. package/dist/frontend/lowering/builtins/errors.js +23 -0
  180. package/dist/frontend/lowering/builtins/errors.js.map +1 -1
  181. package/dist/frontend/lowering/builtins/filesystem-calls.d.ts +2 -0
  182. package/dist/frontend/lowering/builtins/filesystem-calls.js +5 -0
  183. package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -1
  184. package/dist/frontend/lowering/builtins/filesystem.js +60 -0
  185. package/dist/frontend/lowering/builtins/filesystem.js.map +1 -1
  186. package/dist/frontend/lowering/builtins/fs-streams.d.ts +26 -0
  187. package/dist/frontend/lowering/builtins/fs-streams.js +131 -0
  188. package/dist/frontend/lowering/builtins/fs-streams.js.map +1 -0
  189. package/dist/frontend/lowering/builtins/module-calls.js +5 -1
  190. package/dist/frontend/lowering/builtins/module-calls.js.map +1 -1
  191. package/dist/frontend/lowering/builtins/timers.d.ts +3 -0
  192. package/dist/frontend/lowering/builtins/timers.js +109 -23
  193. package/dist/frontend/lowering/builtins/timers.js.map +1 -1
  194. package/dist/frontend/lowering/call-signatures.js +6 -0
  195. package/dist/frontend/lowering/call-signatures.js.map +1 -1
  196. package/dist/frontend/lowering/class-dynamic-dispatch.js +216 -20
  197. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  198. package/dist/frontend/lowering/containers/bytes.js +33 -12
  199. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  200. package/dist/frontend/lowering/devirtualize.js +20 -7
  201. package/dist/frontend/lowering/devirtualize.js.map +1 -1
  202. package/dist/frontend/lowering/intern-tables.d.ts +13 -0
  203. package/dist/frontend/lowering/intern-tables.js +536 -0
  204. package/dist/frontend/lowering/intern-tables.js.map +1 -0
  205. package/dist/frontend/lowering/lower-assert.js +700 -61
  206. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  207. package/dist/frontend/lowering/lower-async-iteration.js +11 -2
  208. package/dist/frontend/lowering/lower-async-iteration.js.map +1 -1
  209. package/dist/frontend/lowering/lower-calls.js +75 -6
  210. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  211. package/dist/frontend/lowering/lower-classes.d.ts +3 -0
  212. package/dist/frontend/lowering/lower-classes.js +43 -0
  213. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  214. package/dist/frontend/lowering/lower-dgram.js +132 -67
  215. package/dist/frontend/lowering/lower-dgram.js.map +1 -1
  216. package/dist/frontend/lowering/lower-event-emitter.d.ts +9 -1
  217. package/dist/frontend/lowering/lower-event-emitter.js +78 -0
  218. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
  219. package/dist/frontend/lowering/lower-exprs.d.ts +4 -0
  220. package/dist/frontend/lowering/lower-exprs.js +144 -58
  221. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  222. package/dist/frontend/lowering/lower-inspect.d.ts +6 -0
  223. package/dist/frontend/lowering/lower-inspect.js +138 -39
  224. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  225. package/dist/frontend/lowering/lower-mock.d.ts +11 -0
  226. package/dist/frontend/lowering/lower-mock.js +504 -0
  227. package/dist/frontend/lowering/lower-mock.js.map +1 -0
  228. package/dist/frontend/lowering/lower-modules.js +7 -0
  229. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  230. package/dist/frontend/lowering/lower-server.d.ts +4 -0
  231. package/dist/frontend/lowering/lower-server.js +448 -30
  232. package/dist/frontend/lowering/lower-server.js.map +1 -1
  233. package/dist/frontend/lowering/lower-stmts.js +35 -8
  234. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  235. package/dist/frontend/lowering/lower-stream.d.ts +10 -6
  236. package/dist/frontend/lowering/lower-stream.js +794 -27
  237. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  238. package/dist/frontend/lowering/lower-test.js +86 -8
  239. package/dist/frontend/lowering/lower-test.js.map +1 -1
  240. package/dist/frontend/lowering/lowerer.d.ts +25 -1
  241. package/dist/frontend/lowering/lowerer.js +74 -9
  242. package/dist/frontend/lowering/lowerer.js.map +1 -1
  243. package/dist/frontend/lowering/pairs-snapshot.d.ts +6 -0
  244. package/dist/frontend/lowering/pairs-snapshot.js +49 -0
  245. package/dist/frontend/lowering/pairs-snapshot.js.map +1 -1
  246. package/dist/frontend/lowering/record-sources.d.ts +15 -0
  247. package/dist/frontend/lowering/record-sources.js +46 -0
  248. package/dist/frontend/lowering/record-sources.js.map +1 -0
  249. package/dist/frontend/lowering/surfaces.d.ts +4 -0
  250. package/dist/frontend/lowering/surfaces.js +94 -16
  251. package/dist/frontend/lowering/surfaces.js.map +1 -1
  252. package/dist/frontend/lowering/zlib-constants.d.ts +1 -0
  253. package/dist/frontend/lowering/zlib-constants.js +181 -0
  254. package/dist/frontend/lowering/zlib-constants.js.map +1 -0
  255. package/dist/frontend/mock-shapes.d.ts +10 -0
  256. package/dist/frontend/mock-shapes.js +76 -0
  257. package/dist/frontend/mock-shapes.js.map +1 -0
  258. package/dist/frontend/pipeline.js +5 -3
  259. package/dist/frontend/pipeline.js.map +1 -1
  260. package/dist/frontend/program.js +6 -1
  261. package/dist/frontend/program.js.map +1 -1
  262. package/dist/frontend/resolve.d.ts +4 -0
  263. package/dist/frontend/resolve.js +14 -0
  264. package/dist/frontend/resolve.js.map +1 -1
  265. package/dist/frontend/tsc-codes.js +1 -0
  266. package/dist/frontend/tsc-codes.js.map +1 -1
  267. package/dist/frontend/type-mapper.d.ts +8 -0
  268. package/dist/frontend/type-mapper.js +155 -9
  269. package/dist/frontend/type-mapper.js.map +1 -1
  270. package/dist/index.js +2 -1
  271. package/dist/index.js.map +1 -1
  272. package/dist/ir/analysis.d.ts +10 -0
  273. package/dist/ir/analysis.js +35 -0
  274. package/dist/ir/analysis.js.map +1 -1
  275. package/dist/ir/analysis.test.js +69 -1
  276. package/dist/ir/analysis.test.js.map +1 -1
  277. package/dist/ir/builtin-effects.js +72 -0
  278. package/dist/ir/builtin-effects.js.map +1 -1
  279. package/dist/ir/builtin-signatures.d.ts +1 -1
  280. package/dist/ir/builtin-signatures.js +238 -15
  281. package/dist/ir/builtin-signatures.js.map +1 -1
  282. package/dist/ir/capture-values.d.ts +107 -0
  283. package/dist/ir/capture-values.js +850 -0
  284. package/dist/ir/capture-values.js.map +1 -0
  285. package/dist/ir/capture-values.test.d.ts +1 -0
  286. package/dist/ir/capture-values.test.js +268 -0
  287. package/dist/ir/capture-values.test.js.map +1 -0
  288. package/dist/ir/field-values.d.ts +16 -0
  289. package/dist/ir/field-values.js +128 -0
  290. package/dist/ir/field-values.js.map +1 -0
  291. package/dist/ir/field-values.test.d.ts +1 -0
  292. package/dist/ir/field-values.test.js +160 -0
  293. package/dist/ir/field-values.test.js.map +1 -0
  294. package/dist/ir/final-fields.d.ts +4 -1
  295. package/dist/ir/final-fields.js +11 -3
  296. package/dist/ir/final-fields.js.map +1 -1
  297. package/dist/ir/function-references.test.js +1 -1
  298. package/dist/ir/function-references.test.js.map +1 -1
  299. package/dist/ir/init-only-globals.d.ts +16 -0
  300. package/dist/ir/init-only-globals.js +121 -0
  301. package/dist/ir/init-only-globals.js.map +1 -0
  302. package/dist/ir/init-only-globals.test.d.ts +1 -0
  303. package/dist/ir/init-only-globals.test.js +115 -0
  304. package/dist/ir/init-only-globals.test.js.map +1 -0
  305. package/dist/ir/initializer-bindings.d.ts +18 -1
  306. package/dist/ir/initializer-bindings.js +91 -1
  307. package/dist/ir/initializer-bindings.js.map +1 -1
  308. package/dist/ir/initializer-bindings.test.js +57 -2
  309. package/dist/ir/initializer-bindings.test.js.map +1 -1
  310. package/dist/ir/int32-slots.d.ts +22 -0
  311. package/dist/ir/int32-slots.js +376 -13
  312. package/dist/ir/int32-slots.js.map +1 -1
  313. package/dist/ir/int32-slots.test.js +91 -8
  314. package/dist/ir/int32-slots.test.js.map +1 -1
  315. package/dist/ir/integer-loop-facts.d.ts +19 -1
  316. package/dist/ir/integer-loop-facts.js +155 -7
  317. package/dist/ir/integer-loop-facts.js.map +1 -1
  318. package/dist/ir/integer-ranges.d.ts +8 -5
  319. package/dist/ir/integer-ranges.js +147 -55
  320. package/dist/ir/integer-ranges.js.map +1 -1
  321. package/dist/ir/integer-ranges.test.js +225 -7
  322. package/dist/ir/integer-ranges.test.js.map +1 -1
  323. package/dist/ir/ir.d.ts +29 -2
  324. package/dist/ir/ir.js +17 -0
  325. package/dist/ir/ir.js.map +1 -1
  326. package/dist/ir/property-bags.d.ts +14 -0
  327. package/dist/ir/property-bags.js +121 -0
  328. package/dist/ir/property-bags.js.map +1 -0
  329. package/dist/ir/receiver-readers.d.ts +21 -0
  330. package/dist/ir/receiver-readers.js +217 -0
  331. package/dist/ir/receiver-readers.js.map +1 -0
  332. package/dist/ir/runtime-features.d.ts +1 -0
  333. package/dist/ir/runtime-features.js +34 -2
  334. package/dist/ir/runtime-features.js.map +1 -1
  335. package/dist/ir/validate.js +221 -5
  336. package/dist/ir/validate.js.map +1 -1
  337. package/dist/ir/validate.test.js +21 -0
  338. package/dist/ir/validate.test.js.map +1 -1
  339. package/dist/library/int-infer.js +3 -0
  340. package/dist/library/int-infer.js.map +1 -1
  341. package/dist/library/ir-policy.js +1 -0
  342. package/dist/library/ir-policy.js.map +1 -1
  343. package/dist/native/cli.js +1 -0
  344. package/dist/native/cli.js.map +1 -1
  345. package/dist/native/compiler.js +1 -3
  346. package/dist/native/compiler.js.map +1 -1
  347. package/dist/native/prepare.js +1 -0
  348. package/dist/native/prepare.js.map +1 -1
  349. package/dist/native/sanitizer.test.js +1 -0
  350. package/dist/native/sanitizer.test.js.map +1 -1
  351. package/package.json +20 -20
  352. package/surface-manifest.json +896 -49
@@ -1,6 +1,6 @@
1
1
  import { typedRefConstructor } from "./shapes.js";
2
2
  import { bindLiveArrayOps } from "./expr-stream-bridges.js";
3
- import { BYTES_ELEM_NUM, SCR_ARR_FIELD, f64Lit } from "./common.js";
3
+ import { BYTES_ELEM_NUM, SCR_ARR_FIELD, f64Lit, sizeToDouble } from "./common.js";
4
4
  import { emitUnionPeek, emitUnionTag } from "./union-repr.js";
5
5
  import { INLINE_UNION_FIELD, loadInlineUnion, stackUnionBox, storeInlineUnion, unionBoxBits, } from "./inline-unions.js";
6
6
  import { InternalCompilerError } from "../../errors.js";
@@ -11,6 +11,17 @@ import { BlockBuilder } from "./blocks.js";
11
11
  import { llvmCommentText } from "./common.js";
12
12
  import { arrNewCall, elemAccess, llFieldType, releaseSym, traceAdapter, traceArg, vAdapters, } from "./shapes.js";
13
13
  import { LlvmUnsupportedError } from "./unsupported.js";
14
+ import { recordMayKeepSource, recordSourceFieldOrder } from "./record-sources.js";
15
+ /** Whether to-dyn of a record shape keeps the record itself: an empty shape
16
+ * and an event-listener record (a `handleEvent` function field) box their
17
+ * identity. Every other shape, tuples included, copies its fields into a
18
+ * fresh checked-dynamic value. */
19
+ export function recordDynKeepsIdentity(shape) {
20
+ if (shape.tuple)
21
+ return false;
22
+ return ((shape.fields.length === 0 && !shape.indexValue) ||
23
+ shape.fields.some((f) => f.name === "handleEvent" && f.type.kind === "func"));
24
+ }
14
25
  /** ScrDynKind values (scr_runtime.h). */
15
26
  /** ScrDynHandleTag numeric values (scr_runtime.h's enum order). */
16
27
  const DYN_HANDLE_TAG_NUM = {
@@ -56,11 +67,117 @@ export class LlDyn {
56
67
  dynToStrFn = null;
57
68
  caughtToDynFn = null;
58
69
  helperMemo = new Map();
70
+ recursiveShapes = new Map();
71
+ holdsRecursiveShapes = new Map();
59
72
  /** Emitted function definitions, in interning order. */
60
73
  defs = [];
61
74
  constructor(host) {
62
75
  this.host = host;
63
76
  }
77
+ /** The types a dyn matcher or builder for `t` checks structurally: record
78
+ * fields and index values, array elements and union arms. */
79
+ structuralChildren(t) {
80
+ switch (t.kind) {
81
+ case "record": {
82
+ const shape = this.host.recordsById.get(t.shapeId);
83
+ if (!shape)
84
+ return [];
85
+ const fields = shape.fields.map((f) => f.type);
86
+ return shape.indexValue ? [...fields, shape.indexValue] : fields;
87
+ }
88
+ case "array":
89
+ return [t.elem];
90
+ case "union":
91
+ return this.host.unionsById.get(t.unionId)?.arms ?? [];
92
+ default:
93
+ return [];
94
+ }
95
+ }
96
+ /** A record or array type that reaches itself through its fields,
97
+ * elements or union arms. Only these can describe a cyclic dyn value, so
98
+ * only their matchers and builders track visited values. */
99
+ isRecursiveShape(t) {
100
+ if (t.kind !== "record" && t.kind !== "array")
101
+ return false;
102
+ const key = typeKey(t);
103
+ const known = this.recursiveShapes.get(key);
104
+ if (known !== undefined)
105
+ return known;
106
+ const seen = new Set();
107
+ const pending = [...this.structuralChildren(t)];
108
+ let recursive = false;
109
+ while (pending.length > 0 && !recursive) {
110
+ const next = pending.pop();
111
+ const nextKey = typeKey(next);
112
+ if (nextKey === key)
113
+ recursive = true;
114
+ else if (!seen.has(nextKey)) {
115
+ seen.add(nextKey);
116
+ pending.push(...this.structuralChildren(next));
117
+ }
118
+ }
119
+ this.recursiveShapes.set(key, recursive);
120
+ return recursive;
121
+ }
122
+ /** A type with a recursive shape among the types it reaches. Its matcher
123
+ * and builder keep one visit session open for all of its members, so a
124
+ * dyn value reached through two of them converts once. */
125
+ holdsRecursiveShape(t) {
126
+ const key = typeKey(t);
127
+ const known = this.holdsRecursiveShapes.get(key);
128
+ if (known !== undefined)
129
+ return known;
130
+ const seen = new Set([key]);
131
+ const pending = [...this.structuralChildren(t)];
132
+ let holds = false;
133
+ while (pending.length > 0 && !holds) {
134
+ const next = pending.pop();
135
+ const nextKey = typeKey(next);
136
+ if (seen.has(nextKey))
137
+ continue;
138
+ seen.add(nextKey);
139
+ if (this.isRecursiveShape(next))
140
+ holds = true;
141
+ else
142
+ pending.push(...this.structuralChildren(next));
143
+ }
144
+ this.holdsRecursiveShapes.set(key, holds);
145
+ return holds;
146
+ }
147
+ /** `name` around the structural body `${name}_body`, inside one visit
148
+ * session of the runtime. A recursive shape's matcher ("match") answers
149
+ * true for a (value, matcher) pair it is already checking further up the
150
+ * stack. A recursive shape's builder ("build") answers the value it
151
+ * already built for the same dyn value in the session, so cycles and
152
+ * shared values keep their identity. Matchers ("visit") and builders
153
+ * ("memo") of types holding recursive shapes only keep the session open
154
+ * across their members. */
155
+ emitVisitWrapper(name, t, mode) {
156
+ const host = this.host;
157
+ const what = mode === "match" || mode === "build" ? "visits tracked" : "one visit session";
158
+ if (mode === "match" || mode === "visit") {
159
+ host.declare(`declare zeroext i1 @scr_dyn_match_visit(ptr, ptr, ptr)`);
160
+ this.defs.push(`define internal zeroext i1 @${name}(ptr %d) ${FN_ATTRS} { ; matches ${llvmCommentText(typeKey(t))}, ${what}`, `entry:`, ` %ok = call zeroext i1 @scr_dyn_match_visit(ptr %d, ptr ${mode === "match" ? `@${name}` : "null"}, ptr @${name}_body)`, ` ret i1 %ok`, `}`, ``);
161
+ return;
162
+ }
163
+ const retain = mode === "build" ? vAdapters(host, t).retain : "null";
164
+ host.declare(`declare ptr @scr_dyn_build_visit(ptr, ptr, ptr, ptr, ptr)`);
165
+ this.defs.push(`define internal ptr @${name}(ptr %d, ptr %path) ${FN_ATTRS} { ; check ${llvmCommentText(typeKey(t))}, ${what}`, `entry:`, ` %r = call ptr @scr_dyn_build_visit(ptr %d, ptr %path, ptr ${mode === "build" ? `@${name}` : "null"}, ptr @${name}_body, ptr ${retain})`, ` ret ptr %r`, `}`, ``);
166
+ }
167
+ /** The runtime call that gives a matcher or builder body a capsule's
168
+ * dyn view: inside a visit session (`wrapped`), a capsule keeps the view
169
+ * it was first given, so an outer visit can keep reading it. */
170
+ viewFn(wrapped) {
171
+ const fn = wrapped ? "scr_dyn_visit_view" : "scr_dyn_typed_ref_materialize";
172
+ this.host.declare(`declare ptr @${fn}(ptr)`);
173
+ return fn;
174
+ }
175
+ /** In a recursive shape's builder body: record `value`, just allocated
176
+ * for %d, before its members are built. */
177
+ recordBuilt(B, name, value) {
178
+ this.host.declare(`declare void @scr_dyn_build_add(ptr, ptr, ptr)`);
179
+ B.line(`call void @scr_dyn_build_add(ptr %d, ptr @${name}, ptr ${value})`);
180
+ }
64
181
  /** Branch to a variant only after its literal discriminator and complete
65
182
  * structure match. Use the same path for predicates and builders. */
66
183
  unionArmMatch(B, def, tag, yes, no, preserveRefs = false) {
@@ -315,12 +432,23 @@ export class LlDyn {
315
432
  return out;
316
433
  }
317
434
  /** Ordinary property lookup, including inherited data and accessors (+1). */
318
- objReadLit(B, d, key) {
319
- this.host.declare(`declare ptr @scr_dyn_obj_read(ptr, ptr, ${this.S})`);
435
+ objReadLit(B, d, key, held = false) {
436
+ const read = held ? "scr_dyn_obj_read_held" : "scr_dyn_obj_read";
437
+ this.host.declare(`declare ptr @${read}(ptr, ptr, ${this.S})`);
320
438
  const value = B.tmp();
321
- B.line(`${value} = call ptr @scr_dyn_obj_read(ptr ${d}, ptr ${this.host.cstr(key)}, ${this.S} ${Buffer.byteLength(key, "utf8")})`);
439
+ B.line(`${value} = call ptr @${read}(ptr ${d}, ptr ${this.host.cstr(key)}, ${this.S} ${Buffer.byteLength(key, "utf8")})`);
322
440
  return value;
323
441
  }
442
+ /** A member read for a matcher or builder of `t`: values that can reach a
443
+ * recursive shape go through the runtime's held read, so its visit
444
+ * tracking does not count the read's reference. Returns the value and
445
+ * the matching release. */
446
+ memberRead(B, key, t) {
447
+ const held = this.isRecursiveShape(t) || this.holdsRecursiveShape(t);
448
+ const release = held ? "scr_dyn_release_held" : "scr_dyn_release";
449
+ this.host.declare(`declare void @${release}(ptr)`);
450
+ return { value: this.objReadLit(B, "%d", key, held), release };
451
+ }
324
452
  /** Appends a borrowed string, preserving its full byte length. */
325
453
  putScrStr(B, buf, s) {
326
454
  this.host.declare(`declare void @scr_jb_put_str(ptr, ptr)`);
@@ -435,6 +563,8 @@ export class LlDyn {
435
563
  return existing;
436
564
  const name = `sc_dm_${this.dynMatchers.size}`;
437
565
  this.dynMatchers.set(matcherKey, name);
566
+ const recursive = this.isRecursiveShape(t);
567
+ const wrapped = recursive || this.holdsRecursiveShape(t);
438
568
  const B = new BlockBuilder();
439
569
  if (isRefCounted(t) && t.kind !== "dyn") {
440
570
  const matched = this.typedRefMatches(B, t);
@@ -446,7 +576,7 @@ export class LlDyn {
446
576
  B.startBlock(lNext);
447
577
  }
448
578
  if (t.kind !== "dyn") {
449
- this.host.declare(`declare ptr @scr_dyn_typed_ref_materialize(ptr)`);
579
+ const view = this.viewFn(wrapped);
450
580
  this.host.declare(`declare void @scr_dyn_release_v(ptr)`);
451
581
  const kind = this.kindOf(B, "%d");
452
582
  const capsule = B.tmp();
@@ -461,7 +591,7 @@ export class LlDyn {
461
591
  else {
462
592
  const materialized = B.tmp();
463
593
  const matched = B.tmp();
464
- B.line(`${materialized} = call ptr @scr_dyn_typed_ref_materialize(ptr %d)`);
594
+ B.line(`${materialized} = call ptr @${view}(ptr %d)`);
465
595
  B.line(`${matched} = call zeroext i1 @${name}(ptr ${materialized})`);
466
596
  B.line(`call void @scr_dyn_release_v(ptr ${materialized})`);
467
597
  B.terminate(`ret i1 ${matched}`);
@@ -640,13 +770,12 @@ export class LlDyn {
640
770
  for (const f of shape.fields) {
641
771
  if (f.type.kind === "dyn")
642
772
  continue;
643
- const m = this.objReadLit(B, "%d", f.name);
773
+ const { value: m, release } = this.memberRead(B, f.name, f.type);
644
774
  const lNext = B.newLabel("dm.n");
645
- this.host.declare(`declare void @scr_dyn_release(ptr)`);
646
- this.pendingBail(B, "dm.read", () => B.line(`call void @scr_dyn_release(ptr ${m})`), "i1 false");
775
+ this.pendingBail(B, "dm.read", () => B.line(`call void @${release}(ptr ${m})`), "i1 false");
647
776
  const ok = B.tmp();
648
777
  B.line(`${ok} = call zeroext i1 @${this.dynMatchHelper(f.type, preserveRefs)}(ptr ${m})`);
649
- B.line(`call void @scr_dyn_release(ptr ${m})`);
778
+ B.line(`call void @${release}(ptr ${m})`);
650
779
  B.condBr(ok, lNext, fail);
651
780
  B.startBlock(lNext);
652
781
  }
@@ -764,12 +893,15 @@ export class LlDyn {
764
893
  break;
765
894
  }
766
895
  }
767
- this.defs.push(`define internal zeroext i1 @${name}(ptr %d) ${FN_ATTRS} { ; matches ${key}`, B.render(), `}`, ``);
896
+ this.defs.push(`define internal zeroext i1 @${wrapped ? `${name}_body` : name}(ptr %d) ${FN_ATTRS} { ; matches ${key}`, B.render(), `}`, ``);
897
+ if (wrapped)
898
+ this.emitVisitWrapper(name, t, recursive ? "match" : "visit");
768
899
  return name;
769
900
  }
770
901
  /* ── schema-directed JSON.parse ───────────────────────────────── */
771
902
  jsonSchemas = new Map();
772
903
  jsonParsers = new Map();
904
+ recordNameTables = new Map();
773
905
  /** Targets the one-pass parser (scr_json_parse_schema) can build
774
906
  * directly: number, boolean and string leaves inside arrays and plain
775
907
  * records (no tuple, index signature, internal '%' slot or `__proto__`
@@ -834,10 +966,8 @@ export class LlDyn {
834
966
  throw new InternalCompilerError(`llvm emitter bug: JSON schema of unknown shape ${t.shapeId}`);
835
967
  const struct = mangleRecordStruct(t.shapeId);
836
968
  const index = new Map(shape.fields.map((f, i) => [f.name, i + 1]));
837
- const order = [...(shape.declaredOrder ?? []).filter((n) => index.has(n))];
838
- for (const f of shape.fields)
839
- if (!order.includes(f.name))
840
- order.push(f.name);
969
+ // The runtime names kept-source keys by this index (record-sources.ts).
970
+ const order = recordSourceFieldOrder(shape);
841
971
  const fieldTy = `{ ptr, ${S}, ${S}, ptr }`;
842
972
  const entries = order.map((fieldName) => {
843
973
  const field = shape.fields[index.get(fieldName) - 1];
@@ -856,6 +986,24 @@ export class LlDyn {
856
986
  this.defs.push(`@${name} = internal constant { ${S}, ${S}, ptr, ptr, ptr, ptr, ptr } { ${body} }`, ``);
857
987
  return name;
858
988
  }
989
+ /** The declared-name tables scr_record_source_note scans: parallel
990
+ * constant arrays of field-name bytes and byte lengths in declaration
991
+ * order (the order the record serializes), interned per shape. Internal
992
+ * '%'-fields follow, so they never count as undeclared source keys. */
993
+ recordNameTable(shapeId, shape) {
994
+ const existing = this.recordNameTables.get(shapeId);
995
+ if (existing)
996
+ return existing;
997
+ const host = this.host;
998
+ const S = host.sizeType;
999
+ const base = `sc_rnames_${this.recordNameTables.size}`;
1000
+ const table = { names: `@${base}`, lens: `@${base}_lens` };
1001
+ this.recordNameTables.set(shapeId, table);
1002
+ const n = shape.fields.length;
1003
+ const names = recordSourceFieldOrder(shape);
1004
+ this.defs.push(`@${base} = internal constant [${n} x ptr] [${names.map((name) => `ptr ${host.cstr(name)}`).join(", ")}]`, `@${base}_lens = internal constant [${n} x ${S}] [${names.map((name) => `${S} ${Buffer.byteLength(name, "utf8")}`).join(", ")}]`, ``);
1005
+ return table;
1006
+ }
859
1007
  /** `sc_jp_<n>(ptr text) -> T` for `JSON.parse(text) as T`, or null when T
860
1008
  * is not a schema target. Tries the one-pass schema parser; when it
861
1009
  * declines (any input the checked route might reject or read
@@ -894,6 +1042,8 @@ export class LlDyn {
894
1042
  return existing;
895
1043
  const name = `sc_dc_${this.dynBuilders.size}`;
896
1044
  this.dynBuilders.set(builderKey, name);
1045
+ const recursive = this.isRecursiveShape(t);
1046
+ const memo = !recursive && this.holdsRecursiveShape(t) && this.valTy(t) === "ptr";
897
1047
  const host = this.host;
898
1048
  const retTy = this.valTy(t);
899
1049
  const dummy = retTy === "double" ? `double ${f64Lit(0)}` : retTy === "i1" ? "i1 false" : "ptr null";
@@ -945,7 +1095,7 @@ export class LlDyn {
945
1095
  B.startBlock(plain);
946
1096
  }
947
1097
  else if (t.kind !== "union") {
948
- host.declare(`declare ptr @scr_dyn_typed_ref_materialize(ptr)`);
1098
+ const view = this.viewFn(recursive || memo);
949
1099
  host.declare(`declare ptr @scr_dyn_typed_ref_cached_cast(ptr, ptr, ${host.sizeType})`);
950
1100
  host.declare(`declare void @scr_dyn_typed_ref_cache_cast(ptr, ptr, ${host.sizeType}, ptr, ptr, ptr, i1)`);
951
1101
  host.declare(`declare void @scr_dyn_release_v(ptr)`);
@@ -961,6 +1111,13 @@ export class LlDyn {
961
1111
  B.line(`${cached} = call ptr @scr_dyn_typed_ref_cached_cast(ptr %d, ptr ${host.cstr(key)}, ${host.sizeType} ${Buffer.byteLength(key, "utf8")})`);
962
1112
  const hasCached = B.tmp();
963
1113
  B.line(`${hasCached} = icmp ne ptr ${cached}, null`);
1114
+ if (recursive) {
1115
+ // A cached record keeps its identity: the refresh below rewrites
1116
+ // it in place. Later visits of this capsule in the session answer
1117
+ // it, instead of refreshing it while this visit rebuilds it.
1118
+ host.declare(`declare void @scr_dyn_build_note(ptr, ptr, ptr)`);
1119
+ B.line(`call void @scr_dyn_build_note(ptr %d, ptr @${name}, ptr ${cached})`);
1120
+ }
964
1121
  if (t.kind !== "record" && t.kind !== "array") {
965
1122
  const lCached = B.newLabel("dc.tr.hit");
966
1123
  const lMaterialize = B.newLabel("dc.tr.mat");
@@ -971,7 +1128,7 @@ export class LlDyn {
971
1128
  }
972
1129
  const materialized = B.tmp();
973
1130
  const checked = B.tmp();
974
- B.line(`${materialized} = call ptr @scr_dyn_typed_ref_materialize(ptr %d)`);
1131
+ B.line(`${materialized} = call ptr @${view}(ptr %d)`);
975
1132
  B.line(`${checked} = call ${retTy} @${name}(ptr ${materialized}, ptr %path)`);
976
1133
  B.line(`call void @scr_dyn_release_v(ptr ${materialized})`);
977
1134
  const ok = B.tmp();
@@ -1048,6 +1205,12 @@ export class LlDyn {
1048
1205
  host.declare("declare void @scr_arr_swap_indexed_ext(ptr, ptr)");
1049
1206
  B.line(`call void @scr_arr_swap_indexed_ext(ptr ${cached}, ptr ${checked})`);
1050
1207
  }
1208
+ if (recursive) {
1209
+ // The memo recorded the record built for the view: later visits
1210
+ // in the session answer the cached record that now holds it.
1211
+ host.declare(`declare void @scr_dyn_build_rekey(ptr, ptr, ptr)`);
1212
+ B.line(`call void @scr_dyn_build_rekey(ptr ${materialized}, ptr @${name}, ptr ${cached})`);
1213
+ }
1051
1214
  B.line(`call void ${releaseSym(host, t)}(ptr ${checked})`);
1052
1215
  B.terminate(`ret ptr ${cached}`);
1053
1216
  B.startBlock(lCache);
@@ -1319,6 +1482,8 @@ export class LlDyn {
1319
1482
  B.terminate(`ret ptr null`);
1320
1483
  B.startBlock(lGo);
1321
1484
  B.line(`%r0 = call ptr @${mangleRecordNew(t.shapeId)}()`);
1485
+ if (recursive)
1486
+ this.recordBuilt(B, name, "%r0");
1322
1487
  const items = this.itemsOf(B, "%d");
1323
1488
  byIndex.forEach((f, i) => {
1324
1489
  setPath(null, `${i}`);
@@ -1362,17 +1527,18 @@ export class LlDyn {
1362
1527
  B.startBlock(lCopy);
1363
1528
  }
1364
1529
  B.line(`%r0 = call ptr @${mangleRecordNew(t.shapeId)}()`);
1530
+ if (recursive)
1531
+ this.recordBuilt(B, name, "%r0");
1365
1532
  for (const f of shape.fields) {
1366
- const m = this.objReadLit(B, "%d", f.name);
1367
- host.declare(`declare void @scr_dyn_release(ptr)`);
1533
+ const { value: m, release } = this.memberRead(B, f.name, f.type);
1368
1534
  this.pendingBail(B, "dcr.read", () => {
1369
- B.line(`call void @scr_dyn_release(ptr ${m})`);
1535
+ B.line(`call void @${release}(ptr ${m})`);
1370
1536
  releaseR();
1371
1537
  }, "ptr null");
1372
1538
  setPath(f.name, "0");
1373
1539
  const value = B.tmp();
1374
1540
  B.line(`${value} = call ${this.valTy(f.type)} @${this.dynCheckHelper(f.type, preserveRefs)}(ptr ${m}, ptr ${pathSlot})`);
1375
- B.line(`call void @scr_dyn_release(ptr ${m})`);
1541
+ B.line(`call void @${release}(ptr ${m})`);
1376
1542
  storeInto(f.name, f.type, value);
1377
1543
  this.pendingBail(B, "dcr", () => {
1378
1544
  releaseInline(f.type, value);
@@ -1385,6 +1551,14 @@ export class LlDyn {
1385
1551
  }
1386
1552
  releaseInline(f.type, value);
1387
1553
  }
1554
+ // A closed layout cannot store undeclared keys: a source object
1555
+ // that has them stays beside the record so its reflective
1556
+ // surfaces still observe them (scr_record_source_note).
1557
+ if (recordMayKeepSource(shape)) {
1558
+ const names = this.recordNameTable(t.shapeId, shape);
1559
+ host.declare(`declare void @scr_record_source_note(ptr, ptr, ptr, ptr, ${host.sizeType})`);
1560
+ B.line(`call void @scr_record_source_note(ptr %r0, ptr %d, ptr ${names.names}, ptr ${names.lens}, ${host.sizeType} ${shape.fields.length})`);
1561
+ }
1388
1562
  // Index-signature shapes CAPTURE undeclared keys into the
1389
1563
  // overflow map.
1390
1564
  if (shape.indexValue) {
@@ -1458,6 +1632,8 @@ export class LlDyn {
1458
1632
  const n = this.lenOf(B, "%d");
1459
1633
  const a = B.tmp();
1460
1634
  B.line(`${a} = ${arrNewCall(host, elem, n)}`);
1635
+ if (recursive)
1636
+ this.recordBuilt(B, name, a);
1461
1637
  const items = this.itemsOf(B, "%d");
1462
1638
  const pathSlot = "%dcp";
1463
1639
  B.entryAllocas.push(`${pathSlot} = alloca %ScrDynPath`);
@@ -1476,7 +1652,7 @@ export class LlDyn {
1476
1652
  host.declare(`declare void @scr_arr_set_len(ptr, double)`);
1477
1653
  const index = B.tmp();
1478
1654
  const length = B.tmp();
1479
- B.line(`${index} = sitofp ${this.S} ${i} to double`);
1655
+ B.line(`${index} = ${sizeToDouble(this.S)} ${this.S} ${i} to double`);
1480
1656
  B.line(`${length} = fadd double ${index}, 1.0`);
1481
1657
  B.line(`call void @scr_arr_set_len(ptr ${a}, double ${length})`);
1482
1658
  B.br(doneLabel);
@@ -1563,7 +1739,7 @@ export class LlDyn {
1563
1739
  // retry the union against the ordinary copy-based structural
1564
1740
  // snapshot (the compiler's width-coercion stance, rather than a
1565
1741
  // live narrowed alias).
1566
- host.declare(`declare ptr @scr_dyn_typed_ref_materialize(ptr)`);
1742
+ const view = this.viewFn(recursive || memo);
1567
1743
  host.declare(`declare ptr @scr_dyn_typed_ref_cached_cast(ptr, ptr, ${host.sizeType})`);
1568
1744
  host.declare(`declare void @scr_dyn_typed_ref_cache_cast(ptr, ptr, ${host.sizeType}, ptr, ptr, ptr, i1)`);
1569
1745
  host.declare(`declare void @scr_dyn_release_v(ptr)`);
@@ -1582,7 +1758,7 @@ export class LlDyn {
1582
1758
  // pending exception rather than a NULL result.
1583
1759
  const materialized = B.tmp();
1584
1760
  const checked = B.tmp();
1585
- B.line(`${materialized} = call ptr @scr_dyn_typed_ref_materialize(ptr %d)`);
1761
+ B.line(`${materialized} = call ptr @${view}(ptr %d)`);
1586
1762
  B.line(`${checked} = call ptr @${name}(ptr ${materialized}, ptr %path)`);
1587
1763
  B.line(`call void @scr_dyn_release_v(ptr ${materialized})`);
1588
1764
  B.terminate(`ret ptr ${checked}`);
@@ -1597,7 +1773,7 @@ export class LlDyn {
1597
1773
  B.line(`${hasCached} = icmp ne ptr ${cached}, null`);
1598
1774
  const materialized = B.tmp();
1599
1775
  const checked = B.tmp();
1600
- B.line(`${materialized} = call ptr @scr_dyn_typed_ref_materialize(ptr %d)`);
1776
+ B.line(`${materialized} = call ptr @${view}(ptr %d)`);
1601
1777
  B.line(`${checked} = call ptr @${name}(ptr ${materialized}, ptr %path)`);
1602
1778
  B.line(`call void @scr_dyn_release_v(ptr ${materialized})`);
1603
1779
  const ok = B.tmp();
@@ -1740,7 +1916,9 @@ export class LlDyn {
1740
1916
  throw new LlvmUnsupportedError(`type:${t.kind}`);
1741
1917
  }
1742
1918
  }
1743
- this.defs.push(`define internal ${retTy === "i1" ? "zeroext i1" : retTy} @${name}(ptr %d, ptr %path) ${FN_ATTRS} { ; check ${key}`, B.render(), `}`, ``);
1919
+ this.defs.push(`define internal ${retTy === "i1" ? "zeroext i1" : retTy} @${recursive || memo ? `${name}_body` : name}(ptr %d, ptr %path) ${FN_ATTRS} { ; check ${key}`, B.render(), `}`, ``);
1920
+ if (recursive || memo)
1921
+ this.emitVisitWrapper(name, t, recursive ? "build" : "memo");
1744
1922
  return name;
1745
1923
  }
1746
1924
  /* ── toDynHelper (walkers.ts, ported) ─────────────────────────── */
@@ -1943,8 +2121,7 @@ export class LlDyn {
1943
2121
  break;
1944
2122
  }
1945
2123
  const d = B.tmp();
1946
- const carriesListenerIdentity = shape.fields.some((f) => f.name === "handleEvent" && f.type.kind === "func");
1947
- if ((shape.fields.length === 0 && !shape.indexValue) || carriesListenerIdentity) {
2124
+ if (recordDynKeepsIdentity(shape)) {
1948
2125
  const rc = vAdapters(host, t);
1949
2126
  sourceAccessor = {
1950
2127
  name: `${name}_source_access`,
@@ -2052,9 +2229,17 @@ export class LlDyn {
2052
2229
  }
2053
2230
  if (cyclicRec)
2054
2231
  B.line(`call void @scr_dyn_from_leave()`);
2232
+ let snapshot = d;
2233
+ if (!shape.indexValue && !recordDynKeepsIdentity(shape)) {
2234
+ // Undeclared properties the record kept from its checked source
2235
+ // rejoin the copy in their own-key positions.
2236
+ host.declare(`declare ptr @scr_record_source_apply(ptr, ptr)`);
2237
+ snapshot = B.tmp();
2238
+ B.line(`${snapshot} = call ptr @scr_record_source_apply(ptr ${d}, ptr %v)`);
2239
+ }
2055
2240
  host.declare(`declare ptr @scr_dyn_mark_snapshot(ptr)`);
2056
- B.line(`call ptr @scr_dyn_mark_snapshot(ptr ${d})`);
2057
- B.terminate(`ret ptr ${d}`);
2241
+ B.line(`call ptr @scr_dyn_mark_snapshot(ptr ${snapshot})`);
2242
+ B.terminate(`ret ptr ${snapshot}`);
2058
2243
  break;
2059
2244
  }
2060
2245
  case "array": {
@@ -3103,7 +3288,7 @@ export class LlDyn {
3103
3288
  const n = this.lenOf(B, "%d");
3104
3289
  const nd = B.tmp();
3105
3290
  const r = B.tmp();
3106
- B.line(`${nd} = sitofp ${host.sizeType} ${n} to double`);
3291
+ B.line(`${nd} = ${sizeToDouble(host.sizeType)} ${host.sizeType} ${n} to double`);
3107
3292
  B.line(`${r} = call ptr @scr_dyn_new_num(double ${nd})`);
3108
3293
  B.terminate(`ret ptr ${r}`);
3109
3294
  B.startBlock(lStr);
@@ -3142,7 +3327,7 @@ export class LlDyn {
3142
3327
  const n2 = B.tmp();
3143
3328
  B.line(`${n2} = call double @scr_str_utf16_len(ptr ${s})`);
3144
3329
  const idxD = B.tmp();
3145
- B.line(`${idxD} = sitofp ${host.sizeType} ${idx} to double`);
3330
+ B.line(`${idxD} = ${sizeToDouble(host.sizeType)} ${host.sizeType} ${idx} to double`);
3146
3331
  const inR2 = B.tmp();
3147
3332
  B.line(`${inR2} = fcmp olt double ${idxD}, ${n2}`);
3148
3333
  const lHit2 = B.newLabel("kg.ash");
@@ -3395,7 +3580,7 @@ export class LlDyn {
3395
3580
  const index = B.tmp();
3396
3581
  const bd = B.tmp();
3397
3582
  const r = B.tmp();
3398
- B.line(`${index} = sitofp ${host.sizeType} ${i} to double`);
3583
+ B.line(`${index} = ${sizeToDouble(host.sizeType)} ${host.sizeType} ${i} to double`);
3399
3584
  B.line(`${bd} = call double @scr_bytes_get(ptr ${bts}, double ${index})`);
3400
3585
  B.line(`${r} = call ptr @scr_dyn_new_num(double ${bd})`);
3401
3586
  B.line(`store ptr ${r}, ptr ${itemSlot}`);