@scriptc/compiler 0.3.4 → 0.3.6

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 (316) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +409 -42
  2. package/dist/backend/llvm/array-search.js +1 -1
  3. package/dist/backend/llvm/array-search.js.map +1 -1
  4. package/dist/backend/llvm/call-lifetimes.d.ts +6 -0
  5. package/dist/backend/llvm/call-lifetimes.js +19 -0
  6. package/dist/backend/llvm/call-lifetimes.js.map +1 -1
  7. package/dist/backend/llvm/constant-callbacks.d.ts +2 -21
  8. package/dist/backend/llvm/constant-callbacks.js +36 -219
  9. package/dist/backend/llvm/constant-callbacks.js.map +1 -1
  10. package/dist/backend/llvm/constant-callbacks.test.js +22 -0
  11. package/dist/backend/llvm/constant-callbacks.test.js.map +1 -1
  12. package/dist/backend/llvm/dense-array-access.d.ts +9 -0
  13. package/dist/backend/llvm/dense-array-access.js +27 -1
  14. package/dist/backend/llvm/dense-array-access.js.map +1 -1
  15. package/dist/backend/llvm/dyn.d.ts +6 -0
  16. package/dist/backend/llvm/dyn.js +71 -7
  17. package/dist/backend/llvm/dyn.js.map +1 -1
  18. package/dist/backend/llvm/emitter.d.ts +120 -2
  19. package/dist/backend/llvm/emitter.js +820 -142
  20. package/dist/backend/llvm/emitter.js.map +1 -1
  21. package/dist/backend/llvm/expr-async.js +17 -7
  22. package/dist/backend/llvm/expr-async.js.map +1 -1
  23. package/dist/backend/llvm/expr-bytes.js +1 -1
  24. package/dist/backend/llvm/expr-callbacks.d.ts +11 -0
  25. package/dist/backend/llvm/expr-callbacks.js +53 -0
  26. package/dist/backend/llvm/expr-callbacks.js.map +1 -1
  27. package/dist/backend/llvm/expr-calls.js +88 -2
  28. package/dist/backend/llvm/expr-calls.js.map +1 -1
  29. package/dist/backend/llvm/expr-containers.js +50 -27
  30. package/dist/backend/llvm/expr-containers.js.map +1 -1
  31. package/dist/backend/llvm/expr-dispatch.js +1 -0
  32. package/dist/backend/llvm/expr-dispatch.js.map +1 -1
  33. package/dist/backend/llvm/expr-dynamic.js +25 -1
  34. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  35. package/dist/backend/llvm/expr-primitives.d.ts +1 -1
  36. package/dist/backend/llvm/expr-primitives.js +20 -1
  37. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  38. package/dist/backend/llvm/expr-stream-bridges.js +4 -0
  39. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  40. package/dist/backend/llvm/integer-clones.d.ts +103 -0
  41. package/dist/backend/llvm/integer-clones.js +1336 -0
  42. package/dist/backend/llvm/integer-clones.js.map +1 -0
  43. package/dist/backend/llvm/integer-clones.test.d.ts +1 -0
  44. package/dist/backend/llvm/integer-clones.test.js +219 -0
  45. package/dist/backend/llvm/integer-clones.test.js.map +1 -0
  46. package/dist/backend/llvm/lib-datagram.js +14 -0
  47. package/dist/backend/llvm/lib-datagram.js.map +1 -1
  48. package/dist/backend/llvm/lib-dispatch.js +32 -1
  49. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  50. package/dist/backend/llvm/lib-filesystem.js +61 -1
  51. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  52. package/dist/backend/llvm/lib-network.js +21 -3
  53. package/dist/backend/llvm/lib-network.js.map +1 -1
  54. package/dist/backend/llvm/lib-process.js +34 -0
  55. package/dist/backend/llvm/lib-process.js.map +1 -1
  56. package/dist/backend/llvm/lib-shared.js +77 -2
  57. package/dist/backend/llvm/lib-shared.js.map +1 -1
  58. package/dist/backend/llvm/lib-test.js +16 -3
  59. package/dist/backend/llvm/lib-test.js.map +1 -1
  60. package/dist/backend/llvm/lib-tls.js +6 -0
  61. package/dist/backend/llvm/lib-tls.js.map +1 -1
  62. package/dist/backend/llvm/local-array-reads.js +1 -1
  63. package/dist/backend/llvm/local-array-reads.js.map +1 -1
  64. package/dist/backend/llvm/map-entry-fusion.d.ts +28 -0
  65. package/dist/backend/llvm/map-entry-fusion.js +233 -0
  66. package/dist/backend/llvm/map-entry-fusion.js.map +1 -0
  67. package/dist/backend/llvm/map-entry-fusion.test.d.ts +1 -0
  68. package/dist/backend/llvm/map-entry-fusion.test.js +183 -0
  69. package/dist/backend/llvm/map-entry-fusion.test.js.map +1 -0
  70. package/dist/backend/llvm/map-number-lookup.d.ts +2 -0
  71. package/dist/backend/llvm/map-number-lookup.js +1 -1
  72. package/dist/backend/llvm/map-number-lookup.js.map +1 -1
  73. package/dist/backend/llvm/map-number-lookup.test.js +10 -11
  74. package/dist/backend/llvm/map-number-lookup.test.js.map +1 -1
  75. package/dist/backend/llvm/map-read-lifetimes.d.ts +2 -0
  76. package/dist/backend/llvm/map-read-lifetimes.js +3 -0
  77. package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
  78. package/dist/backend/llvm/map-read-lifetimes.test.js +2 -2
  79. package/dist/backend/llvm/nullable-unions.d.ts +6 -3
  80. package/dist/backend/llvm/nullable-unions.js +2 -0
  81. package/dist/backend/llvm/nullable-unions.js.map +1 -1
  82. package/dist/backend/llvm/publish.d.ts +16 -0
  83. package/dist/backend/llvm/publish.js +81 -10
  84. package/dist/backend/llvm/publish.js.map +1 -1
  85. package/dist/backend/llvm/publish.test.d.ts +1 -0
  86. package/dist/backend/llvm/publish.test.js +94 -0
  87. package/dist/backend/llvm/publish.test.js.map +1 -0
  88. package/dist/backend/llvm/record-results.d.ts +1 -1
  89. package/dist/backend/llvm/record-results.js +78 -4
  90. package/dist/backend/llvm/record-results.js.map +1 -1
  91. package/dist/backend/llvm/record-sources.d.ts +7 -0
  92. package/dist/backend/llvm/record-sources.js +14 -0
  93. package/dist/backend/llvm/record-sources.js.map +1 -0
  94. package/dist/backend/llvm/reference-writes.js +1 -0
  95. package/dist/backend/llvm/reference-writes.js.map +1 -1
  96. package/dist/backend/llvm/shapes.d.ts +12 -3
  97. package/dist/backend/llvm/shapes.js +23 -14
  98. package/dist/backend/llvm/shapes.js.map +1 -1
  99. package/dist/backend/llvm/shapes.test.js +5 -3
  100. package/dist/backend/llvm/shapes.test.js.map +1 -1
  101. package/dist/backend/llvm/speculative-integers.d.ts +74 -0
  102. package/dist/backend/llvm/speculative-integers.js +571 -0
  103. package/dist/backend/llvm/speculative-integers.js.map +1 -0
  104. package/dist/backend/llvm/speculative-integers.test.d.ts +1 -0
  105. package/dist/backend/llvm/speculative-integers.test.js +148 -0
  106. package/dist/backend/llvm/speculative-integers.test.js.map +1 -0
  107. package/dist/backend/llvm/string-lifetimes.test.js +75 -1
  108. package/dist/backend/llvm/string-lifetimes.test.js.map +1 -1
  109. package/dist/backend/llvm/walkers.d.ts +17 -0
  110. package/dist/backend/llvm/walkers.js +123 -0
  111. package/dist/backend/llvm/walkers.js.map +1 -1
  112. package/dist/backend/may-throw.js +2 -0
  113. package/dist/backend/may-throw.js.map +1 -1
  114. package/dist/backend/native/contracts.d.ts +2 -1
  115. package/dist/backend/native/executable.js +6 -1
  116. package/dist/backend/native/executable.js.map +1 -1
  117. package/dist/backend/native/runtime-inputs.d.ts +1 -1
  118. package/dist/backend/native/runtime-inputs.js +1 -0
  119. package/dist/backend/native/runtime-inputs.js.map +1 -1
  120. package/dist/backend/runtime-abi.d.ts +2 -2
  121. package/dist/backend/runtime-abi.js +2 -2
  122. package/dist/backend/runtime-pack-targets.test.js +1 -1
  123. package/dist/backend/runtime-pack.d.ts +7 -3
  124. package/dist/backend/runtime-pack.js +12 -6
  125. package/dist/backend/runtime-pack.js.map +1 -1
  126. package/dist/backend/runtime-pack.test.js +16 -7
  127. package/dist/backend/runtime-pack.test.js.map +1 -1
  128. package/dist/contracts/check.js +1 -0
  129. package/dist/contracts/check.js.map +1 -1
  130. package/dist/coverage/surface-manifest.js +3 -3
  131. package/dist/coverage/surface-manifest.js.map +1 -1
  132. package/dist/diagnostics/diagnostic.d.ts +1 -1
  133. package/dist/diagnostics/diagnostic.js +6 -2
  134. package/dist/diagnostics/diagnostic.js.map +1 -1
  135. package/dist/frontend/lowering/builtin-calls.js +13 -0
  136. package/dist/frontend/lowering/builtin-calls.js.map +1 -1
  137. package/dist/frontend/lowering/builtins/callable-aliases.js +82 -8
  138. package/dist/frontend/lowering/builtins/callable-aliases.js.map +1 -1
  139. package/dist/frontend/lowering/builtins/child-process-async.d.ts +8 -6
  140. package/dist/frontend/lowering/builtins/child-process-async.js +45 -29
  141. package/dist/frontend/lowering/builtins/child-process-async.js.map +1 -1
  142. package/dist/frontend/lowering/builtins/compression.d.ts +9 -0
  143. package/dist/frontend/lowering/builtins/compression.js +145 -30
  144. package/dist/frontend/lowering/builtins/compression.js.map +1 -1
  145. package/dist/frontend/lowering/builtins/crypto.js +12 -1
  146. package/dist/frontend/lowering/builtins/crypto.js.map +1 -1
  147. package/dist/frontend/lowering/builtins/errors.js +5 -3
  148. package/dist/frontend/lowering/builtins/errors.js.map +1 -1
  149. package/dist/frontend/lowering/builtins/filesystem-calls.d.ts +6 -0
  150. package/dist/frontend/lowering/builtins/filesystem-calls.js +16 -0
  151. package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -1
  152. package/dist/frontend/lowering/builtins/filesystem.d.ts +8 -0
  153. package/dist/frontend/lowering/builtins/filesystem.js +199 -2
  154. package/dist/frontend/lowering/builtins/filesystem.js.map +1 -1
  155. package/dist/frontend/lowering/builtins/fs-streams.d.ts +26 -0
  156. package/dist/frontend/lowering/builtins/fs-streams.js +131 -0
  157. package/dist/frontend/lowering/builtins/fs-streams.js.map +1 -0
  158. package/dist/frontend/lowering/builtins/hash-stream.d.ts +12 -0
  159. package/dist/frontend/lowering/builtins/hash-stream.js +80 -0
  160. package/dist/frontend/lowering/builtins/hash-stream.js.map +1 -0
  161. package/dist/frontend/lowering/builtins/module-calls.js +17 -3
  162. package/dist/frontend/lowering/builtins/module-calls.js.map +1 -1
  163. package/dist/frontend/lowering/builtins/process.js +9 -2
  164. package/dist/frontend/lowering/builtins/process.js.map +1 -1
  165. package/dist/frontend/lowering/builtins/readline.d.ts +45 -13
  166. package/dist/frontend/lowering/builtins/readline.js +812 -47
  167. package/dist/frontend/lowering/builtins/readline.js.map +1 -1
  168. package/dist/frontend/lowering/builtins/workers.d.ts +4 -0
  169. package/dist/frontend/lowering/builtins/workers.js +58 -0
  170. package/dist/frontend/lowering/builtins/workers.js.map +1 -1
  171. package/dist/frontend/lowering/class-dynamic-dispatch.js +150 -8
  172. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  173. package/dist/frontend/lowering/class-protocols.d.ts +55 -0
  174. package/dist/frontend/lowering/class-protocols.js +735 -0
  175. package/dist/frontend/lowering/class-protocols.js.map +1 -1
  176. package/dist/frontend/lowering/containers/array-from-async.d.ts +18 -0
  177. package/dist/frontend/lowering/containers/array-from-async.js +282 -0
  178. package/dist/frontend/lowering/containers/array-from-async.js.map +1 -0
  179. package/dist/frontend/lowering/containers/bytes.js +33 -12
  180. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  181. package/dist/frontend/lowering/containers/collection-grouping.js +2 -1
  182. package/dist/frontend/lowering/containers/collection-grouping.js.map +1 -1
  183. package/dist/frontend/lowering/containers/collection-methods.js +27 -23
  184. package/dist/frontend/lowering/containers/collection-methods.js.map +1 -1
  185. package/dist/frontend/lowering/devirtualize.js +20 -7
  186. package/dist/frontend/lowering/devirtualize.js.map +1 -1
  187. package/dist/frontend/lowering/divergences.js +188 -15
  188. package/dist/frontend/lowering/divergences.js.map +1 -1
  189. package/dist/frontend/lowering/lower-calls.js +129 -25
  190. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  191. package/dist/frontend/lowering/lower-classes.js +46 -1
  192. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  193. package/dist/frontend/lowering/lower-dgram.js +55 -15
  194. package/dist/frontend/lowering/lower-dgram.js.map +1 -1
  195. package/dist/frontend/lowering/lower-event-emitter.d.ts +9 -1
  196. package/dist/frontend/lowering/lower-event-emitter.js +88 -1
  197. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
  198. package/dist/frontend/lowering/lower-exprs.d.ts +4 -0
  199. package/dist/frontend/lowering/lower-exprs.js +239 -71
  200. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  201. package/dist/frontend/lowering/lower-inspect.js +49 -3
  202. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  203. package/dist/frontend/lowering/lower-mock.d.ts +11 -1
  204. package/dist/frontend/lowering/lower-mock.js +377 -61
  205. package/dist/frontend/lowering/lower-mock.js.map +1 -1
  206. package/dist/frontend/lowering/lower-modules.js +1 -0
  207. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  208. package/dist/frontend/lowering/lower-server.d.ts +2 -1
  209. package/dist/frontend/lowering/lower-server.js +234 -21
  210. package/dist/frontend/lowering/lower-server.js.map +1 -1
  211. package/dist/frontend/lowering/lower-stmts.js +60 -13
  212. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  213. package/dist/frontend/lowering/lower-stream.d.ts +1 -3
  214. package/dist/frontend/lowering/lower-stream.js +325 -20
  215. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  216. package/dist/frontend/lowering/lower-test.js +147 -48
  217. package/dist/frontend/lowering/lower-test.js.map +1 -1
  218. package/dist/frontend/lowering/lowerer.d.ts +13 -1
  219. package/dist/frontend/lowering/lowerer.js +10 -2
  220. package/dist/frontend/lowering/lowerer.js.map +1 -1
  221. package/dist/frontend/lowering/null-prototype.d.ts +13 -0
  222. package/dist/frontend/lowering/null-prototype.js +33 -0
  223. package/dist/frontend/lowering/null-prototype.js.map +1 -0
  224. package/dist/frontend/lowering/record-sources.d.ts +15 -0
  225. package/dist/frontend/lowering/record-sources.js +46 -0
  226. package/dist/frontend/lowering/record-sources.js.map +1 -0
  227. package/dist/frontend/lowering/surfaces.d.ts +3 -3
  228. package/dist/frontend/lowering/surfaces.js +59 -5
  229. package/dist/frontend/lowering/surfaces.js.map +1 -1
  230. package/dist/frontend/mock-shapes.d.ts +5 -0
  231. package/dist/frontend/mock-shapes.js +27 -2
  232. package/dist/frontend/mock-shapes.js.map +1 -1
  233. package/dist/frontend/program.js +5 -4
  234. package/dist/frontend/program.js.map +1 -1
  235. package/dist/frontend/type-mapper.d.ts +3 -0
  236. package/dist/frontend/type-mapper.js +148 -4
  237. package/dist/frontend/type-mapper.js.map +1 -1
  238. package/dist/index.js +18 -8
  239. package/dist/index.js.map +1 -1
  240. package/dist/ir/analysis.d.ts +10 -0
  241. package/dist/ir/analysis.js +35 -0
  242. package/dist/ir/analysis.js.map +1 -1
  243. package/dist/ir/analysis.test.js +69 -1
  244. package/dist/ir/analysis.test.js.map +1 -1
  245. package/dist/ir/builtin-effects.js +72 -0
  246. package/dist/ir/builtin-effects.js.map +1 -1
  247. package/dist/ir/builtin-signatures.d.ts +1 -1
  248. package/dist/ir/builtin-signatures.js +258 -13
  249. package/dist/ir/builtin-signatures.js.map +1 -1
  250. package/dist/ir/capture-values.d.ts +107 -0
  251. package/dist/ir/capture-values.js +850 -0
  252. package/dist/ir/capture-values.js.map +1 -0
  253. package/dist/ir/capture-values.test.d.ts +1 -0
  254. package/dist/ir/capture-values.test.js +268 -0
  255. package/dist/ir/capture-values.test.js.map +1 -0
  256. package/dist/ir/field-values.d.ts +16 -0
  257. package/dist/ir/field-values.js +128 -0
  258. package/dist/ir/field-values.js.map +1 -0
  259. package/dist/ir/field-values.test.d.ts +1 -0
  260. package/dist/ir/field-values.test.js +160 -0
  261. package/dist/ir/field-values.test.js.map +1 -0
  262. package/dist/ir/final-fields.d.ts +4 -1
  263. package/dist/ir/final-fields.js +11 -3
  264. package/dist/ir/final-fields.js.map +1 -1
  265. package/dist/ir/function-references.test.js +2 -1
  266. package/dist/ir/function-references.test.js.map +1 -1
  267. package/dist/ir/init-only-globals.d.ts +16 -0
  268. package/dist/ir/init-only-globals.js +121 -0
  269. package/dist/ir/init-only-globals.js.map +1 -0
  270. package/dist/ir/init-only-globals.test.d.ts +1 -0
  271. package/dist/ir/init-only-globals.test.js +115 -0
  272. package/dist/ir/init-only-globals.test.js.map +1 -0
  273. package/dist/ir/initializer-bindings.d.ts +18 -1
  274. package/dist/ir/initializer-bindings.js +91 -1
  275. package/dist/ir/initializer-bindings.js.map +1 -1
  276. package/dist/ir/initializer-bindings.test.js +57 -2
  277. package/dist/ir/initializer-bindings.test.js.map +1 -1
  278. package/dist/ir/int32-slots.d.ts +22 -0
  279. package/dist/ir/int32-slots.js +398 -13
  280. package/dist/ir/int32-slots.js.map +1 -1
  281. package/dist/ir/int32-slots.test.js +119 -8
  282. package/dist/ir/int32-slots.test.js.map +1 -1
  283. package/dist/ir/integer-loop-facts.d.ts +27 -1
  284. package/dist/ir/integer-loop-facts.js +239 -7
  285. package/dist/ir/integer-loop-facts.js.map +1 -1
  286. package/dist/ir/integer-ranges.d.ts +8 -5
  287. package/dist/ir/integer-ranges.js +147 -59
  288. package/dist/ir/integer-ranges.js.map +1 -1
  289. package/dist/ir/integer-ranges.test.js +285 -7
  290. package/dist/ir/integer-ranges.test.js.map +1 -1
  291. package/dist/ir/ir.d.ts +22 -1
  292. package/dist/ir/ir.js +4 -0
  293. package/dist/ir/ir.js.map +1 -1
  294. package/dist/ir/property-bags.d.ts +14 -0
  295. package/dist/ir/property-bags.js +121 -0
  296. package/dist/ir/property-bags.js.map +1 -0
  297. package/dist/ir/receiver-readers.d.ts +21 -0
  298. package/dist/ir/receiver-readers.js +217 -0
  299. package/dist/ir/receiver-readers.js.map +1 -0
  300. package/dist/ir/runtime-features.d.ts +3 -1
  301. package/dist/ir/runtime-features.js +102 -7
  302. package/dist/ir/runtime-features.js.map +1 -1
  303. package/dist/ir/runtime-features.test.js +62 -0
  304. package/dist/ir/runtime-features.test.js.map +1 -1
  305. package/dist/ir/traverse.js +4 -0
  306. package/dist/ir/traverse.js.map +1 -1
  307. package/dist/ir/validate.js +71 -3
  308. package/dist/ir/validate.js.map +1 -1
  309. package/dist/ir/validate.test.js +59 -0
  310. package/dist/ir/validate.test.js.map +1 -1
  311. package/dist/library/int-infer.js +3 -0
  312. package/dist/library/int-infer.js.map +1 -1
  313. package/dist/library/ir-policy.js +5 -0
  314. package/dist/library/ir-policy.js.map +1 -1
  315. package/package.json +20 -20
  316. package/surface-manifest.json +57 -19
@@ -1,4 +1,4 @@
1
- import { analyzeIntegerRanges, INT32_RANGE, withinInt32, } from "./integer-ranges.js";
1
+ import { analyzeIntegerRanges, INT32_RANGE, NON_NEGATIVE_INT32_RANGE, withinInt32, } from "./integer-ranges.js";
2
2
  import { exprFunctionReference, moduleFunctionReferences } from "./function-references.js";
3
3
  import { findInitializerBindings, withInitializerBindings } from "./initializer-bindings.js";
4
4
  import { everyExprChild, everyStmtChild, everyStmtList, everyTypeChild } from "./traverse.js";
@@ -40,6 +40,8 @@ export class Int32Slots {
40
40
  familyOf = new Map();
41
41
  paramFacts = new Map();
42
42
  returns = new Set();
43
+ /** Results narrowed below their level (narrowSlotRanges). */
44
+ returnRanges = new Map();
43
45
  /** Captured-binding groups (one shared box) that hold an int32, and the
44
46
  * group of each `function\0local` member. */
45
47
  boxes = new Set();
@@ -58,6 +60,12 @@ export class Int32Slots {
58
60
  /** Drops the analysis attempted on pinned slots. The contract check and
59
61
  * this analysis use the same range proofs, so this stays empty. */
60
62
  pinViolations = [];
63
+ /** Parameter, return and box candidates (`param:`, `ret:`, `box:` keys)
64
+ * still assumed to hold only non-negative int32s. The optimistic fixpoint
65
+ * starts every unpinned candidate here and demotes it to int32 when a
66
+ * write is an int32 that may be negative: `(x * 31 + n) % m` only proves
67
+ * a result when x and n are known not to be negative. */
68
+ nonNegative = new Set();
61
69
  constructor(classes = new Map()) {
62
70
  this.classes = classes;
63
71
  }
@@ -96,10 +104,14 @@ export class Int32Slots {
96
104
  this.boxes.size === 0 &&
97
105
  this.int32Locals.size === 0)
98
106
  return {};
107
+ const level = (key) => this.nonNegative.has(key) ? NON_NEGATIVE_INT32_RANGE : INT32_RANGE;
99
108
  const result = {
100
109
  field: (className, field) => (this.isField(className, field) ? INT32_RANGE : null),
101
- call: (callee) => (this.returns.has(callee) ? INT32_RANGE : null),
102
- boxed: (localId) => (this.hasBox(this.boxGroup(fnName, localId)) ? INT32_RANGE : null),
110
+ call: (callee) => this.returns.has(callee) ? (this.returnRanges.get(callee) ?? level(`ret:${callee}`)) : null,
111
+ boxed: (localId) => {
112
+ const group = this.boxGroup(fnName, localId);
113
+ return group !== null && this.boxes.has(group) ? level(`box:${group}`) : null;
114
+ },
103
115
  };
104
116
  if (this.int32Locals.size > 0)
105
117
  result.locals = (localId) => this.int32Locals.has(`${fnName}\0${localId}`) || this.int32Locals.has(`\0${localId}`)
@@ -107,9 +119,47 @@ export class Int32Slots {
107
119
  : null;
108
120
  const params = this.paramFacts.get(fnName);
109
121
  if (params)
110
- result.params = params;
122
+ result.params =
123
+ this.nonNegative.size === 0
124
+ ? params
125
+ : new Map([...params].map(([id, range]) => {
126
+ const key = `param:${fnName}\0${id}`;
127
+ return [id, this.nonNegative.has(key) ? NON_NEGATIVE_INT32_RANGE : range];
128
+ }));
111
129
  return result;
112
130
  }
131
+ /** Assume an unpinned candidate holds only non-negative int32s. */
132
+ assumeNonNegative(key) {
133
+ if (!this.pinned.has(key))
134
+ this.nonNegative.add(key);
135
+ }
136
+ isNonNegative(key) {
137
+ return this.nonNegative.has(key);
138
+ }
139
+ /** Widen a non-negative candidate to int32; whether it was one. */
140
+ demote(key) {
141
+ return this.nonNegative.delete(key);
142
+ }
143
+ isPinned(key) {
144
+ return this.pinned.has(key);
145
+ }
146
+ /** The range a parameter fact currently asserts, if it has one. */
147
+ paramRange(fnName, localId) {
148
+ return this.facts(fnName).params?.get(localId) ?? null;
149
+ }
150
+ /** The range a result fact currently asserts, if it has one. */
151
+ returnRange(fnName) {
152
+ return this.facts(fnName).call?.(fnName) ?? null;
153
+ }
154
+ /** Replace a parameter fact with a narrower proven range. */
155
+ narrowParam(fnName, localId, range) {
156
+ this.nonNegative.delete(`param:${fnName}\0${localId}`);
157
+ this.addParam(fnName, localId, range);
158
+ }
159
+ /** Replace a result fact with a narrower proven range. */
160
+ narrowReturn(fnName, range) {
161
+ this.returnRanges.set(fnName, range);
162
+ }
113
163
  boxGroup(fnName, localId) {
114
164
  return this.boxGroupOf.get(`${fnName}\0${localId}`) ?? null;
115
165
  }
@@ -137,6 +187,7 @@ export class Int32Slots {
137
187
  dropBox(group) {
138
188
  if (this.refusePinned(`box:${group}`))
139
189
  return false;
190
+ this.nonNegative.delete(`box:${group}`);
140
191
  return this.boxes.delete(group);
141
192
  }
142
193
  hasBox(group) {
@@ -162,6 +213,7 @@ export class Int32Slots {
162
213
  dropParam(fnName, localId) {
163
214
  if (this.refusePinned(`param:${fnName}\0${localId}`))
164
215
  return false;
216
+ this.nonNegative.delete(`param:${fnName}\0${localId}`);
165
217
  const params = this.paramFacts.get(fnName);
166
218
  if (!params?.delete(localId))
167
219
  return false;
@@ -178,6 +230,8 @@ export class Int32Slots {
178
230
  dropReturn(fnName) {
179
231
  if (this.refusePinned(`ret:${fnName}`))
180
232
  return false;
233
+ this.nonNegative.delete(`ret:${fnName}`);
234
+ this.returnRanges.delete(fnName);
181
235
  return this.returns.delete(fnName);
182
236
  }
183
237
  hasReturn(fnName) {
@@ -231,12 +285,25 @@ const DYN_READ_ONLY = new Set([
231
285
  "arrayBuffer.viewU8",
232
286
  "arrayBuffer.viewU8C",
233
287
  "date.nativeNew",
288
+ // The dynamic operators run the ToPrimitive and coercion helpers of
289
+ // dyn.compare, dyn.numberConstructor and dyn.toStringCoerce, then build a
290
+ // fresh number, string or bigint. dyn.increment steps dyn.toNumeric's result.
291
+ "dyn.add",
292
+ "dyn.arithmetic",
234
293
  "dyn.arrAt",
235
294
  "dyn.arrLen",
236
295
  "dyn.bagGet",
296
+ "dyn.bitwise",
237
297
  "dyn.compare",
298
+ "dyn.forInKeyStrings",
299
+ "dyn.forInKeys",
300
+ "dyn.forInStable",
301
+ "dyn.getOwnPropertyNames",
302
+ "dyn.getPrototype",
238
303
  "dyn.hasKey",
304
+ "dyn.hasOwn",
239
305
  "dyn.in",
306
+ "dyn.increment",
240
307
  "dyn.iterator",
241
308
  "dyn.iteratorCanStep",
242
309
  "dyn.iteratorResult",
@@ -245,13 +312,25 @@ const DYN_READ_ONLY = new Set([
245
312
  "dyn.mapSeedEntries",
246
313
  "dyn.mapSeedEntry",
247
314
  "dyn.numberConstructor",
315
+ "dyn.objCreate",
316
+ "dyn.objEntries",
317
+ "dyn.objEntryPairs",
318
+ "dyn.objKeyStrings",
319
+ "dyn.objKeys",
320
+ "dyn.objValues",
321
+ "dyn.objectTag",
322
+ "dyn.ownKeys",
248
323
  "dyn.packPush",
249
324
  "dyn.packPushSpread",
250
325
  "dyn.stringConstructor",
251
326
  "dyn.this",
327
+ "dyn.toNumberCoerce",
328
+ "dyn.toNumeric",
329
+ "dyn.toString",
252
330
  "dyn.toStringCoerce",
253
331
  "dyn.typedRefIs",
254
332
  "dyn.typedRefKeyIs",
333
+ "dyn.typeof",
255
334
  // error.ctorOptions runs scr_error_init_options, the initializer
256
335
  // error.newOptions also runs: it stamps the receiver's runtime-owned
257
336
  // error prefix and reads `options.cause`.
@@ -259,9 +338,24 @@ const DYN_READ_ONLY = new Set([
259
338
  "error.new",
260
339
  "error.newOptions",
261
340
  "fs.utimesSync",
341
+ "insp.dyn",
342
+ "insp.dynS",
262
343
  "json.stringifyReplacer",
263
344
  "json.stringifyValue",
264
345
  "num.toStringRadix",
346
+ // Process event listeners (signals, uncaughtException, unhandledRejection,
347
+ // rejectionHandled, warning): the runtime keeps the callback and calls it
348
+ // with fresh event values; off compares callbacks by identity.
349
+ "process.offRejectionHandled",
350
+ "process.offSignal",
351
+ "process.offUncaughtException",
352
+ "process.offUnhandledRejection",
353
+ "process.offWarning",
354
+ "process.onRejectionHandled",
355
+ "process.onSignal",
356
+ "process.onUncaughtException",
357
+ "process.onUnhandledRejection",
358
+ "process.onWarning",
265
359
  "sharedArrayBuffer.new",
266
360
  "text.decodeStream",
267
361
  "worker.new",
@@ -654,8 +748,10 @@ export function analyzeInt32Slots(mod) {
654
748
  },
655
749
  });
656
750
  for (const fn of mod.functions) {
657
- if (fn.returnType.kind === "f64" && !fn.async && !fn.generator)
751
+ if (fn.returnType.kind === "f64" && !fn.async && !fn.generator) {
658
752
  slots.addReturn(fn.name);
753
+ slots.assumeNonNegative(`ret:${fn.name}`);
754
+ }
659
755
  if (fn.async ||
660
756
  fn.generator ||
661
757
  !called.has(fn.name) ||
@@ -663,8 +759,10 @@ export function analyzeInt32Slots(mod) {
663
759
  virtual(fn.name))
664
760
  continue;
665
761
  for (const param of fn.params)
666
- if (param.type.kind === "f64")
762
+ if (param.type.kind === "f64" && !slots.isPinned(paramKey(fn.name, param.localId))) {
667
763
  slots.addParam(fn.name, param.localId);
764
+ slots.assumeNonNegative(paramKey(fn.name, param.localId));
765
+ }
668
766
  }
669
767
  const arityChecked = (fn, args, offset) => {
670
768
  if (fn && fn.params.length !== args + offset)
@@ -784,6 +882,11 @@ export function analyzeInt32Slots(mod) {
784
882
  }
785
883
  boxOrigin.set(`param:${fnName}\0${localId}`, group);
786
884
  slots.addBox(group, members);
885
+ // A box starts from its origin parameter's value: it can only be
886
+ // non-negative while that parameter is.
887
+ if (!origin.params.some((p) => p.localId === localId) ||
888
+ slots.isNonNegative(paramKey(fnName, localId)))
889
+ slots.assumeNonNegative(`box:${group}`);
787
890
  }
788
891
  const dropBox = (group, why) => {
789
892
  if (group === null)
@@ -876,6 +979,9 @@ export function analyzeInt32Slots(mod) {
876
979
  });
877
980
  };
878
981
  const provenByFunction = new Map();
982
+ // Each function's parameter and result writes under its latest analysis:
983
+ // at the fixpoint, the ranges of every write under the final facts.
984
+ const lastWrites = new Map();
879
985
  while (queue.length) {
880
986
  const fn = functions.get(queue.pop());
881
987
  queued.delete(fn.name);
@@ -888,16 +994,35 @@ export function analyzeInt32Slots(mod) {
888
994
  const ranges = hasCandidateWrite(fn)
889
995
  ? analyzeIntegerRanges(numeric(fn), slots.facts(fn.name))
890
996
  : new Map();
997
+ if (ranges.size > 0)
998
+ lastWrites.set(fn.name, slotWrites(fn, ranges, functions));
999
+ else
1000
+ lastWrites.delete(fn.name);
891
1001
  const proven = [];
892
1002
  const int32 = (e) => withinInt32(ranges.get(e));
1003
+ // An int32 written into a slot still assumed non-negative: widen the
1004
+ // assumption when the value may be negative, and reanalyze its readers.
1005
+ const settle = (slot, e) => {
1006
+ if (!slots.isNonNegative(slot) || (ranges.get(e)?.min ?? -1) >= 0)
1007
+ return;
1008
+ slots.demote(slot);
1009
+ invalidate(slot);
1010
+ const group = boxOrigin.get(slot);
1011
+ if (group !== undefined && slots.demote(`box:${group}`))
1012
+ invalidate(`box:${group}`);
1013
+ };
893
1014
  const args = (callee, list, offset) => {
894
1015
  if (!callee)
895
1016
  return;
896
1017
  list.forEach((arg, i) => {
897
1018
  const param = callee.params[i + offset];
898
- if (!param || !slots.hasParam(callee.name, param.localId) || int32(arg))
1019
+ if (!param || !slots.hasParam(callee.name, param.localId))
899
1020
  return;
900
1021
  const slot = `param:${callee.name}\0${param.localId}`;
1022
+ if (int32(arg)) {
1023
+ settle(slot, arg);
1024
+ return;
1025
+ }
901
1026
  if (dropParam(callee.name, param.localId, `argument in ${fn.name} is not int32`)) {
902
1027
  invalidate(slot);
903
1028
  // An argument computed where the caller's own parameters were
@@ -913,9 +1038,11 @@ export function analyzeInt32Slots(mod) {
913
1038
  };
914
1039
  const boxWrite = (localId, value) => {
915
1040
  const group = slots.boxGroup(fn.name, localId);
916
- if (!slots.hasBox(group) || int32(value))
1041
+ if (!slots.hasBox(group))
917
1042
  return;
918
- if (dropBox(group, `write in ${fn.name} is not int32`))
1043
+ if (int32(value))
1044
+ settle(`box:${group}`, value);
1045
+ else if (dropBox(group, `write in ${fn.name} is not int32`))
919
1046
  invalidate(`box:${group}`);
920
1047
  };
921
1048
  walkFunction(fn, {
@@ -936,8 +1063,10 @@ export function analyzeInt32Slots(mod) {
936
1063
  }
937
1064
  }
938
1065
  else if (s.kind === "return" && slots.hasReturn(fn.name)) {
939
- if (s.value && int32(s.value))
1066
+ if (s.value && int32(s.value)) {
1067
+ settle(`ret:${fn.name}`, s.value);
940
1068
  return;
1069
+ }
941
1070
  reason(`ret:${fn.name}`, "return is not int32");
942
1071
  slots.dropReturn(fn.name);
943
1072
  invalidate(`ret:${fn.name}`);
@@ -957,7 +1086,8 @@ export function analyzeInt32Slots(mod) {
957
1086
  for (const proven of provenByFunction.values())
958
1087
  for (const value of proven)
959
1088
  slots.provenWrites.add(value);
960
- rangedParameters(slots, functions, retry, numeric, (callee) => readers.get(`ret:${callee}`));
1089
+ const ranged = rangedParameters(slots, functions, retry, numeric, (callee) => readers.get(`ret:${callee}`));
1090
+ narrowSlotRanges(slots, functions, numeric, lastWrites, ranged, (slot) => readers.get(slot));
961
1091
  return slots;
962
1092
  }
963
1093
  /** Bounds a widened parameter range jumps to: the int32 limits, and the
@@ -985,8 +1115,9 @@ const widenMax = (max) => WIDEN_MAX.find((bound) => bound >= max) ?? Infinity;
985
1115
  * every call site is checked under the final ranges. The facts the main
986
1116
  * fixpoint proved are fixed here: these ranges only add precision. */
987
1117
  function rangedParameters(slots, functions, retry, numeric, callersOf) {
1118
+ const changed = new Set();
988
1119
  if (retry.size === 0)
989
- return;
1120
+ return changed;
990
1121
  // Per function: retried parameter → its range so far (absent: no call
991
1122
  // site analyzed yet; null: failed).
992
1123
  const retried = new Map();
@@ -1097,7 +1228,261 @@ function rangedParameters(slots, functions, retry, numeric, callersOf) {
1097
1228
  }
1098
1229
  for (const [fnName, ranges] of retried)
1099
1230
  for (const [id, range] of ranges)
1100
- if (range)
1231
+ if (range) {
1101
1232
  slots.addParam(fnName, id, range);
1233
+ changed.add(fnName);
1234
+ }
1235
+ return changed;
1236
+ }
1237
+ const joinRanges = (a, b) => a && b ? { min: Math.min(a.min, b.min), max: Math.max(a.max, b.max) } : null;
1238
+ const rangeWithin = (inner, outer) => inner !== null && inner.min >= outer.min && inner.max <= outer.max;
1239
+ const sameRange = (a, b) => a.min === b.min && a.max === b.max;
1240
+ /** The values one analysis of a function writes into parameter slots of
1241
+ * its direct callees and into its own result slot (`param:` and `ret:`
1242
+ * keys), joined per slot; null when some write has no proven range. */
1243
+ function slotWrites(fn, ranges, functions) {
1244
+ const writes = new Map();
1245
+ const write = (key, value) => {
1246
+ const range = value ? (ranges.get(value) ?? null) : null;
1247
+ const previous = writes.get(key);
1248
+ writes.set(key, previous === undefined ? range : joinRanges(previous, range));
1249
+ };
1250
+ const args = (callee, list, offset) => {
1251
+ if (!callee)
1252
+ return;
1253
+ list.forEach((arg, i) => {
1254
+ const param = callee.params[i + offset];
1255
+ if (param)
1256
+ write(`param:${callee.name}\0${param.localId}`, arg);
1257
+ });
1258
+ };
1259
+ walkFunction(fn, {
1260
+ stmt: (s) => {
1261
+ if (s.kind === "return")
1262
+ write(`ret:${fn.name}`, s.value);
1263
+ },
1264
+ expr: (e) => {
1265
+ if (e.kind === "call")
1266
+ args(functions.get(e.callee), e.args, 0);
1267
+ else if (e.kind === "new")
1268
+ args(functions.get(`%${e.className}.constructor`), e.args, 1);
1269
+ },
1270
+ });
1271
+ return writes;
1272
+ }
1273
+ /** Rounds after which narrowSlotRanges keeps its last verified ranges. */
1274
+ const NARROW_ROUNDS = 6;
1275
+ /** Narrows parameter and result facts from their proven level (int32 or
1276
+ * non-negative int32, or a call-site range) to the values actually written
1277
+ * into them, and revives results the level could not prove. `(x * 31 + n)
1278
+ * % m` proves its result only under a positive divisor, and keeps i32
1279
+ * arithmetic only when `x` is known to be small; the levels know neither,
1280
+ * the values passed and returned do.
1281
+ *
1282
+ * A descending iteration from the fixpoint's facts: each round assumes a
1283
+ * range for every slot, reanalyzes the functions that read a slot whose
1284
+ * assumption changed, and joins the ranges of every write into each slot.
1285
+ * The assumptions are verified (inductive) when every slot's writes land
1286
+ * inside its assumed range: then, by induction over the execution, every
1287
+ * slot holds only values in its range. A verified round adopts the joined
1288
+ * writes as the next assumptions (each bound moves at most once, so the
1289
+ * iteration ends), and a reanalyzed function whose every return is now an
1290
+ * int32 joins with that range as a result candidate. A slot whose writes
1291
+ * leave its assumption falls back to its last verified range (a revived
1292
+ * result to none). Only verified assumptions are kept, and a reanalyzed
1293
+ * function must still prove every write into a field or box slot (whose
1294
+ * facts do not change here), or the narrowing is abandoned. Pinned
1295
+ * (contract) slots keep their contract range. */
1296
+ function narrowSlotRanges(slots, functions, numeric, lastWrites, changed, readersOf) {
1297
+ // Every parameter and result slot with a fact, and that fact.
1298
+ const proven = new Map();
1299
+ const fixed = new Set();
1300
+ // Results the fixpoint dropped (a return was not an int32 at the level).
1301
+ const revivable = new Set();
1302
+ for (const fn of functions.values()) {
1303
+ const result = slots.hasReturn(fn.name) ? slots.returnRange(fn.name) : null;
1304
+ if (result)
1305
+ proven.set(`ret:${fn.name}`, result);
1306
+ else if (fn.returnType.kind === "f64" && !fn.async && !fn.generator)
1307
+ revivable.add(`ret:${fn.name}`);
1308
+ for (const param of fn.params) {
1309
+ const range = slots.hasParam(fn.name, param.localId)
1310
+ ? slots.paramRange(fn.name, param.localId)
1311
+ : null;
1312
+ if (range)
1313
+ proven.set(`param:${fn.name}\0${param.localId}`, range);
1314
+ }
1315
+ }
1316
+ for (const key of proven.keys())
1317
+ if (slots.isPinned(key))
1318
+ fixed.add(key);
1319
+ if (proven.size === fixed.size)
1320
+ return;
1321
+ // The readers of a slot: a parameter's function, a result's callers.
1322
+ const readersOfKey = (key) => {
1323
+ if (key.startsWith("param:"))
1324
+ return [key.slice(6, key.indexOf("\0"))];
1325
+ const readers = readersOf(key);
1326
+ return readers ? [...readers] : [];
1327
+ };
1328
+ const factsUnder = (fn, assumed) => {
1329
+ const base = slots.facts(fn.name);
1330
+ const params = new Map(base.params ?? []);
1331
+ for (const param of fn.params) {
1332
+ const range = assumed.get(`param:${fn.name}\0${param.localId}`);
1333
+ if (range)
1334
+ params.set(param.localId, range);
1335
+ }
1336
+ const call = base.call;
1337
+ return {
1338
+ ...base,
1339
+ params,
1340
+ call: (callee) => assumed.get(`ret:${callee}`) ?? (call ? call(callee) : null),
1341
+ };
1342
+ };
1343
+ // Reanalyze one function: its slot writes, and whether it still proves
1344
+ // every write into field and box slots.
1345
+ const observe = (fn, assumed) => {
1346
+ const ranges = analyzeIntegerRanges(numeric(fn), factsUnder(fn, assumed));
1347
+ let sound = true;
1348
+ const box = (localId, value) => {
1349
+ const group = slots.boxGroup(fn.name, localId);
1350
+ if (!slots.hasBox(group))
1351
+ return;
1352
+ const range = ranges.get(value) ?? null;
1353
+ const level = slots.isNonNegative(`box:${group}`) ? NON_NEGATIVE_INT32_RANGE : INT32_RANGE;
1354
+ if (!rangeWithin(range, level))
1355
+ sound = false;
1356
+ };
1357
+ walkFunction(fn, {
1358
+ stmt: (s) => {
1359
+ if (s.kind === "assign")
1360
+ box(s.localId, s.value);
1361
+ else if (s.kind === "varDecl" && s.init)
1362
+ box(s.localId, s.init);
1363
+ else if (s.kind === "fieldSet" && slots.isField(s.className, s.field))
1364
+ if (!withinInt32(ranges.get(s.value)))
1365
+ sound = false;
1366
+ },
1367
+ expr: (e) => {
1368
+ if (e.kind === "assignExpr")
1369
+ box(e.localId, e.value);
1370
+ },
1371
+ });
1372
+ return { writes: slotWrites(fn, ranges, functions), sound };
1373
+ };
1374
+ const writesByFunction = new Map(lastWrites);
1375
+ const join = () => {
1376
+ const joined = new Map();
1377
+ for (const writes of writesByFunction.values())
1378
+ for (const [key, range] of writes) {
1379
+ if (!proven.has(key) && !revivable.has(key))
1380
+ continue;
1381
+ const previous = joined.get(key);
1382
+ joined.set(key, previous === undefined ? range : joinRanges(previous, range));
1383
+ }
1384
+ return joined;
1385
+ };
1386
+ // The ranges every function was last analyzed under.
1387
+ let analyzed = new Map(proven);
1388
+ let verified = new Map(proven);
1389
+ // Functions whose recorded writes predate their current facts.
1390
+ const dirty = new Set(changed);
1391
+ // The narrowing operator: a bound moves at most once from its proven
1392
+ // value (a revived result's from int32), so recursion that shifts its
1393
+ // argument (`f(d - 1)`) cannot walk a bound down one step per round.
1394
+ const narrowed = (joined) => {
1395
+ const next = new Map(verified);
1396
+ for (const [key, range] of joined) {
1397
+ const current = verified.get(key);
1398
+ if (!current || fixed.has(key) || !range || !rangeWithin(range, current))
1399
+ continue;
1400
+ const original = proven.get(key) ?? INT32_RANGE;
1401
+ next.set(key, {
1402
+ min: current.min === original.min ? range.min : current.min,
1403
+ max: current.max === original.max ? range.max : current.max,
1404
+ });
1405
+ }
1406
+ return next;
1407
+ };
1408
+ let assumed = dirty.size > 0 ? new Map(proven) : narrowed(join());
1409
+ for (let round = 0; round < NARROW_ROUNDS; round++) {
1410
+ for (const [key, range] of assumed) {
1411
+ const before = analyzed.get(key);
1412
+ if (!before || !sameRange(range, before))
1413
+ for (const name of readersOfKey(key))
1414
+ dirty.add(name);
1415
+ }
1416
+ for (const key of analyzed.keys())
1417
+ if (!assumed.has(key))
1418
+ for (const name of readersOfKey(key))
1419
+ dirty.add(name);
1420
+ const observedNow = new Set();
1421
+ for (const name of dirty) {
1422
+ const fn = functions.get(name);
1423
+ if (!fn)
1424
+ continue;
1425
+ const observed = observe(fn, assumed);
1426
+ if (!observed.sound)
1427
+ return;
1428
+ writesByFunction.set(name, observed.writes);
1429
+ observedNow.add(name);
1430
+ }
1431
+ dirty.clear();
1432
+ analyzed = assumed;
1433
+ const joined = join();
1434
+ let inductive = true;
1435
+ const next = new Map(assumed);
1436
+ for (const [key, range] of assumed) {
1437
+ const written = joined.get(key);
1438
+ if (written === undefined || rangeWithin(written, range))
1439
+ continue;
1440
+ inductive = false;
1441
+ const fallback = verified.get(key);
1442
+ if (fallback)
1443
+ next.set(key, fallback);
1444
+ else
1445
+ next.delete(key);
1446
+ }
1447
+ if (inductive) {
1448
+ verified = assumed;
1449
+ const tighter = narrowed(joined);
1450
+ // Results that reanalysis under the narrowed facts proves now.
1451
+ for (const key of revivable) {
1452
+ const range = joined.get(key);
1453
+ if (!tighter.has(key) && observedNow.has(key.slice(4)) && withinInt32(range))
1454
+ tighter.set(key, range);
1455
+ }
1456
+ if (tighter.size === assumed.size &&
1457
+ [...tighter].every(([key, range]) => sameRange(range, assumed.get(key))))
1458
+ break;
1459
+ assumed = tighter;
1460
+ }
1461
+ else if (next.size !== assumed.size ||
1462
+ [...next].some(([key, range]) => !sameRange(range, assumed.get(key)))) {
1463
+ assumed = next;
1464
+ }
1465
+ else
1466
+ break; // narrowing other slots broke a verified one: keep `verified`
1467
+ }
1468
+ for (const [key, range] of verified) {
1469
+ if (fixed.has(key))
1470
+ continue;
1471
+ const original = proven.get(key);
1472
+ if (original && sameRange(range, original))
1473
+ continue;
1474
+ if (key.startsWith("ret:")) {
1475
+ const fnName = key.slice(4);
1476
+ if (!original) {
1477
+ slots.addReturn(fnName);
1478
+ slots.reasons.delete(key);
1479
+ }
1480
+ slots.narrowReturn(fnName, range);
1481
+ }
1482
+ else {
1483
+ const cut = key.indexOf("\0");
1484
+ slots.narrowParam(key.slice(6, cut), key.slice(cut + 1), range);
1485
+ }
1486
+ }
1102
1487
  }
1103
1488
  //# sourceMappingURL=int32-slots.js.map