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
@@ -9,65 +9,51 @@ module Rigor
9
9
  module MethodDispatcher
10
10
  # Symbol-form `reduce` / `inject` return-type tier.
11
11
  #
12
- # `IteratorDispatch.inject_block_params` deliberately declines the
13
- # Symbol-call shapes (`(1..n).reduce(1, :*)`, `[1,2,3].reduce(:+)`)
14
- # because they carry no block to bind parameters for the decline
15
- # of *block-param typing* is correct. What that decline leaves on
16
- # the floor is the *return type*: with no block and no precise tier,
17
- # the call falls to `Enumerable#reduce`'s RBS overload
18
- # `(untyped, Symbol) -> untyped`, so the whole fold widens to
19
- # `Dynamic[top]`.
12
+ # `IteratorDispatch.inject_block_params` deliberately declines the Symbol-call shapes
13
+ # (`(1..n).reduce(1, :*)`, `[1,2,3].reduce(:+)`) because they carry no block to bind parameters for —
14
+ # the decline of *block-param typing* is correct. What that decline leaves on the floor is the
15
+ # *return type*: with no block and no precise tier, the call falls to `Enumerable#reduce`'s RBS
16
+ # overload `(untyped, Symbol) -> untyped`, so the whole fold widens to `Dynamic[top]`.
20
17
  #
21
- # This tier recovers a precise return type for the Symbol-operand
22
- # forms by dispatching the named operator on the accumulated type:
18
+ # This tier recovers a precise return type for the Symbol-operand forms by dispatching the named
19
+ # operator on the accumulated type:
23
20
  #
24
- # - `(seed, :op)` (2-arg) — operand starts at the seed type `S`;
25
- # the result type is `dispatch(:op, widen(S) ∪ widen(E), widen(E))`
26
- # joined with the seed (the seed is returned unchanged when the
27
- # collection is empty). `E` is the receiver's element type.
28
- # - `(:op)` (1-arg) no seed: the first element seeds the memo, so
29
- # the operand type is `E` and the result is
30
- # `dispatch(:op, widen(E), widen(E))`. RBS models this overload as
31
- # `() { (E, E) -> E } -> E` (no nil), so the tier returns the
32
- # operator result without manufacturing a nil staying consistent
33
- # with the declared type and Rigor's false-positive discipline
34
- # (the empty-collection `nil` runtime case is not modelled by RBS
35
- # and adding it here would only pressure callers into defensive
36
- # nil-handling for code that works).
21
+ # - `(seed, :op)` (2-arg) — operand starts at the seed type `S`; the result type is
22
+ # `dispatch(:op, widen(S) ∪ widen(E), widen(E))` joined with the seed (the seed is returned
23
+ # unchanged when the collection is empty). `E` is the receiver's element type.
24
+ # - `(:op)` (1-arg) — no seed: the first element seeds the memo, so the operand type is `E` and the
25
+ # result is `dispatch(:op, widen(E), widen(E))`. RBS models this overload as
26
+ # `() { (E, E) -> E } -> E` (no nil), so the tier returns the operator result without manufacturing
27
+ # a nil staying consistent with the declared type and Rigor's false-positive discipline (the
28
+ # empty-collection `nil` runtime case is not modelled by RBS and adding it here would only pressure
29
+ # callers into defensive nil-handling for code that works).
37
30
  #
38
- # The tier is precision-additive: it declines (returns nil, today's
39
- # `Dynamic[top]` behaviour) for every shape it cannot prove —
40
- # unknown element type, Dynamic / Top receiver, a non-`Constant`
41
- # Symbol operand, or an operator the engine cannot dispatch on the
42
- # widened operand types.
31
+ # The tier is precision-additive: it declines (returns nil, today's `Dynamic[top]` behaviour) for
32
+ # every shape it cannot prove — unknown element type, Dynamic / Top receiver, a non-`Constant` Symbol
33
+ # operand, or an operator the engine cannot dispatch on the widened operand types.
43
34
  #
44
- # `widen_value_pinned` (ADR-55/56) collapses `Constant`/`IntegerRange`
45
- # operands to their nominal base before dispatch so the result is the
46
- # operator's nominal return (`Integer`) rather than a constant-folded
47
- # `Constant[120]` full constant folding of the reduction is out of
48
- # scope, the precision target is the carrier (`Integer`), not the value.
35
+ # `widen_value_pinned` (ADR-55/56) collapses `Constant`/`IntegerRange` operands to their nominal base
36
+ # before dispatch so the result is the operator's nominal return (`Integer`) rather than a
37
+ # constant-folded `Constant[120]` full constant folding of the reduction is out of scope, the
38
+ # precision target is the carrier (`Integer`), not the value.
49
39
  module ReduceFolding
50
40
  module_function
51
41
 
52
42
  REDUCE_METHODS = %i[reduce inject].freeze
53
43
  private_constant :REDUCE_METHODS
54
44
 
55
- # Allow-listed pure, side-effect-free fold operators. Each is
56
- # safe on the foldable constant operand classes (Integer / Float
57
- # / Rational); division / modulo by zero is caught by the rescue
58
- # harness in `execute_constant_reduce` and declines to the
59
- # nominal fold. `:gcd` / `:lcm` are valid binary Integer methods
60
- # (`acc.public_send(:gcd, elem)`); `:min` / `:max` are *not* (no
61
- # `Integer#min`/`#max` — they would raise and decline), so they
62
- # are deliberately omitted.
45
+ # Allow-listed pure, side-effect-free fold operators. Each is safe on the foldable constant operand
46
+ # classes (Integer / Float / Rational); division / modulo by zero is caught by the rescue harness
47
+ # in `execute_constant_reduce` and declines to the nominal fold. `:gcd` / `:lcm` are valid binary
48
+ # Integer methods (`acc.public_send(:gcd, elem)`); `:min` / `:max` are *not* (no
49
+ # `Integer#min`/`#max` they would raise and decline), so they are deliberately omitted.
63
50
  CONSTANT_FOLD_OPERATORS = %i[+ * - / % & | ^ gcd lcm].freeze
64
51
  private_constant :CONSTANT_FOLD_OPERATORS
65
52
 
66
- # Hard caps (ADR-41 WD4 style). The element count is checked
67
- # BEFORE the receiver is enumerated, so a `(1..1_000_000)` range
68
- # never materialises. The bit-length cap rejects factorial-style
69
- # blow-up (`(1..64).reduce(:*)` is a ~296-bit Integer) so the
70
- # folded value can never become an analyzer-heavy bignum.
53
+ # Hard caps (ADR-41 WD4 style). The element count is checked BEFORE the receiver is enumerated, so
54
+ # a `(1..1_000_000)` range never materialises. The bit-length cap rejects factorial-style blow-up
55
+ # (`(1..64).reduce(:*)` is a ~296-bit Integer) so the folded value can never become an
56
+ # analyzer-heavy bignum.
71
57
  CONSTANT_FOLD_ELEMENT_CAP = 64
72
58
  CONSTANT_FOLD_BIT_CAP = 256
73
59
  private_constant :CONSTANT_FOLD_ELEMENT_CAP, :CONSTANT_FOLD_BIT_CAP
@@ -81,14 +67,11 @@ module Rigor
81
67
  operator, seed = operator_and_seed(args)
82
68
  return nil if operator.nil?
83
69
 
84
- # Precision pre-check: when the receiver is a fully-constant
85
- # collection (a `Constant[Range]` with foldable endpoints or a
86
- # `Tuple` of `Constant` elements) and the operator is an
87
- # allow-listed pure op, treat the reduction as a pure function
88
- # and execute it on the real values, capped. Any decline (size
89
- # cap, non-constant member, magnitude, exception) falls through
90
- # to the carrier-precise nominal fold below — byte-identical to
91
- # pre-fold behaviour.
70
+ # Precision pre-check: when the receiver is a fully-constant collection (a `Constant[Range]` with
71
+ # foldable endpoints or a `Tuple` of `Constant` elements) and the operator is an allow-listed pure
72
+ # op, treat the reduction as a pure function and execute it on the real values, capped. Any
73
+ # decline (size cap, non-constant member, magnitude, exception) falls through to the
74
+ # carrier-precise nominal fold below byte-identical to pre-fold behaviour.
92
75
  folded = try_constant_reduce(context.receiver, operator, seed)
93
76
  return folded if folded
94
77
 
@@ -98,12 +81,11 @@ module Rigor
98
81
  fold_result(operator, seed, element, context.environment)
99
82
  end
100
83
 
101
- # Executes the reduction on real constant values, or returns nil
102
- # to decline. The caller falls through to the nominal fold on a
103
- # nil return, so every guard here is precision-additive only.
84
+ # Executes the reduction on real constant values, or returns nil to decline. The caller falls
85
+ # through to the nominal fold on a nil return, so every guard here is precision-additive only.
104
86
  #
105
- # @param seed [Rigor::Type, nil] the optional seed type; only a
106
- # foldable `Constant` seed is honoured, any other seed declines.
87
+ # @param seed [Rigor::Type, nil] the optional seed type; only a foldable `Constant` seed is
88
+ # honoured, any other seed declines.
107
89
  # @return [Rigor::Type::Constant, nil]
108
90
  def try_constant_reduce(receiver, operator, seed)
109
91
  return nil unless CONSTANT_FOLD_OPERATORS.include?(operator)
@@ -117,9 +99,8 @@ module Rigor
117
99
  execute_constant_reduce(members, operator, seed_value, seed_present)
118
100
  end
119
101
 
120
- # Extracts the receiver's elements as a Ruby Array of foldable
121
- # constant values, or nil to decline. Checks the size cap BEFORE
122
- # enumerating so an unbounded / huge `Constant[Range]` (e.g.
102
+ # Extracts the receiver's elements as a Ruby Array of foldable constant values, or nil to decline.
103
+ # Checks the size cap BEFORE enumerating so an unbounded / huge `Constant[Range]` (e.g.
123
104
  # `(1..1_000_000)`) never calls `to_a`.
124
105
  #
125
106
  # @return [Array, nil]
@@ -141,8 +122,8 @@ module Rigor
141
122
  # Reject endless / beginless ranges (`(1..)`, `(..5)`).
142
123
  return nil if first.nil? || last.nil?
143
124
 
144
- # Size BEFORE enumeration — `Range#size` is O(1) for numeric
145
- # ranges and never materialises the elements.
125
+ # Size BEFORE enumeration — `Range#size` is O(1) for numeric ranges and never materialises the
126
+ # elements.
146
127
  size = value.size
147
128
  return nil unless size.is_a?(Integer)
148
129
  return nil if size > CONSTANT_FOLD_ELEMENT_CAP
@@ -159,9 +140,8 @@ module Rigor
159
140
  elements.map(&:value)
160
141
  end
161
142
 
162
- # @return [Array(Object, Boolean)] `[seed_value, present?]`. A nil
163
- # seed type yields `[nil, false]` (no-seed form). A foldable
164
- # `Constant` seed yields `[value, true]`. Any other seed yields
143
+ # @return [Array(Object, Boolean)] `[seed_value, present?]`. A nil seed type yields `[nil, false]`
144
+ # (no-seed form). A foldable `Constant` seed yields `[value, true]`. Any other seed yields
165
145
  # `[nil, false]` so the caller can decline.
166
146
  def constant_seed(seed)
167
147
  return [nil, false] if seed.nil?
@@ -170,11 +150,9 @@ module Rigor
170
150
  [seed.value, true]
171
151
  end
172
152
 
173
- # Runs the actual reduction, guarded by the rescue harness and
174
- # the magnitude cap. Empty-collection semantics match Ruby:
175
- # `[].reduce(s, :op) == s` (seed form) and `[].reduce(:op) == nil`
176
- # (no-seed form → declines so the nominal fold's no-nil contract
177
- # stands; see `fold_result`).
153
+ # Runs the actual reduction, guarded by the rescue harness and the magnitude cap. Empty-collection
154
+ # semantics match Ruby: `[].reduce(s, :op) == s` (seed form) and `[].reduce(:op) == nil` (no-seed
155
+ # form declines so the nominal fold's no-nil contract stands; see `fold_result`).
178
156
  #
179
157
  # @return [Rigor::Type::Constant, nil]
180
158
  def execute_constant_reduce(members, operator, seed_value, seed_present)
@@ -182,9 +160,8 @@ module Rigor
182
160
  if seed_present
183
161
  members.reduce(seed_value) { |acc, e| acc.public_send(operator, e) }
184
162
  else
185
- # No-seed empty collection reduces to nil; decline so the
186
- # nominal no-nil contract is preserved rather than folding
187
- # to `Constant[nil]`.
163
+ # No-seed empty collection reduces to nil; decline so the nominal no-nil contract is preserved
164
+ # rather than folding to `Constant[nil]`.
188
165
  return nil if members.empty?
189
166
 
190
167
  members.reduce { |acc, e| acc.public_send(operator, e) }
@@ -206,17 +183,15 @@ module Rigor
206
183
  FOLDABLE_FOLD_CLASSES.any? { |klass| value.is_a?(klass) }
207
184
  end
208
185
 
209
- # Rejects bignum blow-up. A folded Integer wider than the bit cap
210
- # (factorial, repeated multiplication) declines to the nominal
211
- # `Integer` carrier rather than parking a heavy literal in the
212
- # type graph. Float / Rational carry no comparable blow-up risk.
186
+ # Rejects bignum blow-up. A folded Integer wider than the bit cap (factorial, repeated
187
+ # multiplication) declines to the nominal `Integer` carrier rather than parking a heavy literal in
188
+ # the type graph. Float / Rational carry no comparable blow-up risk.
213
189
  def magnitude_too_large?(result)
214
190
  result.is_a?(Integer) && result.bit_length > CONSTANT_FOLD_BIT_CAP
215
191
  end
216
192
 
217
- # Splits the call's positional arguments into the operator Symbol
218
- # and the optional seed. Returns `[nil, nil]` for any non-Symbol-
219
- # operand shape so `try_dispatch` declines.
193
+ # Splits the call's positional arguments into the operator Symbol and the optional seed. Returns
194
+ # `[nil, nil]` for any non-Symbol-operand shape so `try_dispatch` declines.
220
195
  #
221
196
  # - `[:op]` -> operator `:op`, no seed
222
197
  # - `[seed, :op]` -> operator `:op`, seed `seed`
@@ -239,11 +214,9 @@ module Rigor
239
214
  type.value.is_a?(Symbol) ? type.value : nil
240
215
  end
241
216
 
242
- # Dispatches the operator on the widened operand types. With a
243
- # seed the memo type spans `seed | element` (the first iteration's
244
- # memo is the seed, every later iteration's memo is a previous
245
- # operator result); without a seed the memo and operand are both
246
- # the element type.
217
+ # Dispatches the operator on the widened operand types. With a seed the memo type spans
218
+ # `seed | element` (the first iteration's memo is the seed, every later iteration's memo is a
219
+ # previous operator result); without a seed the memo and operand are both the element type.
247
220
  def fold_result(operator, seed, element, environment)
248
221
  widened_element = Type::Combinator.widen_value_pinned(element)
249
222
  memo = if seed.nil?
@@ -257,12 +230,10 @@ module Rigor
257
230
  result = dispatch_operator(memo, operator, widened_element, environment)
258
231
  return nil if result.nil?
259
232
 
260
- # The seed itself is the result when the collection is empty
261
- # (`[].reduce(s, :op) == s`), so a 2-arg fold's static type is
262
- # the operator result joined with the seed. The seed is widened
263
- # (`Constant[0]` -> `Integer`) for the join so the carrier stays
264
- # the precision target rather than leaking a value-pinned member
265
- # (`0 | Integer`) — full constant folding of the fold is out of
233
+ # The seed itself is the result when the collection is empty (`[].reduce(s, :op) == s`), so a
234
+ # 2-arg fold's static type is the operator result joined with the seed. The seed is widened
235
+ # (`Constant[0]` -> `Integer`) for the join so the carrier stays the precision target rather than
236
+ # leaking a value-pinned member (`0 | Integer`) full constant folding of the fold is out of
266
237
  # scope.
267
238
  return result if seed.nil?
268
239
 
@@ -10,13 +10,10 @@ module Rigor
10
10
  #
11
11
  # === Supported methods
12
12
  #
13
- # * `escape(str)` / `quote(str)` — escapes regexp meta-characters.
14
- # Returns `Constant[String]`.
15
- # * `new(str)` / `new(str, opts)` constructs a Regexp at fold time
16
- # when the pattern argument is a `Constant[String]`. The optional
17
- # second argument may be a `Constant[Integer]` (flag bits), a
18
- # `Constant[true/false]` (IGNORECASE shorthand), or absent.
19
- # Returns `Constant[Regexp]`.
13
+ # * `escape(str)` / `quote(str)` — escapes regexp meta-characters. Returns `Constant[String]`.
14
+ # * `new(str)` / `new(str, opts)` — constructs a Regexp at fold time when the pattern argument is a
15
+ # `Constant[String]`. The optional second argument may be a `Constant[Integer]` (flag bits), a
16
+ # `Constant[true/false]` (IGNORECASE shorthand), or absent. Returns `Constant[Regexp]`.
20
17
  #
21
18
  # === Non-constant / unsupported cases
22
19
  #
@@ -43,37 +40,29 @@ module Rigor
43
40
  nil
44
41
  end
45
42
 
46
- # `Regexp.last_match` reads the same match-data slot the perlish
47
- # `$~` global tracks. On a proven-match edge — the truthy branch
48
- # of `if str =~ /re/`, the surviving path of `unless /re/ =~ s;
49
- # raise; end`, a `case`/`when` regex arm — the flow engine has
50
- # already narrowed `$~` to a non-nil `MatchData` (see
51
- # `Narrowing#regex_match_predicate_scopes`). Upstream RBS types
52
- # `Regexp.last_match` as `() -> MatchData?` / `(int) -> String?`,
53
- # so without this consult the call drops back to the nilable
54
- # return even where the surrounding flow has *proven* the match
55
- # succeeded — re-introducing the `possible nil receiver` the `$~`
56
- # narrowing exists to remove the moment the code reaches for the
57
- # match through the method rather than the global.
43
+ # `Regexp.last_match` reads the same match-data slot the perlish `$~` global tracks. On a
44
+ # proven-match edge — the truthy branch of `if str =~ /re/`, the surviving path of `unless /re/ =~
45
+ # s; raise; end`, a `case`/`when` regex arm the flow engine has already narrowed `$~` to a
46
+ # non-nil `MatchData` (see `Narrowing#regex_match_predicate_scopes`). Upstream RBS types
47
+ # `Regexp.last_match` as `() -> MatchData?` / `(int) -> String?`, so without this consult the call
48
+ # drops back to the nilable return even where the surrounding flow has *proven* the match
49
+ # succeeded — re-introducing the `possible nil receiver` the `$~` narrowing exists to remove the
50
+ # moment the code reaches for the match through the method rather than the global.
58
51
  #
59
- # Mirrors the global's narrowing exactly, so it rides the same
60
- # `Scope#forget_match_globals` invalidation (an intervening call
61
- # that can re-run a match clears `$~`, and this consult clears
52
+ # Mirrors the global's narrowing exactly, so it rides the same `Scope#forget_match_globals`
53
+ # invalidation (an intervening call that can re-run a match clears `$~`, and this consult clears
62
54
  # with it):
63
55
  #
64
56
  # * 0-arg -> `MatchData` (the narrowed `$~`)
65
- # * `(N)` -> `String` when capture group N is unconditional on
66
- # every successful match (the same set the `$N`
67
- # globals narrow), else `String?` (an optional /
68
- # alternation-reachable group is nil at runtime even
69
- # on a successful match).
57
+ # * `(N)` -> `String` when capture group N is unconditional on every successful match (the same
58
+ # set the `$N` globals narrow), else `String?` (an optional / alternation-reachable
59
+ # group is nil at runtime even on a successful match).
70
60
  # * `(:name)` / `(0)` and other forms defer to RBS.
71
61
  #
72
- # Declines (returns nil -> RBS) whenever `$~` is NOT proven
73
- # non-nil: no match edge established it, or a falsey edge bound it
74
- # to `Constant[nil]`. Narrowing only on the proven edge keeps the
75
- # bare `m = Regexp.last_match; m[...]` (no preceding match) firing
76
- # exactly as today — this never invents a match.
62
+ # Declines (returns nil -> RBS) whenever `$~` is NOT proven non-nil: no match edge established it,
63
+ # or a falsey edge bound it to `Constant[nil]`. Narrowing only on the proven edge keeps the bare
64
+ # `m = Regexp.last_match; m[...]` (no preceding match) firing exactly as today — this never invents
65
+ # a match.
77
66
  def fold_last_match(context)
78
67
  scope = context.scope
79
68
  return nil if scope.nil?
@@ -88,18 +77,16 @@ module Rigor
88
77
  fold_last_match_group(args.first, scope)
89
78
  end
90
79
 
91
- # Narrowed `$~` is a non-nil `Nominal[MatchData]`. A bare
92
- # `MatchData?` / `nil` / Dynamic binding is NOT a proven match.
80
+ # Narrowed `$~` is a non-nil `Nominal[MatchData]`. A bare `MatchData?` / `nil` / Dynamic binding is
81
+ # NOT a proven match.
93
82
  def proven_match?(match_data)
94
83
  match_data.is_a?(Type::Nominal) && match_data.class_name == "MatchData"
95
84
  end
96
85
 
97
- # `Regexp.last_match(N)` for a value-pinned positive Integer N.
98
- # Track the matching `$N` global the predicate edge already
99
- # narrowed: present (`String`) means the group is unconditional,
100
- # absent means it is optional / alternation-reachable (nil at
101
- # runtime on a success), so we surface `String?`. A non-constant
102
- # or non-positive index defers to RBS.
86
+ # `Regexp.last_match(N)` for a value-pinned positive Integer N. Track the matching `$N` global the
87
+ # predicate edge already narrowed: present (`String`) means the group is unconditional, absent
88
+ # means it is optional / alternation-reachable (nil at runtime on a success), so we surface
89
+ # `String?`. A non-constant or non-positive index defers to RBS.
103
90
  def fold_last_match_group(arg, scope)
104
91
  return nil unless arg.is_a?(Type::Constant)
105
92
 
@@ -123,11 +110,10 @@ module Rigor
123
110
  Type::Combinator.constant_of(Regexp.escape(str))
124
111
  end
125
112
 
126
- # `Regexp.new(pattern)` / `Regexp.new(pattern, opts)` — constructs
127
- # the pattern at inference time. Delegates to Ruby's real
128
- # `Regexp.new` so all option forms (Integer flags, `true`/`false`,
129
- # option strings) are handled without case-analysis; non-constant or
130
- # invalid arguments decline through to the RBS tier.
113
+ # `Regexp.new(pattern)` / `Regexp.new(pattern, opts)` — constructs the pattern at inference time.
114
+ # Delegates to Ruby's real `Regexp.new` so all option forms (Integer flags, `true`/`false`, option
115
+ # strings) are handled without case-analysis; non-constant or invalid arguments decline through to
116
+ # the RBS tier.
131
117
  def fold_new(args)
132
118
  return nil if args.empty? || args.size > 2
133
119
 
@@ -6,20 +6,17 @@ require_relative "singleton_folding"
6
6
  module Rigor
7
7
  module Inference
8
8
  module MethodDispatcher
9
- # Folds `Set` constructor calls into `Constant[Set]` when all
10
- # arguments are statically known.
9
+ # Folds `Set` constructor calls into `Constant[Set]` when all arguments are statically known.
11
10
  #
12
- # Ruby 3.2+ implements Set in C (`set.c`). The constructor is
13
- # deterministic — it reads only its arguments and writes nothing
14
- # to global state.
11
+ # Ruby 3.2+ implements Set in C (`set.c`). The constructor is deterministic — it reads only its
12
+ # arguments and writes nothing to global state.
15
13
  #
16
14
  # === Supported methods
17
15
  #
18
- # * `Set[]` — variadic constructor; each argument must be a
19
- # `Constant[T]`. Returns `Constant[Set]`.
16
+ # * `Set[]` — variadic constructor; each argument must be a `Constant[T]`. Returns `Constant[Set]`.
20
17
  # * `Set.new` — zero-argument form; returns `Constant[Set.new]`.
21
- # * `Set.new(tuple)` — the argument must be a `Tuple` whose
22
- # every element is a `Constant[T]`. Returns `Constant[Set]`.
18
+ # * `Set.new(tuple)` — the argument must be a `Tuple` whose every element is a `Constant[T]`. Returns
19
+ # `Constant[Set]`.
23
20
  #
24
21
  # === Non-constant / unsupported cases
25
22
  #