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
@@ -1,12 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # `Date` and `DateTime` live in CRuby's bundled `date` gem, which
4
- # is stdlib rather than core so the constants are not visible
5
- # until `date` is required. The dispatcher's `CATALOG_BY_CLASS`
6
- # table references `Date` and `DateTime` at load time, so requiring
7
- # the gem here (alongside the loader file that exports the catalog)
8
- # keeps the wiring self-contained: a consumer that pulls in the
9
- # constant-folding rule book gets the Date constants for free.
3
+ # `Date` and `DateTime` live in CRuby's bundled `date` gem, which is stdlib rather than core — so the
4
+ # constants are not visible until `date` is required. The dispatcher's `CATALOG_BY_CLASS` table
5
+ # references `Date` and `DateTime` at load time, so requiring the gem here (alongside the loader file
6
+ # that exports the catalog) keeps the wiring self-contained: a consumer that pulls in the constant-folding
7
+ # rule book gets the Date constants for free.
10
8
  require "date"
11
9
 
12
10
  require_relative "method_catalog"
@@ -14,78 +12,51 @@ require_relative "method_catalog"
14
12
  module Rigor
15
13
  module Inference
16
14
  module Builtins
17
- # `Date` / `DateTime` catalog. Singleton — load once, consult
18
- # during dispatch.
15
+ # `Date` / `DateTime` catalog. Singleton — load once, consult during dispatch.
19
16
  #
20
- # `Date` and `DateTime` both come from CRuby's bundled `date`
21
- # gem (`references/ruby/ext/date/date_core.c`). A single
22
- # `Init_date_core` function registers them, so the catalog
23
- # carries both classes `Date` plus the `DateTime` subclass
24
- # whose own Init block extends with `hour` / `min` /
25
- # `strftime` / `iso8601` etc. The Ruby-side prelude
26
- # (`lib/date.rb`) only contributes `Date#infinite?` and the
27
- # nested `Date::Infinity` class; the bulk of the surface is
28
- # in C.
17
+ # `Date` and `DateTime` both come from CRuby's bundled `date` gem (`references/ruby/ext/date/date_core.c`).
18
+ # A single `Init_date_core` function registers them, so the catalog carries both classes — `Date`
19
+ # plus the `DateTime` subclass whose own Init block extends with `hour` / `min` / `strftime` /
20
+ # `iso8601` etc. The Ruby-side prelude (`lib/date.rb`) only contributes `Date#infinite?` and the
21
+ # nested `Date::Infinity` class; the bulk of the surface is in C.
29
22
  #
30
- # Date / DateTime receivers are not lifted to a `Constant`
31
- # carrier today (there is no Date literal node the closest
32
- # is `Date.today` / `Date.parse(...)`, which produce
33
- # `Nominal[Date]`). The catalog wiring therefore mostly
34
- # governs:
23
+ # Date / DateTime receivers are not lifted to a `Constant` carrier today (there is no Date literal
24
+ # node the closest is `Date.today` / `Date.parse(...)`, which produce `Nominal[Date]`). The
25
+ # catalog wiring therefore mostly governs:
35
26
  #
36
- # 1. The Integer-typed reader surface (`#year`, `#month`,
37
- # `#day`, `#wday`, `#hour`, `#min`, `#sec`) — RBS-declared
38
- # `Integer` is preserved through dispatch.
39
- # 2. The blocklist below, which keeps mutator-style methods
40
- # that the C-body classifier already flagged
41
- # (`mutates_self`) from being missed by a future
42
- # `Constant<Date>` carrier, plus a defensive
43
- # `:initialize_copy` entry for symmetry with the other
44
- # catalogs.
27
+ # 1. The Integer-typed reader surface (`#year`, `#month`, `#day`, `#wday`, `#hour`, `#min`, `#sec`) —
28
+ # RBS-declared `Integer` is preserved through dispatch.
29
+ # 2. The blocklist below, which keeps mutator-style methods that the C-body classifier already
30
+ # flagged (`mutates_self`) from being missed by a future `Constant<Date>` carrier, plus a
31
+ # defensive `:initialize_copy` entry for symmetry with the other catalogs.
45
32
  #
46
- # The non-bang `#next_day` / `#prev_day` / `#next_month` /
47
- # `#prev_month` / `#next_year` / `#prev_year` / `#>>` / `#<<`
48
- # selectors all RETURN brand-new `Date` objects rather than
49
- # mutating the receiver they intentionally stay
50
- # catalog-eligible. The two real mutators
51
- # (`#initialize_copy`, `#marshal_load`) are already classified
52
- # `:mutates_self` by the C-body regex, so they fall out of
53
- # `MethodCatalog#safe_for_folding?` without an explicit
54
- # blocklist entry; the entries below are defense-in-depth
55
- # against indirect mutators the regex might miss in a future
56
- # CRuby bump.
33
+ # The non-bang `#next_day` / `#prev_day` / `#next_month` / `#prev_month` / `#next_year` /
34
+ # `#prev_year` / `#>>` / `#<<` selectors all RETURN brand-new `Date` objects rather than mutating the
35
+ # receiver they intentionally stay catalog-eligible. The two real mutators (`#initialize_copy`,
36
+ # `#marshal_load`) are already classified `:mutates_self` by the C-body regex, so they fall out of
37
+ # `MethodCatalog#safe_for_folding?` without an explicit blocklist entry; the entries below are
38
+ # defense-in-depth against indirect mutators the regex might miss in a future CRuby bump.
57
39
  DATE_CATALOG = MethodCatalog.for_topic(
58
40
  "date",
59
41
  mutating_selectors: {
60
42
  "Date" => Set[
61
- # `d_lite_initialize_copy` is already classed
62
- # `:mutates_self` by the regex (it calls
63
- # `rb_check_frozen` and rewrites the receiver's
64
- # internal `dat` slots). Listed here for symmetry with
65
- # String / Array / Range / Set / Time and to keep the
66
- # blocklist self-documenting.
43
+ # `d_lite_initialize_copy` is already classed `:mutates_self` by the regex (it calls
44
+ # `rb_check_frozen` and rewrites the receiver's internal `dat` slots). Listed here for
45
+ # symmetry with String / Array / Range / Set / Time and to keep the blocklist
46
+ # self-documenting.
67
47
  :initialize_copy,
68
- # `d_lite_fill` is a `#ifndef NDEBUG` debug method that
69
- # warms the receiver's cached `simple` / `complex`
70
- # fields via the `get_s_*` / `get_c_*` macros. The
71
- # macros perform in-place writes on the receiver's
72
- # internal `dat` struct but use no helper the C-body
73
- # regex recognises, so the classifier mis-flags it
74
- # `:leaf`. Blocked so a future `Constant<Date>` carrier
75
- # never folds it.
48
+ # `d_lite_fill` is a `#ifndef NDEBUG` debug method that warms the receiver's cached `simple` /
49
+ # `complex` fields via the `get_s_*` / `get_c_*` macros. The macros perform in-place writes on
50
+ # the receiver's internal `dat` struct but use no helper the C-body regex recognises, so the
51
+ # classifier mis-flags it `:leaf`. Blocked so a future `Constant<Date>` carrier never folds it.
76
52
  :fill
77
53
  ],
78
54
  "DateTime" => Set[
79
- # `DateTime` inherits the bulk of its surface from
80
- # `Date`. The dedicated DateTime-side methods are all
81
- # readers (`hour`, `min`, …) plus formatting
82
- # converters (`strftime`, `iso8601`, ); none mutate
83
- # the receiver. The single defensive entry mirrors the
84
- # Date side so that the inherited
85
- # `Date#initialize_copy` (registered against
86
- # `cDateTime` through subclassing) cannot fold through
87
- # the catalog if a future `Constant<DateTime>` carrier
88
- # ever lands.
55
+ # `DateTime` inherits the bulk of its surface from `Date`. The dedicated DateTime-side methods
56
+ # are all readers (`hour`, `min`, …) plus formatting converters (`strftime`, `iso8601`, …);
57
+ # none mutate the receiver. The single defensive entry mirrors the Date side so that the
58
+ # inherited `Date#initialize_copy` (registered against `cDateTime` through subclassing) cannot
59
+ # fold through the catalog if a future `Constant<DateTime>` carrier ever lands.
89
60
  :initialize_copy
90
61
  ]
91
62
  }
@@ -5,55 +5,41 @@ require_relative "method_catalog"
5
5
  module Rigor
6
6
  module Inference
7
7
  module Builtins
8
- # `Encoding` catalog. Singleton — load once, consult during
9
- # dispatch.
8
+ # `Encoding` catalog. Singleton — load once, consult during dispatch.
10
9
  #
11
- # Encoding instances are deep-frozen value objects: once
12
- # registered, their `name` / `dummy?` / `ascii_compatible?`
13
- # slots never change and the C bodies for the per-instance
14
- # methods are pure. The C-body classifier therefore lands
15
- # every instance method as `:leaf` correctly.
10
+ # Encoding instances are deep-frozen value objects: once registered, their `name` / `dummy?` /
11
+ # `ascii_compatible?` slots never change and the C bodies for the per-instance methods are pure.
12
+ # The C-body classifier therefore lands every instance method as `:leaf` correctly.
16
13
  #
17
- # The blocklist focuses on the *singleton* surface where the
18
- # hidden state is the process-wide encoding registry. Every
19
- # method classified `:leaf` on the singleton actually reads
20
- # (or, for the setters, writes) a global, so a hypothetical
21
- # `Constant<Encoding>`-class receiver MUST NOT fold them
22
- # against the analyzer process's registry — what UTF-8's
23
- # alias list is in the analyzer is not necessarily what it
24
- # is in the analysed program.
14
+ # The blocklist focuses on the *singleton* surface where the hidden state is the process-wide
15
+ # encoding registry. Every method classified `:leaf` on the singleton actually reads (or, for the
16
+ # setters, writes) a global, so a hypothetical `Constant<Encoding>`-class receiver MUST NOT fold
17
+ # them against the analyzer process's registry what UTF-8's alias list is in the analyzer is not
18
+ # necessarily what it is in the analysed program.
25
19
  ENCODING_CATALOG = MethodCatalog.for_topic(
26
20
  "encoding",
27
21
  mutating_selectors: {
28
22
  "Encoding" => Set[
29
- # Defence-in-depth: mirrors range_catalog.rb /
30
- # complex_catalog.rb. Encoding does not currently
31
- # expose a public `initialize_copy` (Encoding objects
32
- # are deep-frozen and #dup is a no-op), but the
33
- # convention keeps the door closed against future
34
- # CRuby changes that would leak a copy-mutator.
23
+ # Defence-in-depth: mirrors range_catalog.rb / complex_catalog.rb. Encoding does not currently
24
+ # expose a public `initialize_copy` (Encoding objects are deep-frozen and #dup is a no-op),
25
+ # but the convention keeps the door closed against future CRuby changes that would leak a
26
+ # copy-mutator.
35
27
  :initialize_copy,
36
28
  :hash,
37
29
  :eql?,
38
- # `Encoding.find(name)` walks the global encoding
39
- # registry. Pure with respect to its argument but
40
- # the registry itself can drift (load-order, locale,
41
- # process-wide `default_external=` calls), so a
42
- # constant-fold would lock in the analyzer's view.
30
+ # `Encoding.find(name)` walks the global encoding registry. Pure with respect to its argument
31
+ # but the registry itself can drift (load-order, locale, process-wide `default_external=`
32
+ # calls), so a constant-fold would lock in the analyzer's view.
43
33
  :find,
44
- # `Encoding.list` / `Encoding.aliases` /
45
- # `Encoding.name_list` enumerate the same global
46
- # registry. Same reasoning as `find` — the values
47
- # are not guaranteed to match the analysed program's
48
- # registry.
34
+ # `Encoding.list` / `Encoding.aliases` / `Encoding.name_list` enumerate the same global
35
+ # registry. Same reasoning as `find` the values are not guaranteed to match the analysed
36
+ # program's registry.
49
37
  :list,
50
38
  :aliases,
51
39
  :name_list,
52
- # Global-default mutators. `MethodCatalog#blocked?`
53
- # only auto-blocks `!`-suffixed selectors, so we MUST
54
- # list these explicitly: each writes the process-wide
55
- # default-encoding slot read by `default_external` /
56
- # `default_internal`.
40
+ # Global-default mutators. `MethodCatalog#blocked?` only auto-blocks `!`-suffixed selectors,
41
+ # so we MUST list these explicitly: each writes the process-wide default-encoding slot read by
42
+ # `default_external` / `default_internal`.
57
43
  :default_external=,
58
44
  :default_internal=
59
45
  ]
@@ -7,12 +7,10 @@ module Rigor
7
7
  module Builtins
8
8
  # `Enumerable` module catalog. Singleton — load once.
9
9
  #
10
- # `Enumerable` is a Ruby module, not a class, so the
11
- # catalog is NOT routed through
12
- # `MethodDispatcher::ConstantFolding::CATALOG_BY_CLASS`
13
- # (which dispatches on the receiver's concrete class).
14
- # The data is wired into `MODULE_CATALOGS` in
15
- # `MethodDispatcher::ConstantFolding` (ancestor-chain lookup).
10
+ # `Enumerable` is a Ruby module, not a class, so the catalog is NOT routed through
11
+ # `MethodDispatcher::ConstantFolding::CATALOG_BY_CLASS` (which dispatches on the receiver's concrete
12
+ # class). The data is wired into `MODULE_CATALOGS` in `MethodDispatcher::ConstantFolding`
13
+ # (ancestor-chain lookup).
16
14
  ENUMERABLE_CATALOG = MethodCatalog.for_topic(
17
15
  "enumerable",
18
16
  mutating_selectors: {
@@ -5,80 +5,61 @@ require_relative "method_catalog"
5
5
  module Rigor
6
6
  module Inference
7
7
  module Builtins
8
- # `Exception` catalog. Singleton — load once, consult during
9
- # dispatch.
8
+ # `Exception` catalog. Singleton — load once, consult during dispatch.
10
9
  #
11
- # Exception is the base of every Ruby error class (RuntimeError,
12
- # StandardError, KeyError, …). The Init_Exception block in
13
- # `references/ruby/error.c` registers the entire hierarchy in
14
- # one pass, so the YAML carries 27 classes but only the base
15
- # `Exception` row is wired into `CATALOG_BY_CLASS` for v0.0.5.
16
- # A `RuntimeError` receiver hits the Exception arm via
17
- # `is_a?(Exception)` and the catalog answers with the base-class
18
- # entries; subclass-specific methods (`KeyError#receiver`,
19
- # `NameError#name`, …) intentionally miss the lookup until a
20
- # later slice routes per-subclass class_names.
10
+ # Exception is the base of every Ruby error class (RuntimeError, StandardError, KeyError, …). The
11
+ # Init_Exception block in `references/ruby/error.c` registers the entire hierarchy in one pass, so
12
+ # the YAML carries 27 classes — but only the base `Exception` row is wired into `CATALOG_BY_CLASS`
13
+ # for v0.0.5. A `RuntimeError` receiver hits the Exception arm via `is_a?(Exception)` and the
14
+ # catalog answers with the base-class entries; subclass-specific methods (`KeyError#receiver`,
15
+ # `NameError#name`, …) intentionally miss the lookup until a later slice routes per-subclass
16
+ # class_names.
21
17
  #
22
- # The catalog tier here is *defence in depth* — every base
23
- # method that could plausibly fold has been weighed against the
24
- # robustness principle (strict on returns) and either left
25
- # `:dispatch` / `:mutates_self` (in which case the catalog
26
- # already declines) or blocklisted because the static classifier
27
- # missed an indirect side effect. The remaining `:leaf` method
28
- # that DOES fold is `#cause`, a pure accessor.
18
+ # The catalog tier here is *defence in depth* — every base method that could plausibly fold has
19
+ # been weighed against the robustness principle (strict on returns) and either left `:dispatch` /
20
+ # `:mutates_self` (in which case the catalog already declines) or blocklisted because the static
21
+ # classifier missed an indirect side effect. The remaining `:leaf` method that DOES fold is
22
+ # `#cause`, a pure accessor.
29
23
  EXCEPTION_CATALOG = MethodCatalog.for_topic(
30
24
  "exception",
31
25
  mutating_selectors: {
32
26
  "Exception" => Set[
33
- # `exc_initialize` writes `mesg` / `backtrace` ivars on
34
- # self via `rb_ivar_set` the C-body classifier missed
35
- # the indirect mutator because the helpers are not in
36
- # its regex. Blocklisted so a hypothetical future
37
- # `Constant<Exception>` carrier cannot fold an aliasing
27
+ # `exc_initialize` writes `mesg` / `backtrace` ivars on self via `rb_ivar_set` — the C-body
28
+ # classifier missed the indirect mutator because the helpers are not in its regex.
29
+ # Blocklisted so a hypothetical future `Constant<Exception>` carrier cannot fold an aliasing
38
30
  # constructor through the catalog.
39
31
  :initialize,
40
- # `exc_exception` either returns self (no-arg) or calls
41
- # `rb_obj_clone` + `exc_initialize_internal` on the
42
- # clone the clone branch mutates fresh state through
43
- # the same indirect helpers as `:initialize`. Conservative
44
- # blocklist; the cost is one folded no-arg call.
32
+ # `exc_exception` either returns self (no-arg) or calls `rb_obj_clone` +
33
+ # `exc_initialize_internal` on the clone — the clone branch mutates fresh state through the
34
+ # same indirect helpers as `:initialize`. Conservative blocklist; the cost is one folded
35
+ # no-arg call.
45
36
  :exception,
46
- # `exc_detailed_message` formats with platform / locale
47
- # data (highlight markers depend on `$stderr.tty?` via
48
- # the keyword arg default and `rb_io_tty_p`). Folding
49
- # would freeze a value that depends on the calling
50
- # process's stderr state.
37
+ # `exc_detailed_message` formats with platform / locale data (highlight markers depend on
38
+ # `$stderr.tty?` via the keyword arg default and `rb_io_tty_p`). Folding would freeze a value
39
+ # that depends on the calling process's stderr state.
51
40
  :detailed_message,
52
- # `exc_backtrace` reads the captured frame list, which
53
- # depends on where the exception was raised context
54
- # the static fold tier cannot reproduce.
41
+ # `exc_backtrace` reads the captured frame list, which depends on where the exception was
42
+ # raised context the static fold tier cannot reproduce.
55
43
  :backtrace,
56
- # Same rationale as `:backtrace`; `Thread::Backtrace::Location`
57
- # objects are runtime artefacts.
44
+ # Same rationale as `:backtrace`; `Thread::Backtrace::Location` objects are runtime artefacts.
58
45
  :backtrace_locations,
59
- # `exc_set_backtrace` mutates the @backtrace ivar via
60
- # `rb_ivar_set` — another indirect mutator the classifier
61
- # missed.
46
+ # `exc_set_backtrace` mutates the @backtrace ivar via `rb_ivar_set` — another indirect
47
+ # mutator the classifier missed.
62
48
  :set_backtrace,
63
- # `initialize_copy` is blocklisted by convention so a
64
- # hypothetical future `Constant<Exception>` carrier
65
- # cannot fold an aliasing copy through the catalog.
49
+ # `initialize_copy` is blocklisted by convention so a hypothetical future
50
+ # `Constant<Exception>` carrier cannot fold an aliasing copy through the catalog.
66
51
  :initialize_copy,
67
- # Defensive entries for the universal mutation surface.
68
- # Object-identity hashing on a constant carrier is fine,
69
- # but `eql?` on Exception delegates to `==` (dispatch);
70
- # blocking both keeps the constant-fold tier honest.
52
+ # Defensive entries for the universal mutation surface. Object-identity hashing on a constant
53
+ # carrier is fine, but `eql?` on Exception delegates to `==` (dispatch); blocking both keeps
54
+ # the constant-fold tier honest.
71
55
  :hash,
72
56
  :eql?
73
57
  ],
74
- # `Exception.to_tty?` (singleton) calls
75
- # `rb_io_tty_p($stderr)`; its return depends on the
76
- # process's stderr state at runtime, never on compile-time
77
- # arguments. The catalog tier today only consults
78
- # `mutating_selectors` for instance-receiver dispatches via
79
- # `CATALOG_BY_CLASS`, so this row is documentation-grade —
80
- # it records the soundness rationale for any future slice
81
- # that wires the singleton path through the catalog.
58
+ # `Exception.to_tty?` (singleton) calls `rb_io_tty_p($stderr)`; its return depends on the
59
+ # process's stderr state at runtime, never on compile-time arguments. The catalog tier today
60
+ # only consults `mutating_selectors` for instance-receiver dispatches via `CATALOG_BY_CLASS`, so
61
+ # this row is documentation-grade it records the soundness rationale for any future slice that
62
+ # wires the singleton path through the catalog.
82
63
  "Exception.singleton" => Set[
83
64
  :to_tty?
84
65
  ]
@@ -7,27 +7,22 @@ module Rigor
7
7
  module Builtins
8
8
  # `Hash` catalog. Singleton — load once, consult during dispatch.
9
9
  #
10
- # Hash mirrors Array's mutation pattern: nearly every iteration
11
- # method yields through `rb_hash_foreach` plus a per-pair static
12
- # callback (`each_value_i`, `keep_if_i`, …), and the C-body
13
- # classifier does not follow into the callback so it lands as
14
- # `:leaf` despite being block-dependent. The blocklist below
15
- # captures every false-positive `:leaf` we have spotted in the
16
- # generated YAML — bias toward conservatism so a missed fold is
17
- # acceptable but a folded mutator/yielder is not.
10
+ # Hash mirrors Array's mutation pattern: nearly every iteration method yields through
11
+ # `rb_hash_foreach` plus a per-pair static callback (`each_value_i`, `keep_if_i`, …), and the C-body
12
+ # classifier does not follow into the callback so it lands as `:leaf` despite being block-dependent.
13
+ # The blocklist below captures every false-positive `:leaf` we have spotted in the generated YAML —
14
+ # bias toward conservatism so a missed fold is acceptable but a folded mutator/yielder is not.
18
15
  HASH_CATALOG = MethodCatalog.for_topic(
19
16
  "hash",
20
17
  mutating_selectors: {
21
18
  "Hash" => Set[
22
- # Block-dependent iteration — yields via `rb_hash_foreach`
23
- # plus a per-pair callback that the regex classifier does
24
- # not follow:
19
+ # Block-dependent iteration — yields via `rb_hash_foreach` plus a per-pair callback that the
20
+ # regex classifier does not follow:
25
21
  :each, :each_pair, :each_key, :each_value,
26
22
  :select, :filter, :reject,
27
23
  :transform_values,
28
- # Block-dependent merge — `rb_hash_merge` delegates into
29
- # `rb_hash_update`, which yields per conflict when a block
30
- # is given:
24
+ # Block-dependent merge — `rb_hash_merge` delegates into `rb_hash_update`, which yields per
25
+ # conflict when a block is given:
31
26
  :merge
32
27
  ]
33
28
  }
@@ -5,57 +5,44 @@ require "yaml"
5
5
  module Rigor
6
6
  module Inference
7
7
  module Builtins
8
- # Generic loader for offline-generated catalogs under
9
- # `data/builtins/ruby_core/<topic>.yml`. One instance per topic
10
- # (numeric, string, array, …); each owns the path to its own
11
- # YAML and the per-class blocklist of selectors the static
12
- # classifier marked `:leaf` but that actually mutate the
13
- # receiver (false positives the C-body heuristic does not
14
- # catch).
8
+ # Generic loader for offline-generated catalogs under `data/builtins/ruby_core/<topic>.yml`. One
9
+ # instance per topic (numeric, string, array, …); each owns the path to its own YAML and the
10
+ # per-class blocklist of selectors the static classifier marked `:leaf` but that actually mutate the
11
+ # receiver (false positives the C-body heuristic does not catch).
15
12
  #
16
- # `safe_for_folding?(class_name, selector, kind:)` returns true
17
- # when:
13
+ # `safe_for_folding?(class_name, selector, kind:)` returns true when:
18
14
  # 1. The catalog has an entry for `(class_name, selector, kind)`,
19
- # 2. The entry's `purity` is one of `leaf` / `trivial` /
20
- # `leaf_when_numeric`,
15
+ # 2. The entry's `purity` is one of `leaf` / `trivial` / `leaf_when_numeric`,
21
16
  # 3. The selector is NOT in the per-class mutation blocklist.
22
17
  #
23
- # Missing catalog files (e.g. in a bare gem install where data
24
- # was opted out) degrade to `false` so the dispatcher falls
25
- # back to its hand-rolled allow lists.
18
+ # Missing catalog files (e.g. in a bare gem install where data was opted out) degrade to `false` so
19
+ # the dispatcher falls back to its hand-rolled allow lists.
26
20
  class MethodCatalog
27
21
  FOLDABLE_PURITIES = Set["leaf", "trivial", "leaf_when_numeric"].freeze
28
22
  EMPTY_CATALOG = { "classes" => {} }.freeze
29
23
 
30
- # Selectors that are classified `:leaf` by the C-body analysis
31
- # (they read no global mutable state in the C sense) but whose
32
- # result is NOT reproducible across Ruby processes, so they must
33
- # never be folded into a `Constant`:
24
+ # Selectors that are classified `:leaf` by the C-body analysis (they read no global mutable state
25
+ # in the C sense) but whose result is NOT reproducible across Ruby processes, so they must never
26
+ # be folded into a `Constant`:
34
27
  #
35
- # - `hash` — every core `#hash` (`String`/`Symbol`/`Integer`/
36
- # `Float`/…) is salted with a per-process SipHash seed, so
37
- # `"x".hash` differs in every process. Folding bakes one
38
- # process's value into the type and the on-disk cache.
28
+ # - `hash` — every core `#hash` (`String`/`Symbol`/`Integer`/`Float`/…) is salted with a
29
+ # per-process SipHash seed, so `"x".hash` differs in every process. Folding bakes one process's
30
+ # value into the type and the on-disk cache.
39
31
  # - `object_id` / `__id__` — identity-allocated per process.
40
32
  #
41
- # This is a UNIVERSAL block (across every catalogued class)
42
- # because `hash` / `object_id` are `Object`-level and present on
43
- # every receiver; a per-class blocklist would silently miss a
44
- # class. The deterministic siblings (`inspect`, `to_s`) are
45
- # unaffected.
33
+ # This is a UNIVERSAL block (across every catalogued class) because `hash` / `object_id` are
34
+ # `Object`-level and present on every receiver; a per-class blocklist would silently miss a class.
35
+ # The deterministic siblings (`inspect`, `to_s`) are unaffected.
46
36
  NON_REPRODUCIBLE_SELECTORS = Set[:hash, :object_id, :__id__].freeze
47
37
 
48
- # Shared root for the offline-generated catalogues. Resolving it
49
- # here keeps the repo-relative `../../../../` hop in one place
50
- # instead of copying it into every per-topic loader.
38
+ # Shared root for the offline-generated catalogues. Resolving it here keeps the repo-relative
39
+ # `../../../../` hop in one place instead of copying it into every per-topic loader.
51
40
  DATA_ROOT = File.expand_path("../../../../data/builtins/ruby_core", __dir__)
52
41
  private_constant :DATA_ROOT
53
42
 
54
- # Build a catalog for a named topic, resolving its YAML path
55
- # under {DATA_ROOT}. Equivalent to `new(path: …)` for the common
56
- # case where the file is `<topic>.yml`; prefer this over passing
57
- # an explicit `File.expand_path` so the data-root hop stays
58
- # centralised.
43
+ # Build a catalog for a named topic, resolving its YAML path under {DATA_ROOT}. Equivalent to
44
+ # `new(path: …)` for the common case where the file is `<topic>.yml`; prefer this over passing an
45
+ # explicit `File.expand_path` so the data-root hop stays centralised.
59
46
  def self.for_topic(topic, mutating_selectors: {})
60
47
  new(path: File.join(DATA_ROOT, "#{topic}.yml"), mutating_selectors: mutating_selectors)
61
48
  end
@@ -63,14 +50,10 @@ module Rigor
63
50
  def initialize(path:, mutating_selectors: {})
64
51
  @path = path
65
52
  @mutating_selectors = mutating_selectors.transform_values(&:freeze).freeze
66
- # ADR-15 Phase 4b.x — eager-load so the instance is
67
- # safe to `Ractor.make_shareable`. Lazy init via
68
- # `@catalog ||= load_catalog` would write to a
69
- # potentially-frozen instance the first time a
70
- # worker Ractor consults the catalog, raising
71
- # `FrozenError`. The YAML parse is a once-per-process
72
- # cost and the catalogs are constructed at module
73
- # load time anyway, so eager init is free in
53
+ # ADR-15 Phase 4b.x — eager-load so the instance is safe to `Ractor.make_shareable`. Lazy init
54
+ # via `@catalog ||= load_catalog` would write to a potentially-frozen instance the first time a
55
+ # worker Ractor consults the catalog, raising `FrozenError`. The YAML parse is a once-per-process
56
+ # cost and the catalogs are constructed at module load time anyway, so eager init is free in
74
57
  # practice.
75
58
  @catalog = load_catalog
76
59
  end
@@ -117,11 +100,9 @@ module Rigor
117
100
  end
118
101
 
119
102
  def blocked?(class_name, selector)
120
- # Bang-suffixed selectors are mutating by Ruby convention
121
- # (`upcase!`, `concat`, etc. are listed explicitly below;
122
- # this catches the rest). We bias toward false negatives:
123
- # losing a fold opportunity is acceptable; folding a
124
- # mutator is not.
103
+ # Bang-suffixed selectors are mutating by Ruby convention (`upcase!`, `concat`, etc. are listed
104
+ # explicitly below; this catches the rest). We bias toward false negatives: losing a fold
105
+ # opportunity is acceptable; folding a mutator is not.
125
106
  selector_str = selector.to_s
126
107
  return true if selector_str.end_with?("!")
127
108
 
@@ -5,26 +5,21 @@ require_relative "method_catalog"
5
5
  module Rigor
6
6
  module Inference
7
7
  module Builtins
8
- # `Numeric` family catalog (Integer, Float, Rational, Complex,
9
- # Numeric). Singleton — load once, consult during dispatch.
8
+ # `Numeric` family catalog (Integer, Float, Rational, Complex, Numeric). Singleton — load once,
9
+ # consult during dispatch.
10
10
  #
11
- # The catalog is produced offline by `tool/extract_builtin_catalog.rb`
12
- # from the CRuby reference checkout under `references/ruby` plus the
13
- # RBS core signatures under `references/rbs`. The loader is the
14
- # runtime bridge: callers ask "is `Integer#+` safe to invoke during
15
- # constant folding?" and the answer comes straight from the offline
16
- # classification (`leaf` / `trivial` / `leaf_when_numeric` are
17
- # foldable; everything else is not).
11
+ # The catalog is produced offline by `tool/extract_builtin_catalog.rb` from the CRuby reference
12
+ # checkout under `references/ruby` plus the RBS core signatures under `references/rbs`. The loader
13
+ # is the runtime bridge: callers ask "is `Integer#+` safe to invoke during constant folding?" and
14
+ # the answer comes straight from the offline classification (`leaf` / `trivial` / `leaf_when_numeric`
15
+ # are foldable; everything else is not).
18
16
  #
19
- # No mutation blocklist is needed. The numeric classes expose no
20
- # foldable bang or indirect-mutator method that the static C
21
- # classifier mis-attributes (every `:leaf` numeric method is a pure
22
- # value computation), so the generic `MethodCatalog` loader shared
23
- # with the eighteen other per-class catalogs covers it directly.
24
- # This previously hand-rolled its own `safe_for_folding?` /
25
- # `method_entry` / `load_catalog` copy of `MethodCatalog`; folding
26
- # it onto the shared loader also picks up alias resolution (e.g.
27
- # `Integer#magnitude` → `abs`, `Integer#inspect` → `to_s`), which the
17
+ # No mutation blocklist is needed. The numeric classes expose no foldable bang or indirect-mutator
18
+ # method that the static C classifier mis-attributes (every `:leaf` numeric method is a pure value
19
+ # computation), so the generic `MethodCatalog` loader shared with the eighteen other per-class
20
+ # catalogs covers it directly. This previously hand-rolled its own `safe_for_folding?` /
21
+ # `method_entry` / `load_catalog` copy of `MethodCatalog`; folding it onto the shared loader also
22
+ # picks up alias resolution (e.g. `Integer#magnitude` → `abs`, `Integer#inspect` → `to_s`), which the
28
23
  # old bespoke loader silently dropped.
29
24
  NUMERIC_CATALOG = MethodCatalog.for_topic("numeric")
30
25
  end
@@ -5,24 +5,19 @@ require_relative "method_catalog"
5
5
  module Rigor
6
6
  module Inference
7
7
  module Builtins
8
- # `Pathname` catalog. Singleton — load once, consult during
9
- # dispatch.
8
+ # `Pathname` catalog. Singleton — load once, consult during dispatch.
10
9
  #
11
- # TODO(blocklist curation): read
12
- # `data/builtins/ruby_core/pathname.yml` and add per-method
13
- # blocklist entries for any `:leaf` classifications that are
14
- # actually mutators or otherwise unsafe to fold. Each entry
15
- # SHOULD carry a one-line comment naming the indirect mutator
16
- # helper that triggered the false positive (see
17
- # `string_catalog.rb`, `array_catalog.rb`, `time_catalog.rb`
18
- # for the canonical shape).
10
+ # TODO(blocklist curation): read `data/builtins/ruby_core/pathname.yml` and add per-method blocklist
11
+ # entries for any `:leaf` classifications that are actually mutators or otherwise unsafe to fold.
12
+ # Each entry SHOULD carry a one-line comment naming the indirect mutator helper that triggered the
13
+ # false positive (see `string_catalog.rb`, `array_catalog.rb`, `time_catalog.rb` for the canonical
14
+ # shape).
19
15
  PATHNAME_CATALOG = MethodCatalog.for_topic(
20
16
  "pathname",
21
17
  mutating_selectors: {
22
18
  "Pathname" => Set[
23
- # initialize_copy is blocklisted by convention so a
24
- # hypothetical future `Constant<Pathname>` carrier
25
- # cannot fold an aliasing copy through the catalog.
19
+ # initialize_copy is blocklisted by convention so a hypothetical future `Constant<Pathname>`
20
+ # carrier cannot fold an aliasing copy through the catalog.
26
21
  :initialize_copy
27
22
  ]
28
23
  }