rigortype 0.2.7 → 0.2.8

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 (414) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/docs/manual/04-diagnostics.md +7 -4
  4. data/docs/manual/06-baseline.md +5 -2
  5. data/docs/manual/15-type-protection-coverage.md +6 -4
  6. data/lib/rigor/analysis/baseline.rb +56 -96
  7. data/lib/rigor/analysis/buffer_binding.rb +13 -20
  8. data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +29 -48
  9. data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +35 -54
  10. data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +23 -37
  11. data/lib/rigor/analysis/check_rules/main_pass_collector.rb +16 -23
  12. data/lib/rigor/analysis/check_rules/rule_walk.rb +48 -71
  13. data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +19 -28
  14. data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +48 -67
  15. data/lib/rigor/analysis/check_rules.rb +174 -274
  16. data/lib/rigor/analysis/dependency_recorder.rb +26 -38
  17. data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +13 -25
  18. data/lib/rigor/analysis/dependency_source_inference/builder.rb +17 -30
  19. data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +15 -26
  20. data/lib/rigor/analysis/dependency_source_inference/index.rb +45 -76
  21. data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +23 -40
  22. data/lib/rigor/analysis/dependency_source_inference/walker.rb +50 -83
  23. data/lib/rigor/analysis/dependency_source_inference.rb +6 -10
  24. data/lib/rigor/analysis/diagnostic.rb +48 -75
  25. data/lib/rigor/analysis/erb_template_detector.rb +13 -18
  26. data/lib/rigor/analysis/fact_store.rb +12 -22
  27. data/lib/rigor/analysis/incremental.rb +47 -63
  28. data/lib/rigor/analysis/incremental_session.rb +74 -100
  29. data/lib/rigor/analysis/project_scan.rb +12 -23
  30. data/lib/rigor/analysis/result.rb +3 -5
  31. data/lib/rigor/analysis/rule_catalog.rb +67 -95
  32. data/lib/rigor/analysis/run_stats.rb +38 -61
  33. data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +101 -160
  34. data/lib/rigor/analysis/runner/pool_coordinator.rb +121 -188
  35. data/lib/rigor/analysis/runner/project_pre_passes.rb +62 -96
  36. data/lib/rigor/analysis/runner/run_snapshots.rb +12 -18
  37. data/lib/rigor/analysis/runner.rb +220 -333
  38. data/lib/rigor/analysis/self_call_resolution_recorder.rb +30 -43
  39. data/lib/rigor/analysis/worker_session.rb +64 -102
  40. data/lib/rigor/ast/type_node.rb +6 -8
  41. data/lib/rigor/ast.rb +6 -10
  42. data/lib/rigor/bleeding_edge.rb +27 -35
  43. data/lib/rigor/builtins/hkt_builtins.rb +7 -14
  44. data/lib/rigor/builtins/imported_refinements.rb +106 -149
  45. data/lib/rigor/builtins/predefined_constant_refinements.rb +51 -65
  46. data/lib/rigor/builtins/regex_refinement.rb +32 -43
  47. data/lib/rigor/builtins/static_return_refinements.rb +57 -81
  48. data/lib/rigor/cache/descriptor.rb +58 -94
  49. data/lib/rigor/cache/incremental_snapshot.rb +32 -48
  50. data/lib/rigor/cache/rbs_cache_producer.rb +10 -15
  51. data/lib/rigor/cache/rbs_class_ancestor_table.rb +10 -16
  52. data/lib/rigor/cache/rbs_class_type_param_names.rb +10 -16
  53. data/lib/rigor/cache/rbs_constant_table.rb +8 -13
  54. data/lib/rigor/cache/rbs_descriptor.rb +8 -13
  55. data/lib/rigor/cache/rbs_environment.rb +11 -19
  56. data/lib/rigor/cache/rbs_environment_marshal_patch.rb +11 -19
  57. data/lib/rigor/cache/rbs_known_class_names.rb +8 -12
  58. data/lib/rigor/cache/store.rb +96 -151
  59. data/lib/rigor/cli/annotate_command.rb +51 -88
  60. data/lib/rigor/cli/baseline_command.rb +10 -17
  61. data/lib/rigor/cli/check_command.rb +121 -199
  62. data/lib/rigor/cli/check_runner_factory.rb +8 -14
  63. data/lib/rigor/cli/ci_detector.rb +9 -14
  64. data/lib/rigor/cli/command.rb +8 -14
  65. data/lib/rigor/cli/coverage_command.rb +19 -26
  66. data/lib/rigor/cli/coverage_mutation.rb +14 -19
  67. data/lib/rigor/cli/coverage_report.rb +0 -2
  68. data/lib/rigor/cli/coverage_scan.rb +7 -11
  69. data/lib/rigor/cli/diagnostic_formats.rb +43 -62
  70. data/lib/rigor/cli/diff_command.rb +10 -20
  71. data/lib/rigor/cli/docs_command.rb +26 -40
  72. data/lib/rigor/cli/doctor_command.rb +8 -9
  73. data/lib/rigor/cli/explain_command.rb +4 -7
  74. data/lib/rigor/cli/fused_protection_renderer.rb +4 -5
  75. data/lib/rigor/cli/fused_protection_report.rb +6 -8
  76. data/lib/rigor/cli/lsp_command.rb +11 -19
  77. data/lib/rigor/cli/mcp_command.rb +4 -6
  78. data/lib/rigor/cli/mutation_protection_renderer.rb +3 -4
  79. data/lib/rigor/cli/mutation_protection_report.rb +6 -9
  80. data/lib/rigor/cli/options.rb +11 -19
  81. data/lib/rigor/cli/plugin_command.rb +18 -30
  82. data/lib/rigor/cli/plugins_command.rb +29 -51
  83. data/lib/rigor/cli/plugins_renderer.rb +12 -20
  84. data/lib/rigor/cli/prism_colorizer.rb +13 -19
  85. data/lib/rigor/cli/protection_renderer.rb +5 -7
  86. data/lib/rigor/cli/protection_report.rb +27 -17
  87. data/lib/rigor/cli/renderable.rb +4 -6
  88. data/lib/rigor/cli/show_bleedingedge_command.rb +5 -8
  89. data/lib/rigor/cli/sig_gen_command.rb +14 -26
  90. data/lib/rigor/cli/skill_command.rb +30 -47
  91. data/lib/rigor/cli/skill_describe.rb +40 -64
  92. data/lib/rigor/cli/trace_command.rb +9 -16
  93. data/lib/rigor/cli/trace_renderer.rb +35 -51
  94. data/lib/rigor/cli/triage_command.rb +6 -10
  95. data/lib/rigor/cli/triage_renderer.rb +1 -2
  96. data/lib/rigor/cli/type_of_command.rb +14 -23
  97. data/lib/rigor/cli/type_of_renderer.rb +3 -5
  98. data/lib/rigor/cli/type_scan_command.rb +6 -10
  99. data/lib/rigor/cli/type_scan_renderer.rb +3 -5
  100. data/lib/rigor/cli/type_scan_report.rb +2 -3
  101. data/lib/rigor/cli/upgrade_command.rb +2 -3
  102. data/lib/rigor/cli.rb +16 -28
  103. data/lib/rigor/config_audit.rb +35 -44
  104. data/lib/rigor/configuration/dependencies.rb +41 -70
  105. data/lib/rigor/configuration/severity_profile.rb +28 -42
  106. data/lib/rigor/configuration.rb +150 -241
  107. data/lib/rigor/environment/bundle_sig_discovery.rb +74 -118
  108. data/lib/rigor/environment/class_registry.rb +19 -26
  109. data/lib/rigor/environment/constant_type_cache_holder.rb +14 -21
  110. data/lib/rigor/environment/hkt_registry_holder.rb +6 -12
  111. data/lib/rigor/environment/lockfile_resolver.rb +31 -47
  112. data/lib/rigor/environment/rbs_collection_discovery.rb +39 -63
  113. data/lib/rigor/environment/rbs_coverage_report.rb +24 -42
  114. data/lib/rigor/environment/rbs_loader.rb +420 -518
  115. data/lib/rigor/environment/reflection.rb +28 -53
  116. data/lib/rigor/environment/reporters.rb +13 -24
  117. data/lib/rigor/environment.rb +176 -291
  118. data/lib/rigor/flow_contribution/conflict.rb +16 -27
  119. data/lib/rigor/flow_contribution/element.rb +7 -12
  120. data/lib/rigor/flow_contribution/fact.rb +33 -57
  121. data/lib/rigor/flow_contribution/merge_result.rb +6 -9
  122. data/lib/rigor/flow_contribution/merger.rb +32 -47
  123. data/lib/rigor/flow_contribution.rb +37 -55
  124. data/lib/rigor/inference/acceptance.rb +133 -219
  125. data/lib/rigor/inference/block_parameter_binder.rb +52 -82
  126. data/lib/rigor/inference/body_fixpoint.rb +22 -30
  127. data/lib/rigor/inference/budget_trace.rb +43 -63
  128. data/lib/rigor/inference/builtins/array_catalog.rb +4 -6
  129. data/lib/rigor/inference/builtins/comparable_catalog.rb +4 -6
  130. data/lib/rigor/inference/builtins/complex_catalog.rb +13 -19
  131. data/lib/rigor/inference/builtins/date_catalog.rb +38 -67
  132. data/lib/rigor/inference/builtins/encoding_catalog.rb +22 -36
  133. data/lib/rigor/inference/builtins/enumerable_catalog.rb +4 -6
  134. data/lib/rigor/inference/builtins/exception_catalog.rb +38 -57
  135. data/lib/rigor/inference/builtins/hash_catalog.rb +9 -14
  136. data/lib/rigor/inference/builtins/method_catalog.rb +29 -48
  137. data/lib/rigor/inference/builtins/numeric_catalog.rb +13 -18
  138. data/lib/rigor/inference/builtins/pathname_catalog.rb +8 -13
  139. data/lib/rigor/inference/builtins/proc_catalog.rb +38 -62
  140. data/lib/rigor/inference/builtins/random_catalog.rb +21 -32
  141. data/lib/rigor/inference/builtins/range_catalog.rb +12 -21
  142. data/lib/rigor/inference/builtins/rational_catalog.rb +9 -15
  143. data/lib/rigor/inference/builtins/re_catalog.rb +29 -48
  144. data/lib/rigor/inference/builtins/set_catalog.rb +18 -27
  145. data/lib/rigor/inference/builtins/string_catalog.rb +12 -19
  146. data/lib/rigor/inference/builtins/struct_catalog.rb +18 -30
  147. data/lib/rigor/inference/builtins/time_catalog.rb +28 -44
  148. data/lib/rigor/inference/closure_escape_analyzer.rb +44 -67
  149. data/lib/rigor/inference/coverage_scanner.rb +13 -18
  150. data/lib/rigor/inference/def_return_typer.rb +8 -14
  151. data/lib/rigor/inference/dynamic_origin.rb +23 -20
  152. data/lib/rigor/inference/expression_typer.rb +774 -1152
  153. data/lib/rigor/inference/fallback.rb +8 -12
  154. data/lib/rigor/inference/fallback_tracer.rb +4 -10
  155. data/lib/rigor/inference/flow_tracer.rb +25 -36
  156. data/lib/rigor/inference/hkt_body.rb +45 -68
  157. data/lib/rigor/inference/hkt_body_parser.rb +33 -52
  158. data/lib/rigor/inference/hkt_reducer.rb +38 -59
  159. data/lib/rigor/inference/hkt_registry.rb +50 -76
  160. data/lib/rigor/inference/indexed_narrowing.rb +55 -81
  161. data/lib/rigor/inference/macro_block_self_type.rb +21 -34
  162. data/lib/rigor/inference/method_dispatcher/array_to_h_folding.rb +11 -18
  163. data/lib/rigor/inference/method_dispatcher/block_folding.rb +49 -83
  164. data/lib/rigor/inference/method_dispatcher/call_context.rb +16 -23
  165. data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +13 -22
  166. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +307 -454
  167. data/lib/rigor/inference/method_dispatcher/data_folding.rb +24 -34
  168. data/lib/rigor/inference/method_dispatcher/file_folding.rb +22 -37
  169. data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +52 -81
  170. data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +51 -78
  171. data/lib/rigor/inference/method_dispatcher/literal_string_folding.rb +60 -97
  172. data/lib/rigor/inference/method_dispatcher/math_folding.rb +23 -34
  173. data/lib/rigor/inference/method_dispatcher/member_shape_projection.rb +18 -26
  174. data/lib/rigor/inference/method_dispatcher/method_folding.rb +37 -71
  175. data/lib/rigor/inference/method_dispatcher/overload_selector.rb +114 -182
  176. data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +122 -193
  177. data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +15 -24
  178. data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +64 -93
  179. data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +31 -45
  180. data/lib/rigor/inference/method_dispatcher/set_folding.rb +6 -9
  181. data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +356 -511
  182. data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +22 -32
  183. data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +15 -21
  184. data/lib/rigor/inference/method_dispatcher/struct_folding.rb +66 -82
  185. data/lib/rigor/inference/method_dispatcher/time_folding.rb +10 -15
  186. data/lib/rigor/inference/method_dispatcher/uri_folding.rb +9 -13
  187. data/lib/rigor/inference/method_dispatcher.rb +378 -524
  188. data/lib/rigor/inference/method_parameter_binder.rb +81 -114
  189. data/lib/rigor/inference/multi_target_binder.rb +51 -68
  190. data/lib/rigor/inference/mutation_widening.rb +115 -158
  191. data/lib/rigor/inference/narrowing.rb +509 -727
  192. data/lib/rigor/inference/origin_lookup.rb +38 -0
  193. data/lib/rigor/inference/parameter_inference_collector.rb +100 -100
  194. data/lib/rigor/inference/precision_scanner.rb +26 -35
  195. data/lib/rigor/inference/project_patched_methods.rb +20 -32
  196. data/lib/rigor/inference/project_patched_scanner.rb +23 -37
  197. data/lib/rigor/inference/protection_scanner.rb +16 -18
  198. data/lib/rigor/inference/rbs_type_translator.rb +49 -66
  199. data/lib/rigor/inference/scope_indexer.rb +473 -817
  200. data/lib/rigor/inference/statement_evaluator.rb +706 -1111
  201. data/lib/rigor/inference/struct_fold_safety.rb +34 -48
  202. data/lib/rigor/inference/synthetic_method.rb +9 -16
  203. data/lib/rigor/inference/synthetic_method_index.rb +20 -35
  204. data/lib/rigor/inference/synthetic_method_scanner.rb +63 -103
  205. data/lib/rigor/language_server/buffer_resolution.rb +6 -9
  206. data/lib/rigor/language_server/buffer_table.rb +11 -18
  207. data/lib/rigor/language_server/completion_provider.rb +69 -116
  208. data/lib/rigor/language_server/debouncer.rb +16 -25
  209. data/lib/rigor/language_server/diagnostic_publisher.rb +26 -40
  210. data/lib/rigor/language_server/document_symbol_provider.rb +14 -19
  211. data/lib/rigor/language_server/folding_range_provider.rb +11 -19
  212. data/lib/rigor/language_server/hover_provider.rb +8 -11
  213. data/lib/rigor/language_server/hover_renderer.rb +56 -93
  214. data/lib/rigor/language_server/loop.rb +14 -19
  215. data/lib/rigor/language_server/project_context.rb +46 -74
  216. data/lib/rigor/language_server/selection_range_provider.rb +9 -12
  217. data/lib/rigor/language_server/server.rb +55 -83
  218. data/lib/rigor/language_server/signature_help_provider.rb +29 -46
  219. data/lib/rigor/language_server/synchronized_writer.rb +4 -7
  220. data/lib/rigor/language_server/uri.rb +8 -13
  221. data/lib/rigor/language_server.rb +4 -6
  222. data/lib/rigor/mcp/loop.rb +2 -3
  223. data/lib/rigor/mcp/server.rb +4 -7
  224. data/lib/rigor/mcp.rb +3 -6
  225. data/lib/rigor/plugin/access_denied_error.rb +5 -8
  226. data/lib/rigor/plugin/additional_initializer.rb +21 -31
  227. data/lib/rigor/plugin/base.rb +335 -518
  228. data/lib/rigor/plugin/blueprint.rb +14 -23
  229. data/lib/rigor/plugin/box.rb +18 -29
  230. data/lib/rigor/plugin/fact_store.rb +16 -26
  231. data/lib/rigor/plugin/inflector.rb +37 -53
  232. data/lib/rigor/plugin/io_boundary.rb +33 -56
  233. data/lib/rigor/plugin/isolation.rb +42 -55
  234. data/lib/rigor/plugin/load_error.rb +10 -15
  235. data/lib/rigor/plugin/loader.rb +30 -49
  236. data/lib/rigor/plugin/macro/block_as_method.rb +20 -32
  237. data/lib/rigor/plugin/macro/heredoc_template.rb +35 -58
  238. data/lib/rigor/plugin/macro/nested_class_template.rb +22 -36
  239. data/lib/rigor/plugin/macro/trait_registry.rb +34 -51
  240. data/lib/rigor/plugin/macro.rb +10 -15
  241. data/lib/rigor/plugin/manifest.rb +85 -144
  242. data/lib/rigor/plugin/node_context.rb +14 -22
  243. data/lib/rigor/plugin/node_rule_walk.rb +49 -74
  244. data/lib/rigor/plugin/protocol_contract.rb +25 -39
  245. data/lib/rigor/plugin/registry.rb +132 -205
  246. data/lib/rigor/plugin/services.rb +21 -33
  247. data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -19
  248. data/lib/rigor/plugin/trust_policy.rb +24 -38
  249. data/lib/rigor/plugin/type_node_resolver.rb +15 -24
  250. data/lib/rigor/protection/diagnostic_oracle.rb +11 -13
  251. data/lib/rigor/protection/mutation_scanner.rb +27 -35
  252. data/lib/rigor/protection/mutator.rb +50 -70
  253. data/lib/rigor/protection/test_suite_oracle.rb +20 -27
  254. data/lib/rigor/rbs_extended/conformance_checker.rb +48 -68
  255. data/lib/rigor/rbs_extended/hkt_directives.rb +28 -54
  256. data/lib/rigor/rbs_extended/reporter.rb +24 -40
  257. data/lib/rigor/rbs_extended.rb +107 -197
  258. data/lib/rigor/reflection.rb +68 -86
  259. data/lib/rigor/scope/discovery_index.rb +14 -19
  260. data/lib/rigor/scope.rb +255 -310
  261. data/lib/rigor/sig_gen/classification.rb +6 -10
  262. data/lib/rigor/sig_gen/generator.rb +197 -323
  263. data/lib/rigor/sig_gen/layout_index.rb +12 -20
  264. data/lib/rigor/sig_gen/method_candidate.rb +12 -17
  265. data/lib/rigor/sig_gen/observation_collector.rb +38 -70
  266. data/lib/rigor/sig_gen/observed_call.rb +13 -23
  267. data/lib/rigor/sig_gen/path_mapper.rb +17 -29
  268. data/lib/rigor/sig_gen/renderer.rb +7 -13
  269. data/lib/rigor/sig_gen/type_elaborator.rb +15 -28
  270. data/lib/rigor/sig_gen/write_result.rb +8 -16
  271. data/lib/rigor/sig_gen/writer.rb +95 -174
  272. data/lib/rigor/sig_gen.rb +3 -6
  273. data/lib/rigor/signature_path_audit.rb +24 -30
  274. data/lib/rigor/source/constant_path.rb +10 -14
  275. data/lib/rigor/source/literals.rb +31 -45
  276. data/lib/rigor/source/node_locator.rb +9 -11
  277. data/lib/rigor/source/node_walker.rb +9 -13
  278. data/lib/rigor/source.rb +3 -4
  279. data/lib/rigor/testing.rb +16 -20
  280. data/lib/rigor/triage/catalogue.rb +38 -62
  281. data/lib/rigor/triage.rb +31 -52
  282. data/lib/rigor/trinary.rb +9 -13
  283. data/lib/rigor/type/acceptance_router.rb +4 -6
  284. data/lib/rigor/type/accepts_result.rb +10 -14
  285. data/lib/rigor/type/app.rb +19 -27
  286. data/lib/rigor/type/bot.rb +4 -6
  287. data/lib/rigor/type/bound_method.rb +10 -15
  288. data/lib/rigor/type/combinator.rb +165 -257
  289. data/lib/rigor/type/constant.rb +23 -34
  290. data/lib/rigor/type/data_class.rb +10 -15
  291. data/lib/rigor/type/data_instance.rb +14 -20
  292. data/lib/rigor/type/difference.rb +21 -32
  293. data/lib/rigor/type/dynamic.rb +3 -5
  294. data/lib/rigor/type/hash_shape.rb +32 -18
  295. data/lib/rigor/type/integer_range.rb +11 -16
  296. data/lib/rigor/type/intersection.rb +27 -42
  297. data/lib/rigor/type/nominal.rb +10 -15
  298. data/lib/rigor/type/plain_lattice.rb +9 -13
  299. data/lib/rigor/type/refined.rb +67 -114
  300. data/lib/rigor/type/singleton.rb +4 -6
  301. data/lib/rigor/type/struct_class.rb +11 -16
  302. data/lib/rigor/type/struct_instance.rb +15 -21
  303. data/lib/rigor/type/tuple.rb +14 -19
  304. data/lib/rigor/type/union.rb +30 -42
  305. data/lib/rigor/type_node/generic.rb +14 -26
  306. data/lib/rigor/type_node/identifier.rb +12 -19
  307. data/lib/rigor/type_node.rb +3 -12
  308. data/lib/rigor/value_semantics.rb +16 -21
  309. data/lib/rigor/version.rb +1 -1
  310. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +18 -30
  311. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +16 -29
  312. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +12 -23
  313. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +22 -39
  314. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +26 -46
  315. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +51 -87
  316. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +10 -17
  317. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +26 -39
  318. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +118 -176
  319. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +30 -51
  320. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +57 -92
  321. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +71 -108
  322. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +13 -22
  323. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +15 -25
  324. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +8 -13
  325. data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +16 -24
  326. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +30 -47
  327. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +79 -129
  328. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +36 -57
  329. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +27 -41
  330. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +16 -24
  331. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +148 -235
  332. data/plugins/rigor-activerecord/lib/rigor-activerecord.rb +3 -5
  333. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +8 -14
  334. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +9 -15
  335. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +4 -7
  336. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +23 -41
  337. data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +3 -5
  338. data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +6 -10
  339. data/plugins/rigor-activesupport-core-ext/lib/rigor-activesupport-core-ext.rb +8 -11
  340. data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +30 -45
  341. data/plugins/rigor-devise/lib/rigor-devise.rb +3 -5
  342. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +43 -69
  343. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +26 -35
  344. data/plugins/rigor-dry-schema/lib/rigor-dry-schema.rb +3 -5
  345. data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +30 -47
  346. data/plugins/rigor-dry-struct/lib/rigor-dry-struct.rb +3 -5
  347. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +67 -113
  348. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +29 -46
  349. data/plugins/rigor-dry-types/lib/rigor-dry-types.rb +3 -5
  350. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -20
  351. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +14 -23
  352. data/plugins/rigor-dry-validation/lib/rigor-dry-validation.rb +2 -3
  353. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +22 -37
  354. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +28 -46
  355. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +13 -17
  356. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +30 -47
  357. data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +52 -80
  358. data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +21 -31
  359. data/plugins/rigor-graphql/lib/rigor-graphql.rb +3 -5
  360. data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +11 -17
  361. data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +20 -34
  362. data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +45 -75
  363. data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +22 -36
  364. data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +22 -41
  365. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +17 -32
  366. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +6 -12
  367. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +4 -8
  368. data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +17 -32
  369. data/plugins/rigor-rails/lib/rigor-rails.rb +11 -18
  370. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +58 -92
  371. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +20 -34
  372. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +20 -31
  373. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +49 -82
  374. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +55 -92
  375. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +51 -90
  376. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +17 -30
  377. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +38 -70
  378. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +42 -74
  379. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +280 -497
  380. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +54 -89
  381. data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +32 -54
  382. data/plugins/rigor-rbs-inline/lib/rigor-rbs-inline.rb +8 -13
  383. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +9 -16
  384. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +24 -39
  385. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +13 -22
  386. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +34 -56
  387. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/scope_walker.rb +22 -42
  388. data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +43 -75
  389. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +27 -39
  390. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/http_status_codes.rb +14 -19
  391. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +20 -34
  392. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +28 -47
  393. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +21 -37
  394. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +13 -22
  395. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +18 -31
  396. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +6 -10
  397. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +14 -29
  398. data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +23 -41
  399. data/plugins/rigor-sinatra/lib/rigor-sinatra.rb +3 -5
  400. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +23 -38
  401. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +57 -96
  402. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +22 -35
  403. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +41 -69
  404. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb +6 -10
  405. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +24 -41
  406. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +29 -50
  407. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +55 -88
  408. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +159 -262
  409. data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +21 -29
  410. data/plugins/rigor-statesman/lib/rigor-statesman.rb +3 -5
  411. data/plugins/rigor-typescript-utility-types/lib/rigor/plugin/typescript_utility_types.rb +23 -37
  412. data/plugins/rigor-typescript-utility-types/lib/rigor-typescript-utility-types.rb +4 -6
  413. data/sig/rigor/scope.rbs +6 -0
  414. metadata +2 -1
@@ -5,92 +5,69 @@ require_relative "method_catalog"
5
5
  module Rigor
6
6
  module Inference
7
7
  module Builtins
8
- # `Proc` / `Method` / `UnboundMethod` catalog. Singleton —
9
- # load once, consult during dispatch.
8
+ # `Proc` / `Method` / `UnboundMethod` catalog. Singleton — load once, consult during dispatch.
10
9
  #
11
- # The three callable carriers are imported together because
12
- # `Init_Proc` registers them in a single C init block. They
13
- # share the same fundamental hazard at the catalog tier:
14
- # most of their public methods invoke the wrapped Ruby code
15
- # (the proc body, the bound method's receiver, …) and that
16
- # code can do anything read mutable state, call I/O, return
17
- # different values on successive calls. The static C-body
18
- # classifier marks these `:leaf` because the C functions
19
- # themselves do not call `rb_funcall*` / `rb_yield` directly
20
- # (they delegate through the VM's optimised call paths and
21
- # method-entry table), but folding any of them at compile
22
- # time would freeze a value the runtime never actually
23
- # produces twice.
10
+ # The three callable carriers are imported together because `Init_Proc` registers them in a single
11
+ # C init block. They share the same fundamental hazard at the catalog tier: most of their public
12
+ # methods invoke the wrapped Ruby code (the proc body, the bound method's receiver, …) and that code
13
+ # can do anything read mutable state, call I/O, return different values on successive calls. The
14
+ # static C-body classifier marks these `:leaf` because the C functions themselves do not call
15
+ # `rb_funcall*` / `rb_yield` directly (they delegate through the VM's optimised call paths and
16
+ # method-entry table), but folding any of them at compile time would freeze a value the runtime
17
+ # never actually produces twice.
24
18
  #
25
- # The blocklist below errs aggressively on the side of
26
- # caution: a hypothetical future `Constant<Proc>` /
27
- # `Constant<Method>` / `Constant<UnboundMethod>` carrier
28
- # would have very little to gain from these folds and a
29
- # great deal to lose if user code ran behind the analyzer's
30
- # back. Reflective readers (`#arity`, `#parameters`,
31
- # `#source_location`, `#name`, `#owner`, `#receiver`) remain
32
- # foldable; the RBS tier still resolves return types for
33
- # the blocklisted methods so callers do not lose precision.
19
+ # The blocklist below errs aggressively on the side of caution: a hypothetical future
20
+ # `Constant<Proc>` / `Constant<Method>` / `Constant<UnboundMethod>` carrier would have very little
21
+ # to gain from these folds and a great deal to lose if user code ran behind the analyzer's back.
22
+ # Reflective readers (`#arity`, `#parameters`, `#source_location`, `#name`, `#owner`, `#receiver`)
23
+ # remain foldable; the RBS tier still resolves return types for the blocklisted methods so callers
24
+ # do not lose precision.
34
25
  PROC_CATALOG = MethodCatalog.for_topic(
35
26
  "proc",
36
27
  mutating_selectors: {
37
28
  "Proc" => Set[
38
- # `#call` / `#[]` / `#===` / `#yield` invoke the proc
39
- # body. The C body routes through
40
- # `OPTIMIZED_METHOD_TYPE_CALL` (a VM fast path the
41
- # classifier cannot see into); the proc body can do
42
- # anything — read globals, mutate captured locals,
43
- # raise. MUST decline to fold.
29
+ # `#call` / `#[]` / `#===` / `#yield` invoke the proc body. The C body routes through
30
+ # `OPTIMIZED_METHOD_TYPE_CALL` (a VM fast path the classifier cannot see into); the proc body
31
+ # can do anything read globals, mutate captured locals, raise. MUST decline to fold.
44
32
  :call,
45
33
  :[],
46
34
  :===,
47
35
  :yield,
48
- # `#curry` / `#<<` / `#>>` allocate a fresh `Proc`
49
- # that closes over the receiver (and, for `<<` /
50
- # `>>`, over the argument). Folding would freeze a
51
- # specific `Proc` instance whose identity the runtime
52
- # never actually produces (object_id differs every
53
- # call), so the catalog tier declines.
36
+ # `#curry` / `#<<` / `#>>` allocate a fresh `Proc` that closes over the receiver (and, for
37
+ # `<<` / `>>`, over the argument). Folding would freeze a specific `Proc` instance whose
38
+ # identity the runtime never actually produces (object_id differs every call), so the catalog
39
+ # tier declines.
54
40
  :curry,
55
41
  :<<,
56
42
  :>>,
57
- # `#to_proc` returns `self` for `Proc` (cheap), but
58
- # blocking it keeps the rule shape uniform across the
59
- # three callable carriers (Method#to_proc allocates a
60
- # fresh `Proc`).
43
+ # `#to_proc` returns `self` for `Proc` (cheap), but blocking it keeps the rule shape uniform
44
+ # across the three callable carriers (Method#to_proc allocates a fresh `Proc`).
61
45
  :to_proc,
62
- # Identity-based equality and hashing: `#hash` is
63
- # derived from the underlying ISeq pointer; `#==` /
64
- # `#eql?` compare ISeq + binding. Folding to a
65
- # `Constant<Integer>` / `Constant<bool>` would freeze
66
- # an answer that depends on memory layout. Defensive.
46
+ # Identity-based equality and hashing: `#hash` is derived from the underlying ISeq pointer;
47
+ # `#==` / `#eql?` compare ISeq + binding. Folding to a `Constant<Integer>` / `Constant<bool>`
48
+ # would freeze an answer that depends on memory layout. Defensive.
67
49
  :hash,
68
50
  :==,
69
51
  :eql?,
70
- # `initialize_copy` is blocklisted by convention so a
71
- # hypothetical future `Constant<Proc>` carrier cannot
72
- # fold an aliasing copy through the catalog.
52
+ # `initialize_copy` is blocklisted by convention so a hypothetical future `Constant<Proc>`
53
+ # carrier cannot fold an aliasing copy through the catalog.
73
54
  :initialize_copy
74
55
  ],
75
56
  "Method" => Set[
76
- # `#call` / `#[]` / `#===` invoke the bound method.
77
- # Same hazard as `Proc#call`: arbitrary user code,
78
- # arbitrary side effects.
57
+ # `#call` / `#[]` / `#===` invoke the bound method. Same hazard as `Proc#call`: arbitrary user
58
+ # code, arbitrary side effects.
79
59
  :call,
80
60
  :[],
81
61
  :===,
82
- # `#curry` / `#<<` / `#>>` allocate a fresh `Proc`
83
- # that closes over the bound method.
62
+ # `#curry` / `#<<` / `#>>` allocate a fresh `Proc` that closes over the bound method.
84
63
  :curry,
85
64
  :<<,
86
65
  :>>,
87
- # `#to_proc` allocates a fresh `Proc` wrapping the
88
- # bound method folding would freeze its object_id.
89
- # The classifier already marks it `:block_dependent`,
90
- # but the explicit entry keeps the intent obvious.
66
+ # `#to_proc` allocates a fresh `Proc` wrapping the bound method — folding would freeze its
67
+ # object_id. The classifier already marks it `:block_dependent`, but the explicit entry keeps
68
+ # the intent obvious.
91
69
  :to_proc,
92
- # `#unbind` allocates a fresh `UnboundMethod` whose
93
- # identity differs every call.
70
+ # `#unbind` allocates a fresh `UnboundMethod` whose identity differs every call.
94
71
  :unbind,
95
72
  # Identity-based equality and hashing.
96
73
  :hash,
@@ -100,9 +77,8 @@ module Rigor
100
77
  :initialize_copy
101
78
  ],
102
79
  "UnboundMethod" => Set[
103
- # `#bind` allocates a fresh `Method` whose object_id
104
- # differs every call; `#bind_call` invokes the bound
105
- # method (already classified `:block_dependent`).
80
+ # `#bind` allocates a fresh `Method` whose object_id differs every call; `#bind_call` invokes
81
+ # the bound method (already classified `:block_dependent`).
106
82
  :bind,
107
83
  :bind_call,
108
84
  # Identity-based equality and hashing.
@@ -5,47 +5,36 @@ require_relative "method_catalog"
5
5
  module Rigor
6
6
  module Inference
7
7
  module Builtins
8
- # `Random` catalog. Singleton — load once, consult during
9
- # dispatch.
8
+ # `Random` catalog. Singleton — load once, consult during dispatch.
10
9
  #
11
- # The static classifier marks most Random methods `:leaf`
12
- # because their C bodies do not call `rb_funcall*` /
13
- # `rb_yield` / `rb_check_frozen` directly. Random is the
14
- # canonical case where that heuristic under-counts: every
15
- # call to `#rand` / `#bytes` / `Random.rand` / `Random.bytes`
16
- # advances the receiver's Mersenne-Twister state through a
17
- # helper (`rand_random` -> `random_real` / `random_ulong_limited`),
18
- # so folding any of them statically is unsound.
19
- # `Random.new_seed` and `Random.urandom` are non-deterministic
20
- # (different output every call); even though they are
21
- # functionally pure they would produce a misleading constant
22
- # at fold time. The whole class is conservative-by-default
23
- # at the catalog tier; precision flows through the RBS layer.
10
+ # The static classifier marks most Random methods `:leaf` because their C bodies do not call
11
+ # `rb_funcall*` / `rb_yield` / `rb_check_frozen` directly. Random is the canonical case where that
12
+ # heuristic under-counts: every call to `#rand` / `#bytes` / `Random.rand` / `Random.bytes` advances
13
+ # the receiver's Mersenne-Twister state through a helper (`rand_random` -> `random_real` /
14
+ # `random_ulong_limited`), so folding any of them statically is unsound. `Random.new_seed` and
15
+ # `Random.urandom` are non-deterministic (different output every call); even though they are
16
+ # functionally pure they would produce a misleading constant at fold time. The whole class is
17
+ # conservative-by-default at the catalog tier; precision flows through the RBS layer.
24
18
  RANDOM_CATALOG = MethodCatalog.for_topic(
25
19
  "random",
26
20
  mutating_selectors: {
27
21
  "Random" => Set[
28
- # `rand_random` -> `random_real` / `random_ulong_limited`
29
- # advance the MT state on the receiver (instance #rand)
30
- # and on `Random::DEFAULT` (singleton .rand). The
31
- # classifier misses the indirect mutator.
22
+ # `rand_random` -> `random_real` / `random_ulong_limited` advance the MT state on the receiver
23
+ # (instance #rand) and on `Random::DEFAULT` (singleton .rand). The classifier misses the
24
+ # indirect mutator.
32
25
  :rand,
33
- # `random_bytes` / `random_s_bytes` consume MT output
34
- # the same way #rand does — every call mutates the
35
- # underlying generator.
26
+ # `random_bytes` / `random_s_bytes` consume MT output the same way #rand does — every call
27
+ # mutates the underlying generator.
36
28
  :bytes,
37
- # Non-deterministic: each call produces a fresh seed
38
- # via `with_random_seed` reading platform entropy. Folding
39
- # to a constant would freeze a value that the runtime
40
- # never actually returns twice.
29
+ # Non-deterministic: each call produces a fresh seed via `with_random_seed` reading platform
30
+ # entropy. Folding to a constant would freeze a value that the runtime never actually returns
31
+ # twice.
41
32
  :new_seed,
42
- # Non-deterministic: reads from platform CSPRNG (e.g.
43
- # /dev/urandom). Folding is unsound for the same reason
44
- # as `new_seed`.
33
+ # Non-deterministic: reads from platform CSPRNG (e.g. /dev/urandom). Folding is unsound for
34
+ # the same reason as `new_seed`.
45
35
  :urandom,
46
- # `initialize_copy` is blocklisted by convention so a
47
- # hypothetical future `Constant<Random>` carrier
48
- # cannot fold an aliasing copy through the catalog.
36
+ # `initialize_copy` is blocklisted by convention so a hypothetical future `Constant<Random>`
37
+ # carrier cannot fold an aliasing copy through the catalog.
49
38
  :initialize_copy
50
39
  ]
51
40
  }
@@ -5,35 +5,26 @@ require_relative "method_catalog"
5
5
  module Rigor
6
6
  module Inference
7
7
  module Builtins
8
- # `Range` catalog. Singleton — load once, consult during
9
- # dispatch.
8
+ # `Range` catalog. Singleton — load once, consult during dispatch.
10
9
  #
11
- # Range is largely immutable: `begin`, `end`, and `excl` are
12
- # set at construction by `range_initialize` and never mutated
13
- # afterwards. The blocklist below therefore stays small. The
14
- # entries we DO need are the iteration methods whose C body
15
- # routes through a helper the block/yield regex does not
16
- # recognise, so the classifier mis-flags them as `:leaf`
17
- # despite yielding to a block.
10
+ # Range is largely immutable: `begin`, `end`, and `excl` are set at construction by
11
+ # `range_initialize` and never mutated afterwards. The blocklist below therefore stays small. The
12
+ # entries we DO need are the iteration methods whose C body routes through a helper the block/yield
13
+ # regex does not recognise, so the classifier mis-flags them as `:leaf` despite yielding to a block.
18
14
  RANGE_CATALOG = MethodCatalog.for_topic(
19
15
  "range",
20
16
  mutating_selectors: {
21
17
  "Range" => Set[
22
- # `range_initialize` / `range_initialize_copy` write
23
- # `begin`/`end`/`excl` slots on the receiver; classed
24
- # `:leaf` because the writes go through the struct
25
- # accessor not `rb_check_frozen`. Blocked for symmetry
26
- # with String / Array.
18
+ # `range_initialize` / `range_initialize_copy` write `begin`/`end`/`excl` slots on the
19
+ # receiver; classed `:leaf` because the writes go through the struct accessor not
20
+ # `rb_check_frozen`. Blocked for symmetry with String / Array.
27
21
  :initialize, :initialize_copy,
28
- # `range_reverse_each` yields to its block via
29
- # `range_each_func` -> caller's block; the regex
22
+ # `range_reverse_each` yields to its block via `range_each_func` -> caller's block; the regex
30
23
  # classifier follows direct `rb_yield*` calls only.
31
24
  :reverse_each,
32
- # `range_percent_step` returns an Enumerator unless a
33
- # block is supplied, in which case it yields. Treated
34
- # as block-dependent so the fold tier never invokes it
35
- # against a literal Range and tries to materialise an
36
- # Enumerator into a Constant.
25
+ # `range_percent_step` returns an Enumerator unless a block is supplied, in which case it
26
+ # yields. Treated as block-dependent so the fold tier never invokes it against a literal Range
27
+ # and tries to materialise an Enumerator into a Constant.
37
28
  :%
38
29
  ]
39
30
  }
@@ -5,23 +5,17 @@ require_relative "method_catalog"
5
5
  module Rigor
6
6
  module Inference
7
7
  module Builtins
8
- # `Rational` catalog. Singleton — load once, consult during
9
- # dispatch.
8
+ # `Rational` catalog. Singleton — load once, consult during dispatch.
10
9
  #
11
- # Rational is fully immutable: numerator / denominator slots
12
- # are written once during `nurat_s_new_internal` and the C
13
- # body never reaches for `rb_check_frozen`. Every catalog
14
- # entry classifies cleanly (`:leaf`, `:leaf_when_numeric`,
15
- # or `:dispatch` for the two methods that delegate into
16
- # user-redefinable `==` / `Float()` — `nurat_eqeq_p` and
17
- # `nurat_fdiv`). Bang-suffixed mutators do not exist on
18
- # Rational.
10
+ # Rational is fully immutable: numerator / denominator slots are written once during
11
+ # `nurat_s_new_internal` and the C body never reaches for `rb_check_frozen`. Every catalog entry
12
+ # classifies cleanly (`:leaf`, `:leaf_when_numeric`, or `:dispatch` for the two methods that
13
+ # delegate into user-redefinable `==` / `Float()` — `nurat_eqeq_p` and `nurat_fdiv`). Bang-suffixed
14
+ # mutators do not exist on Rational.
19
15
  #
20
- # The blocklist therefore stays minimal. `initialize_copy`
21
- # is added defensively (mirrors Range / Set) so a
22
- # hypothetical future `Constant<Rational>` carrier cannot
23
- # fold an aliasing copy through the catalog and surface a
24
- # shared mutable handle.
16
+ # The blocklist therefore stays minimal. `initialize_copy` is added defensively (mirrors Range /
17
+ # Set) so a hypothetical future `Constant<Rational>` carrier cannot fold an aliasing copy through
18
+ # the catalog and surface a shared mutable handle.
25
19
  RATIONAL_CATALOG = MethodCatalog.for_topic(
26
20
  "rational",
27
21
  mutating_selectors: {
@@ -5,70 +5,51 @@ require_relative "method_catalog"
5
5
  module Rigor
6
6
  module Inference
7
7
  module Builtins
8
- # `Regexp` / `MatchData` catalog. Singleton — load once,
9
- # consult during dispatch.
8
+ # `Regexp` / `MatchData` catalog. Singleton — load once, consult during dispatch.
10
9
  #
11
- # `Init_Regexp` in `references/ruby/re.c` registers BOTH
12
- # classes in a single C init block, so the catalog carries
13
- # both `Regexp` (the pattern carrier) plus `MatchData`
14
- # (the result-of-match carrier produced by `Regexp#match` /
15
- # `String#match` and consulted via `$~`). The catalog wiring
10
+ # `Init_Regexp` in `references/ruby/re.c` registers BOTH classes in a single C init block, so the
11
+ # catalog carries both `Regexp` (the pattern carrier) plus `MatchData` (the result-of-match
12
+ # carrier produced by `Regexp#match` / `String#match` and consulted via `$~`). The catalog wiring
16
13
  # therefore mostly governs:
17
14
  #
18
- # 1. The reader surface on each class (`Regexp#source`,
19
- # `Regexp#options`, `Regexp#casefold?`, `MatchData#size`,
20
- # `MatchData#captures`, etc.) — RBS-declared returns are
21
- # preserved through dispatch.
22
- # 2. The blocklist below, which keeps methods that touch
23
- # process-global state (the `$~` backref) from being
24
- # folded. Regexp matching is observably stateful:
25
- # `Regexp#=~`, `#===` and `#~` all call `rb_backref_set`
26
- # (writing `$~` and the `$1..$N` / `$&` / `` $` `` / `$'`
27
- # aliases). A constant-fold that dropped those calls
28
- # would silently change the visible state of the program,
15
+ # 1. The reader surface on each class (`Regexp#source`, `Regexp#options`, `Regexp#casefold?`,
16
+ # `MatchData#size`, `MatchData#captures`, etc.) — RBS-declared returns are preserved through
17
+ # dispatch.
18
+ # 2. The blocklist below, which keeps methods that touch process-global state (the `$~` backref)
19
+ # from being folded. Regexp matching is observably stateful: `Regexp#=~`, `#===` and `#~` all
20
+ # call `rb_backref_set` (writing `$~` and the `$1..$N` / `$&` / `` $` `` / `$'` aliases). A
21
+ # constant-fold that dropped those calls would silently change the visible state of the program,
29
22
  # so they MUST decline through to the RBS tier.
30
23
  #
31
- # `Regexp.last_match` and `Regexp.timeout` / `Regexp.timeout=`
32
- # are class-level (singleton) methods that also touch
33
- # process-global state, but the dispatcher's catalog lookup
34
- # only consults `:instance` entries todayclass-method calls
35
- # on a `Singleton` receiver type take the `meta_*` path in
36
- # `MethodDispatcher` rather than walking `CATALOG_BY_CLASS`
37
- # so listing them here would be dead code. Their RBS-tier
38
- # signatures already widen the answer enough to keep the
39
- # behaviour sound; revisit if the dispatcher ever grows a
40
- # singleton-aware catalog path.
24
+ # `Regexp.last_match` and `Regexp.timeout` / `Regexp.timeout=` are class-level (singleton) methods
25
+ # that also touch process-global state, but the dispatcher's catalog lookup only consults
26
+ # `:instance` entries today — class-method calls on a `Singleton` receiver type take the `meta_*`
27
+ # path in `MethodDispatcher` rather than walking `CATALOG_BY_CLASS` so listing them here would be
28
+ # dead code. Their RBS-tier signatures already widen the answer enough to keep the behaviour sound;
29
+ # revisit if the dispatcher ever grows a singleton-aware catalog path.
41
30
  REGEXP_CATALOG = MethodCatalog.for_topic(
42
31
  "re",
43
32
  mutating_selectors: {
44
33
  "Regexp" => Set[
45
- # Defensive: aliasing-copy semantics already covered
46
- # by the `:mutates_self` classifier, listed here for
47
- # symmetry with String / Array / Hash / Range / Set.
34
+ # Defensive: aliasing-copy semantics already covered by the `:mutates_self` classifier,
35
+ # listed here for symmetry with String / Array / Hash / Range / Set.
48
36
  :initialize_copy,
49
- # `=~`, `===`, `~` all run `rb_reg_search` (or call
50
- # `rb_backref_set(Qnil)` directly) every successful
51
- # OR failing match writes `$~` and the
52
- # `$1..$N` / `$&` / `` $` `` / `$'` aliases. Folding
53
- # would discard the visible side effect.
37
+ # `=~`, `===`, `~` all run `rb_reg_search` (or call `rb_backref_set(Qnil)` directly) — every
38
+ # successful OR failing match writes `$~` and the `$1..$N` / `$&` / `` $` `` / `$'` aliases.
39
+ # Folding would discard the visible side effect.
54
40
  :=~,
55
41
  :"===",
56
42
  :~,
57
- # `match` is already `:block_dependent` (the C body
58
- # yields), but it ALSO writes `$~` regardless of the
59
- # block. Listed here so a future extractor that
60
- # reclassifies it as `:leaf` (because the yield is
61
- # behind a helper) does not silently fold it.
43
+ # `match` is already `:block_dependent` (the C body yields), but it ALSO writes `$~`
44
+ # regardless of the block. Listed here so a future extractor that reclassifies it as `:leaf`
45
+ # (because the yield is behind a helper) does not silently fold it.
62
46
  :match
63
47
  ],
64
48
  "MatchData" => Set[
65
- # Defensive entry mirroring the other catalogs.
66
- # `match_init_copy` is already `:leaf` per the
67
- # extractor (it copies the regs slot in place but
68
- # uses no helper the C-body regex flags as a
69
- # mutator); blocked so a future
70
- # `Constant<MatchData>` carrier never folds an
71
- # aliasing copy through the catalog.
49
+ # Defensive entry mirroring the other catalogs. `match_init_copy` is already `:leaf` per the
50
+ # extractor (it copies the regs slot in place but uses no helper the C-body regex flags as a
51
+ # mutator); blocked so a future `Constant<MatchData>` carrier never folds an aliasing copy
52
+ # through the catalog.
72
53
  :initialize_copy
73
54
  ]
74
55
  }
@@ -7,41 +7,32 @@ module Rigor
7
7
  module Builtins
8
8
  # `Set` catalog. Singleton — load once, consult during dispatch.
9
9
  #
10
- # Set was rewritten in C and folded into CRuby for Ruby 3.2+;
11
- # the reference branch (`ruby_4_0`) ships the implementation in
12
- # `references/ruby/set.c` with `Init_Set` registering every
13
- # method directly. There is no `set.rb` prelude — the trailing
14
- # `rb_provide("set.rb")` makes `require "set"` a no-op against
15
- # the built-in.
10
+ # Set was rewritten in C and folded into CRuby for Ruby 3.2+; the reference branch (`ruby_4_0`)
11
+ # ships the implementation in `references/ruby/set.c` with `Init_Set` registering every method
12
+ # directly. There is no `set.rb` prelude — the trailing `rb_provide("set.rb")` makes `require "set"`
13
+ # a no-op against the built-in.
16
14
  #
17
- # The blocklist below catches the catalog `:leaf` entries the
18
- # C-body classifier mis-attributes. Set's iteration helpers
19
- # (`set_iter`, `RETURN_SIZED_ENUMERATOR`) and its identity-
20
- # mode and reset paths drive into helpers the regex classifier
21
- # does not yet recognise as block-yielding or mutating.
15
+ # The blocklist below catches the catalog `:leaf` entries the C-body classifier mis-attributes.
16
+ # Set's iteration helpers (`set_iter`, `RETURN_SIZED_ENUMERATOR`) and its identity-mode and reset
17
+ # paths drive into helpers the regex classifier does not yet recognise as block-yielding or
18
+ # mutating.
22
19
  SET_CATALOG = MethodCatalog.for_topic(
23
20
  "set",
24
21
  mutating_selectors: {
25
22
  "Set" => Set[
26
- # Indirect mutators classified `:leaf` because the C
27
- # classifier did not follow the helper functions:
23
+ # Indirect mutators classified `:leaf` because the C classifier did not follow the helper
24
+ # functions:
28
25
  #
29
- # - `initialize_copy` calls `set_copy` to overwrite the
30
- # receiver's table.
31
- # - `compare_by_identity` swaps the internal hash type
32
- # via `set_reset_table_with_type`.
33
- # - `reset` rebuilds the internal table to dedup after
34
- # element mutation.
26
+ # - `initialize_copy` calls `set_copy` to overwrite the receiver's table.
27
+ # - `compare_by_identity` swaps the internal hash type via `set_reset_table_with_type`.
28
+ # - `reset` rebuilds the internal table to dedup after element mutation.
35
29
  :initialize_copy, :compare_by_identity, :reset,
36
- # Block-dependent methods classified `:leaf` because the
37
- # C body uses `set_iter` / `RETURN_SIZED_ENUMERATOR`
38
- # rather than calling `rb_yield` directly:
30
+ # Block-dependent methods classified `:leaf` because the C body uses `set_iter` /
31
+ # `RETURN_SIZED_ENUMERATOR` rather than calling `rb_yield` directly:
39
32
  :each, :classify, :divide,
40
- # `disjoint?` delegates into `set_i_intersect`, which
41
- # for non-Set enumerables uses `rb_funcall(other,
42
- # :any?, ...)` that is user-redefinable dispatch the
43
- # classifier missed because the call site is in a
44
- # sibling function.
33
+ # `disjoint?` delegates into `set_i_intersect`, which for non-Set enumerables uses
34
+ # `rb_funcall(other, :any?, ...)` — that is user-redefinable dispatch the classifier missed
35
+ # because the call site is in a sibling function.
45
36
  :disjoint?
46
37
  ]
47
38
  }
@@ -5,16 +5,12 @@ require_relative "method_catalog"
5
5
  module Rigor
6
6
  module Inference
7
7
  module Builtins
8
- # `String` and `Symbol` catalog. Singleton — load once,
9
- # consult during dispatch.
8
+ # `String` and `Symbol` catalog. Singleton — load once, consult during dispatch.
10
9
  #
11
- # The blocklist below is the curated set of catalog `:leaf`
12
- # entries the C-body classifier mis-attributes (the body of
13
- # `rb_str_replace` calls `str_modifiable` / `str_discard`
14
- # which the regex-based classifier does not recognise as
15
- # mutation primitives). Adding to the blocklist is the
16
- # corrective surface for false positives until the
17
- # classifier learns the helper functions.
10
+ # The blocklist below is the curated set of catalog `:leaf` entries the C-body classifier
11
+ # mis-attributes (the body of `rb_str_replace` calls `str_modifiable` / `str_discard` which the
12
+ # regex-based classifier does not recognise as mutation primitives). Adding to the blocklist is the
13
+ # corrective surface for false positives until the classifier learns the helper functions.
18
14
  STRING_CATALOG = MethodCatalog.for_topic(
19
15
  "string",
20
16
  mutating_selectors: {
@@ -23,19 +19,16 @@ module Rigor
23
19
  :prepend, :force_encoding, :encode, :scrub, :unicode_normalize, :"[]=",
24
20
  :upto, :each_byte, :each_char, :each_codepoint,
25
21
  :each_grapheme_cluster, :each_line, :bytesplice,
26
- # `crypt` is not a mutator but is blocked from folding for the
27
- # same "do not bake a non-pure result into a Constant" reason:
28
- # `rb_str_crypt` delegates to the platform `crypt(3)`, whose
29
- # output (algorithm and digest) varies by libc / OS, so
30
- # `"x".crypt("ab")` is not deterministic across the platforms
31
- # an analyzed project may target. The catalog classifies it
32
- # `:leaf` from its C body; this entry overrides that.
22
+ # `crypt` is not a mutator but is blocked from folding for the same "do not bake a non-pure
23
+ # result into a Constant" reason: `rb_str_crypt` delegates to the platform `crypt(3)`, whose
24
+ # output (algorithm and digest) varies by libc / OS, so `"x".crypt("ab")` is not deterministic
25
+ # across the platforms an analyzed project may target. The catalog classifies it `:leaf` from
26
+ # its C body; this entry overrides that.
33
27
  :crypt
34
28
  ],
35
29
  "Symbol" => Set[
36
- # Symbol is immutable in Ruby; the classifier mis-flags
37
- # `inspect` because `rb_sym_inspect` builds a temporary
38
- # mutable buffer. Allow it.
30
+ # Symbol is immutable in Ruby; the classifier mis-flags `inspect` because `rb_sym_inspect`
31
+ # builds a temporary mutable buffer. Allow it.
39
32
  ]
40
33
  }
41
34
  )
@@ -5,44 +5,32 @@ require_relative "method_catalog"
5
5
  module Rigor
6
6
  module Inference
7
7
  module Builtins
8
- # `Struct` catalog. Singleton — load once, consult during
9
- # dispatch.
8
+ # `Struct` catalog. Singleton — load once, consult during dispatch.
10
9
  #
11
- # `Struct` is a meta-class: `Struct.new(*members)` returns a
12
- # fresh anonymous subclass never a `Struct` value. Today
13
- # Rigor never produces a `Constant<Struct>` carrier (a literal
14
- # struct instance), so the catalog is defensive: it documents
15
- # the shape and forbids unsafe folds in case a future tier
16
- # learns to lift literal struct instances into the value
17
- # lattice.
10
+ # `Struct` is a meta-class: `Struct.new(*members)` returns a fresh anonymous subclass — never a
11
+ # `Struct` value. Today Rigor never produces a `Constant<Struct>` carrier (a literal struct
12
+ # instance), so the catalog is defensive: it documents the shape and forbids unsafe folds in case a
13
+ # future tier learns to lift literal struct instances into the value lattice.
18
14
  #
19
- # Subclasses define their own writers (`name=`) at class-build
20
- # time, so per-instance member accessors do not appear in this
21
- # YAML only the generic `[]` / `[]=` pair on the base class.
22
- # `[]=` is already classified `:mutates_self`; `[]` reads a
23
- # member but the answer depends on the subclass's member
24
- # definition, which the catalog does not see, so we blocklist
25
- # it defensively.
15
+ # Subclasses define their own writers (`name=`) at class-build time, so per-instance member
16
+ # accessors do not appear in this YAML — only the generic `[]` / `[]=` pair on the base class. `[]=`
17
+ # is already classified `:mutates_self`; `[]` reads a member but the answer depends on the
18
+ # subclass's member definition, which the catalog does not see, so we blocklist it defensively.
26
19
  STRUCT_CATALOG = MethodCatalog.for_topic(
27
20
  "struct",
28
21
  mutating_selectors: {
29
22
  "Struct" => Set[
30
- # Defensive: aliasing-copy semantics on a hypothetical
31
- # `Constant<Struct>` carrier. Convention across the
32
- # other catalogs (Range, Random, Pathname).
23
+ # Defensive: aliasing-copy semantics on a hypothetical `Constant<Struct>` carrier. Convention
24
+ # across the other catalogs (Range, Random, Pathname).
33
25
  :initialize_copy,
34
- # `rb_struct_hash` mixes member values via
35
- # `rb_hash` -> `rb_funcall(:hash, ...)`. The classifier
36
- # sees no direct dispatch because the recursion goes
37
- # through `rb_hash` (a helper), but the answer depends
38
- # on the member values' `#hash` — user-redefinable.
39
- # Block to avoid folding a hash that would diverge
40
- # from the runtime once a member overrides `#hash`.
26
+ # `rb_struct_hash` mixes member values via `rb_hash` -> `rb_funcall(:hash, ...)`. The
27
+ # classifier sees no direct dispatch because the recursion goes through `rb_hash` (a helper),
28
+ # but the answer depends on the member values' `#hash` — user-redefinable. Block to avoid
29
+ # folding a hash that would diverge from the runtime once a member overrides `#hash`.
41
30
  :hash,
42
- # `rb_struct_aref` reads a member by name or index; the
43
- # answer depends on the subclass's member layout, which
44
- # the catalog does not carry. Folding without knowing
45
- # the layout would be unsound.
31
+ # `rb_struct_aref` reads a member by name or index; the answer depends on the subclass's
32
+ # member layout, which the catalog does not carry. Folding without knowing the layout would
33
+ # be unsound.
46
34
  :[]
47
35
  ]
48
36
  }