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,110 +9,80 @@ require_relative "overload_selector"
9
9
  module Rigor
10
10
  module Inference
11
11
  module MethodDispatcher
12
- # Slice 4 dispatch tier that consults RBS method signatures.
13
- # Sits behind {ConstantFolding}, so anything the constant folder
14
- # already proves (e.g., `1 + 2 == 3`) keeps its full Constant
15
- # precision; only the calls the folder cannot prove fall through
16
- # to RBS.
12
+ # Slice 4 dispatch tier that consults RBS method signatures. Sits behind {ConstantFolding}, so
13
+ # anything the constant folder already proves (e.g., `1 + 2 == 3`) keeps its full Constant precision;
14
+ # only the calls the folder cannot prove fall through to RBS.
17
15
  #
18
- # Phase 2b extends the dispatcher to recognise `Singleton[Foo]`
19
- # receivers, routing those calls through `singleton_method`
20
- # instead of `instance_method`. The constant `Foo` therefore now
21
- # resolves to `Singleton[Foo]`, and `Foo.new` / `Foo.bar` look up
22
- # the corresponding *class* methods.
16
+ # Phase 2b extends the dispatcher to recognise `Singleton[Foo]` receivers, routing those calls
17
+ # through `singleton_method` instead of `instance_method`. The constant `Foo` therefore now resolves
18
+ # to `Singleton[Foo]`, and `Foo.new` / `Foo.bar` look up the corresponding *class* methods.
23
19
  #
24
- # Phase 2c adds argument-typed overload selection: instead of
25
- # always returning `method_types.first`, the dispatcher delegates
26
- # to {OverloadSelector} which filters overloads by positional
27
- # arity and consults `Rigor::Type#accepts` for each parameter.
28
- # When no overload accepts the actual argument types, the
29
- # selector falls back to the first overload so the existing
30
- # phase-1/2b behavior is preserved.
20
+ # Phase 2c adds argument-typed overload selection: instead of always returning `method_types.first`,
21
+ # the dispatcher delegates to {OverloadSelector} which filters overloads by positional arity and
22
+ # consults `Rigor::Type#accepts` for each parameter. When no overload accepts the actual argument
23
+ # types, the selector falls back to the first overload so the existing phase-1/2b behavior is
24
+ # preserved.
31
25
  #
32
- # Phase 2d adds generics instantiation. Receivers carry an
33
- # ordered `type_args` array on `Rigor::Type::Nominal`. The
34
- # dispatcher zips the receiver's `type_args` against the class's
35
- # declared type-parameter names (`Array` -> `[:Elem]`, `Hash` ->
36
- # `[:K, :V]`, ...) to build a substitution map; that map is then
37
- # threaded through {RbsTypeTranslator} so a return type like
38
- # `::Array[Elem]` resolves to `Nominal["Array", [Integer]]`
39
- # rather than degrading the variable to `Dynamic[Top]`. When
40
- # arities mismatch (raw receiver, partial generics) the map is
41
- # left empty and free variables degrade as before.
26
+ # Phase 2d adds generics instantiation. Receivers carry an ordered `type_args` array on
27
+ # `Rigor::Type::Nominal`. The dispatcher zips the receiver's `type_args` against the class's declared
28
+ # type-parameter names (`Array` -> `[:Elem]`, `Hash` -> `[:K, :V]`, ...) to build a substitution map;
29
+ # that map is then threaded through {RbsTypeTranslator} so a return type like `::Array[Elem]`
30
+ # resolves to `Nominal["Array", [Integer]]` rather than degrading the variable to `Dynamic[Top]`.
31
+ # When arities mismatch (raw receiver, partial generics) the map is left empty and free variables
32
+ # degrade as before.
42
33
  #
43
- # Slice 5 phase 1 projects shape-carrying receivers onto their
44
- # underlying nominal so the existing dispatch + substitution
45
- # machinery works without duplication: `Tuple[Integer, String]`
46
- # dispatches as `Array[Integer | String]`, and
47
- # `HashShape{a: Integer}` dispatches as `Hash[Symbol, Integer]`.
48
- # Tuple/HashShape element precision (e.g., `tuple[0]` returning
49
- # the precise member) is handled by the preceding `ShapeDispatch`
50
- # tier.
34
+ # Slice 5 phase 1 projects shape-carrying receivers onto their underlying nominal so the existing
35
+ # dispatch + substitution machinery works without duplication: `Tuple[Integer, String]` dispatches as
36
+ # `Array[Integer | String]`, and `HashShape{a: Integer}` dispatches as `Hash[Symbol, Integer]`.
37
+ # Tuple/HashShape element precision (e.g., `tuple[0]` returning the precise member) is handled by the
38
+ # preceding `ShapeDispatch` tier.
51
39
  #
52
40
  # Remaining limitations:
53
41
  #
54
- # * `block_type:` is ignored; method types that constrain the
55
- # block return type are not yet honored.
56
- # * Keyword arguments are not threaded through call_arg_types,
57
- # so overloads with required keywords are skipped (they cannot
58
- # match the empty kwargs we send).
59
- # * Method-level type parameters (e.g., `def foo[T]: (T) -> T`)
60
- # are not bound; their variables remain `Dynamic[Top]` after
61
- # substitution.
42
+ # * `block_type:` is ignored; method types that constrain the block return type are not yet honored.
43
+ # * Keyword arguments are not threaded through call_arg_types, so overloads with required keywords
44
+ # are skipped (they cannot match the empty kwargs we send).
45
+ # * Method-level type parameters (e.g., `def foo[T]: (T) -> T`) are not bound; their variables remain
46
+ # `Dynamic[Top]` after substitution.
62
47
  #
63
48
  # See docs/adr/4-type-inference-engine.md for the broader plan.
64
49
  # rubocop:disable Metrics/ModuleLength
65
50
  module RbsDispatch
66
51
  module_function
67
52
 
68
- # ADR-43 — ancestor classes whose RBS is authoritative and
69
- # COMPLETE, so a call a subclass makes that the ancestor's RBS
70
- # does not declare is a genuine mistake rather than a gap.
71
- # Membership unlocks inherited-method resolution (and thus
72
- # `call.undefined-method`) for Ruby-source subclasses of these
73
- # classes; every other RBS ancestor stays on the Dynamic
74
- # fallback. Seeded with the plugin contract base this repo
75
- # owns both the class and `sig/rigor/plugin/base.rbs`, and the
76
- # `lib` self-check keeps them in lock-step. NOT a place for
77
- # third-party/core classes whose objects answer to methods
78
- # their RBS omits (`ActionController::Base`, `Hash`, …).
53
+ # ADR-43 — ancestor classes whose RBS is authoritative and COMPLETE, so a call a subclass makes
54
+ # that the ancestor's RBS does not declare is a genuine mistake rather than a gap. Membership
55
+ # unlocks inherited-method resolution (and thus `call.undefined-method`) for Ruby-source
56
+ # subclasses of these classes; every other RBS ancestor stays on the Dynamic fallback. Seeded with
57
+ # the plugin contract base this repo owns both the class and `sig/rigor/plugin/base.rbs`, and
58
+ # the `lib` self-check keeps them in lock-step. NOT a place for third-party/core classes whose
59
+ # objects answer to methods their RBS omits (`ActionController::Base`, `Hash`, …).
79
60
  ALLOWED_RBS_COMPLETE_ANCESTORS = ["Rigor::Plugin::Base"].freeze
80
61
 
81
62
  # @param receiver [Rigor::Type]
82
63
  # @param method_name [Symbol]
83
64
  # @param args [Array<Rigor::Type>]
84
65
  # @param environment [Rigor::Environment]
85
- # @param block_type [Rigor::Type, nil] inferred block return
86
- # type, propagated from `MethodDispatcher.dispatch`. When
87
- # non-nil, the selector prefers a block-bearing overload
88
- # and binds the method-level type parameter that the
89
- # block's return type references to `block_type` (Slice 6
90
- # phase C sub-phase 2).
91
- # @param self_type_override [Rigor::Type, nil] when set,
92
- # the substitution for `Bases::Self` in the method's
93
- # return type. Used by `MethodDispatcher#try_user_class_fallback`
94
- # to preserve the ORIGINAL receiver as the substitute
95
- # for `self` even though the dispatch is routed through
96
- # `Nominal[Object]` so that `Bundler::URI::Generic.dup`
97
- # (which resolves through the `Object` fallback because
98
- # `Bundler::URI::Generic` lacks RBS) returns
99
- # `Bundler::URI::Generic` per `Kernel#dup: () -> self`
100
- # rather than `Object`. Defaults to nil (compute self
101
- # from the resolved class_name as before).
102
- # @param public_only [Boolean] when true, a method whose RBS
103
- # accessibility is `:private` does not resolve (the call
104
- # yields `nil`, i.e. "no rule"). Set by the explicit-
105
- # non-`self`-receiver user-class fallback so a call like
106
- # `Favourite.select(...)` does not adopt the private
66
+ # @param block_type [Rigor::Type, nil] inferred block return type, propagated from
67
+ # `MethodDispatcher.dispatch`. When non-nil, the selector prefers a block-bearing overload and
68
+ # binds the method-level type parameter that the block's return type references to `block_type`
69
+ # (Slice 6 phase C sub-phase 2).
70
+ # @param self_type_override [Rigor::Type, nil] when set, the substitution for `Bases::Self` in the
71
+ # method's return type. Used by `MethodDispatcher#try_user_class_fallback` to preserve the
72
+ # ORIGINAL receiver as the substitute for `self` even though the dispatch is routed through
73
+ # `Nominal[Object]` so that `Bundler::URI::Generic.dup` (which resolves through the `Object`
74
+ # fallback because `Bundler::URI::Generic` lacks RBS) returns `Bundler::URI::Generic` per
75
+ # `Kernel#dup: () -> self` rather than `Object`. Defaults to nil (compute self from the resolved
76
+ # class_name as before).
77
+ # @param public_only [Boolean] when true, a method whose RBS accessibility is `:private` does not
78
+ # resolve (the call yields `nil`, i.e. "no rule"). Set by the explicit-non-`self`-receiver
79
+ # user-class fallback so a call like `Favourite.select(...)` does not adopt the private
107
80
  # `Kernel#select` signature.
108
- # @return [Rigor::Type, nil] inferred return type, or `nil`
109
- # when no rule resolves (no class name, no method, dispatch
110
- # on a Top/Dynamic[Top] receiver, etc.).
111
- # @param scope [Rigor::Scope, nil] when supplied, enables ADR-43
112
- # RBS-complete-ancestor resolution against
113
- # `ALLOWED_RBS_COMPLETE_ANCESTORS`. `nil` keeps inherited calls
114
- # unresolved (`Dynamic[Top]`) — the FP-safe default for open
115
- # hierarchies (`< ActionController::Base`, …).
81
+ # @return [Rigor::Type, nil] inferred return type, or `nil` when no rule resolves (no class name,
82
+ # no method, dispatch on a Top/Dynamic[Top] receiver, etc.).
83
+ # @param scope [Rigor::Scope, nil] when supplied, enables ADR-43 RBS-complete-ancestor resolution
84
+ # against `ALLOWED_RBS_COMPLETE_ANCESTORS`. `nil` keeps inherited calls unresolved
85
+ # (`Dynamic[Top]`) — the FP-safe default for open hierarchies (`< ActionController::Base`, …).
116
86
  def try_dispatch(context)
117
87
  environment = context.environment
118
88
  return nil if environment.nil?
@@ -130,27 +100,22 @@ module Rigor
130
100
  )
131
101
  end
132
102
 
133
- # Slice 6 (Phase C sub-phase 1) probe: returns the positional
134
- # block-parameter types declared by the receiving method's
135
- # selected RBS overload, translated into `Rigor::Type`. Used
136
- # by the StatementEvaluator to bind block parameter names
137
- # before evaluating the block body.
103
+ # Slice 6 (Phase C sub-phase 1) probe: returns the positional block-parameter types declared by
104
+ # the receiving method's selected RBS overload, translated into `Rigor::Type`. Used by the
105
+ # StatementEvaluator to bind block parameter names before evaluating the block body.
138
106
  #
139
- # The probe shares the receiver descriptor / overload selector
140
- # plumbing with `try_dispatch`; only the projection at the end
141
- # differs (the block's positional params instead of the return
142
- # type). Returns an empty array when:
107
+ # The probe shares the receiver descriptor / overload selector plumbing with `try_dispatch`; only
108
+ # the projection at the end differs (the block's positional params instead of the return type).
109
+ # Returns an empty array when:
143
110
  #
144
111
  # - the environment / RBS loader is missing,
145
112
  # - the receiver does not project to a known class,
146
113
  # - the method has no signature in RBS,
147
114
  # - the selected overload has no `block:` clause, or
148
- # - the block is `untyped` / `UntypedFunction` (no statically
149
- # declared parameter types).
115
+ # - the block is `untyped` / `UntypedFunction` (no statically declared parameter types).
150
116
  #
151
- # This deliberately does NOT differentiate "no overload had a
152
- # block" from "the block is untyped"; the binder treats both
153
- # the same way (every parameter defaults to `Dynamic[Top]`).
117
+ # This deliberately does NOT differentiate "no overload had a block" from "the block is untyped";
118
+ # the binder treats both the same way (every parameter defaults to `Dynamic[Top]`).
154
119
  # @return [Array<Rigor::Type>] positional block parameter types.
155
120
  def block_param_types(context)
156
121
  environment = context.environment
@@ -215,23 +180,18 @@ module Rigor
215
180
  self_type_override: self_type_override
216
181
  )
217
182
  rescue StandardError
218
- # Defensive: if RBS' definition builder raises on a broken
219
- # hierarchy (e.g., partially loaded user signatures), the
220
- # dispatcher MUST stay fail-soft.
183
+ # Defensive: if RBS' definition builder raises on a broken hierarchy (e.g., partially loaded
184
+ # user signatures), the dispatcher MUST stay fail-soft.
221
185
  nil
222
186
  end
223
187
 
224
- # Maps a Rigor::Type receiver to a
225
- # `[class_name, kind, type_args]` triple where `kind` is
226
- # either `:instance` or `:singleton` and `type_args` carries
227
- # the receiver's generic instantiation (empty for raw or
228
- # singleton receivers, since `Singleton[Foo]` carries no
229
- # generic args today). Returns nil when the receiver does
230
- # not correspond to a single concrete class.
188
+ # Maps a Rigor::Type receiver to a `[class_name, kind, type_args]` triple where `kind` is either
189
+ # `:instance` or `:singleton` and `type_args` carries the receiver's generic instantiation (empty
190
+ # for raw or singleton receivers, since `Singleton[Foo]` carries no generic args today). Returns
191
+ # nil when the receiver does not correspond to a single concrete class.
231
192
  #
232
- # Slice 5 phase 1 projects Tuple/HashShape receivers to
233
- # their underlying Array/Hash nominal so dispatch reuses the
234
- # generic-typed pipeline.
193
+ # Slice 5 phase 1 projects Tuple/HashShape receivers to their underlying Array/Hash nominal so
194
+ # dispatch reuses the generic-typed pipeline.
235
195
  def receiver_descriptor(receiver)
236
196
  case receiver
237
197
  when Type::Constant
@@ -247,27 +207,21 @@ module Rigor
247
207
  when Type::DataInstance, Type::DataClass, Type::StructInstance, Type::StructClass
248
208
  member_carrier_descriptor(receiver)
249
209
  when Type::BoundMethod
250
- # `BoundMethod` is a precision-bearing alias for
251
- # `Nominal[Method]`: it carries the
252
- # `(receiver, method_name)` binding that
253
- # `MethodFolding.try_backward` consumes at
254
- # `.call` / `.()` / `[]`, but every other call
255
- # site (`.owner` / `.name` / `.arity` / …) must
256
- # still resolve through Method's RBS contract.
257
- # Routing here keeps reflective Method methods
258
- # working without forcing the carrier to
259
- # collapse to a plain Nominal at construction.
210
+ # `BoundMethod` is a precision-bearing alias for `Nominal[Method]`: it carries the
211
+ # `(receiver, method_name)` binding that `MethodFolding.try_backward` consumes at
212
+ # `.call` / `.()` / `[]`, but every other call site (`.owner` / `.name` / `.arity` / …) must
213
+ # still resolve through Method's RBS contract. Routing here keeps reflective Method methods
214
+ # working without forcing the carrier to collapse to a plain Nominal at construction.
260
215
  ["Method", :instance, []]
261
216
  when Type::Dynamic
262
217
  receiver_descriptor(receiver.static_facet)
263
218
  end
264
219
  end
265
220
 
266
- # ADR-48 — project a `Data`/`Struct` member carrier to its tagging
267
- # class (or the `Data`/`Struct` supertype) so non-member calls
268
- # (`inspect`, `==`, `frozen?`, ...) resolve through RBS rather than
269
- # mis-firing undefined-method. Precise member reads were already
270
- # folded by DataFolding / StructFolding above this tier.
221
+ # ADR-48 — project a `Data`/`Struct` member carrier to its tagging class (or the `Data`/`Struct`
222
+ # supertype) so non-member calls (`inspect`, `==`, `frozen?`, ...) resolve through RBS rather
223
+ # than mis-firing undefined-method. Precise member reads were already folded by DataFolding /
224
+ # StructFolding above this tier.
271
225
  def member_carrier_descriptor(receiver)
272
226
  case receiver
273
227
  when Type::DataInstance then [receiver.class_name || "Data", :instance, []]
@@ -294,11 +248,9 @@ module Rigor
294
248
  ]
295
249
  end
296
250
 
297
- # True when the RBS method definition is `private`. A call
298
- # with an explicit, non-`self` receiver cannot reach a
299
- # private method (Ruby raises `NoMethodError`), so the
300
- # explicit-receiver user-class fallback uses this to reject
301
- # private signatures rather than return a wrong type.
251
+ # True when the RBS method definition is `private`. A call with an explicit, non-`self` receiver
252
+ # cannot reach a private method (Ruby raises `NoMethodError`), so the explicit-receiver
253
+ # user-class fallback uses this to reject private signatures rather than return a wrong type.
302
254
  def method_private?(method_definition)
303
255
  method_definition.respond_to?(:accessibility) &&
304
256
  method_definition.accessibility == :private
@@ -308,15 +260,12 @@ module Rigor
308
260
  direct = lookup_method_on(environment, class_name, kind, method_name)
309
261
  return direct if direct
310
262
 
311
- # ADR-43 — scoped inherited-method resolution. The direct
312
- # lookup misses when `class_name` is a Ruby-source subclass
313
- # absent from RBS (so no ancestor walk runs). If its
314
- # discovered superclass chain reaches an allow-listed
315
- # RBS-complete ancestor, resolve the method there so
316
- # inherited contract calls (`self.manifest` on a plugin)
317
- # resolve and the normal call rules apply. Bounded to the
318
- # allow-list, so open hierarchies stay on the Dynamic
319
- # fallback (no false positive on `< ActionController::Base`).
263
+ # ADR-43 — scoped inherited-method resolution. The direct lookup misses when `class_name` is a
264
+ # Ruby-source subclass absent from RBS (so no ancestor walk runs). If its discovered
265
+ # superclass chain reaches an allow-listed RBS-complete ancestor, resolve the method there so
266
+ # inherited contract calls (`self.manifest` on a plugin) resolve and the normal call rules
267
+ # apply. Bounded to the allow-list, so open hierarchies stay on the Dynamic fallback (no false
268
+ # positive on `< ActionController::Base`).
320
269
  ancestor = allowed_rbs_complete_ancestor(environment, class_name, scope)
321
270
  return nil unless ancestor
322
271
 
@@ -332,13 +281,11 @@ module Rigor
332
281
  end
333
282
  end
334
283
 
335
- # The first allow-listed, RBS-complete ancestor reachable from
336
- # `class_name` through `scope.discovered_superclasses`, or nil.
337
- # Returns nil when no scope is threaded, when `class_name` is
338
- # itself RBS-known (the direct lookup already had authority),
339
- # or when the discovered chain reaches no allow-listed class.
340
- # The walk carries a visited set so a malformed cyclic
341
- # `A < B < A` source cannot loop.
284
+ # The first allow-listed, RBS-complete ancestor reachable from `class_name` through
285
+ # `scope.discovered_superclasses`, or nil. Returns nil when no scope is threaded, when
286
+ # `class_name` is itself RBS-known (the direct lookup already had authority), or when the
287
+ # discovered chain reaches no allow-listed class. The walk carries a visited set so a malformed
288
+ # cyclic `A < B < A` source cannot loop.
342
289
  def allowed_rbs_complete_ancestor(environment, class_name, scope)
343
290
  return nil if scope.nil?
344
291
  return nil if Rigor::Reflection.rbs_class_known?(class_name, environment: environment)
@@ -355,12 +302,10 @@ module Rigor
355
302
  nil
356
303
  end
357
304
 
358
- # Slice 4 phase 2d substitution map. Zips the class's
359
- # declared type-parameter names against the receiver's
360
- # `type_args`. Returns an empty hash when either side is
361
- # empty or when arities disagree -- in both cases free
362
- # variables in the method's return type degrade to
363
- # `Dynamic[Top]` per the translator's contract.
305
+ # Slice 4 phase 2d substitution map. Zips the class's declared type-parameter names against the
306
+ # receiver's `type_args`. Returns an empty hash when either side is empty or when arities
307
+ # disagree -- in both cases free variables in the method's return type degrade to `Dynamic[Top]`
308
+ # per the translator's contract.
364
309
  def build_type_vars(environment, class_name, receiver_args)
365
310
  return {} if receiver_args.empty?
366
311
 
@@ -375,12 +320,9 @@ module Rigor
375
320
  def translate_return_type(method_definition, class_name:, kind:, args:, type_vars:, block_type:,
376
321
  environment: nil, self_type_override: nil)
377
322
  # rubocop:enable Metrics/ParameterLists
378
- # Slice 4b-3 (ADR-7 § "Slice 4-A/4-B") — read the
379
- # return-type override through the merger so future
380
- # plugin / `:rbs_extended` bundles that also assert a
381
- # `return_type` slot at this call site compose with
382
- # the RBS::Extended directive instead of silently
383
- # racing it.
323
+ # Slice 4b-3 (ADR-7 § "Slice 4-A/4-B") — read the return-type override through the merger so
324
+ # future plugin / `:rbs_extended` bundles that also assert a `return_type` slot at this call
325
+ # site compose with the RBS::Extended directive instead of silently racing it.
384
326
  override = merged_return_type(method_definition, environment: environment)
385
327
  return override if override
386
328
 
@@ -390,11 +332,9 @@ module Rigor
390
332
  when :singleton then Type::Combinator.singleton_of(class_name)
391
333
  else instance_type
392
334
  end
393
- # `self_type_override` lets the user-class fallback
394
- # path preserve the ORIGINAL receiver as the substitute
395
- # for `Bases::Self` so `Kernel#dup: () -> self`
396
- # resolved through the Object fallback returns the
397
- # caller's type, not Object.
335
+ # `self_type_override` lets the user-class fallback path preserve the ORIGINAL receiver as the
336
+ # substitute for `Bases::Self` so `Kernel#dup: () -> self` resolved through the Object
337
+ # fallback returns the caller's type, not Object.
398
338
  self_type = self_type_override || resolved_self_type
399
339
 
400
340
  method_type = OverloadSelector.select(
@@ -418,12 +358,9 @@ module Rigor
418
358
  )
419
359
  end
420
360
 
421
- # ADR-7 § "Slice 4-A/4-B" — folds the
422
- # `RBS::Extended` `return:` directive (and any
423
- # other `return_type`-bearing contribution future
424
- # slices add at this call site) through the merger
425
- # before consuming. Returns the merged return type
426
- # or nil when no contribution overrides the
361
+ # ADR-7 § "Slice 4-A/4-B" — folds the `RBS::Extended` `return:` directive (and any other
362
+ # `return_type`-bearing contribution future slices add at this call site) through the merger
363
+ # before consuming. Returns the merged return type or nil when no contribution overrides the
427
364
  # RBS-declared return.
428
365
  def merged_return_type(method_definition, environment: nil)
429
366
  contribution = RbsExtended.read_flow_contribution(method_definition, environment: environment)
@@ -432,18 +369,13 @@ module Rigor
432
369
  Rigor::FlowContribution::Merger.merge([contribution]).return_type
433
370
  end
434
371
 
435
- # When a block type is supplied, locate the method-level
436
- # type parameter that the selected overload's block return
437
- # type references and bind it to `block_type`. The
438
- # contribution layers on top of the receiver-derived
439
- # `type_vars` so a method like
440
- # `def map[U] { (Elem) -> U } -> Array[U]` resolves
441
- # `Elem` from the receiver and `U` from the block return
442
- # type at the same call site. Anything outside this exact
443
- # shape (no block clause, an `untyped` block, a non-
444
- # variable block return type, a variable not declared in
445
- # `type_params`) returns the original `type_vars` so
446
- # fallbacks stay consistent.
372
+ # When a block type is supplied, locate the method-level type parameter that the selected
373
+ # overload's block return type references and bind it to `block_type`. The contribution layers
374
+ # on top of the receiver-derived `type_vars` so a method like
375
+ # `def map[U] { (Elem) -> U } -> Array[U]` resolves `Elem` from the receiver and `U` from the
376
+ # block return type at the same call site. Anything outside this exact shape (no block clause,
377
+ # an `untyped` block, a non-variable block return type, a variable not declared in
378
+ # `type_params`) returns the original `type_vars` so fallbacks stay consistent.
447
379
  def compose_block_type_vars(method_type, type_vars, block_type)
448
380
  return type_vars if block_type.nil?
449
381
 
@@ -485,12 +417,10 @@ module Rigor
485
417
  end
486
418
  end
487
419
 
488
- # For a union receiver we keep the conservative answer: only
489
- # return block param types when every member resolves the
490
- # same arity and types (otherwise the call sites would have
491
- # to thread per-member binders, which the slice does not
492
- # support yet). Mismatches degrade to the empty array so the
493
- # binder defaults all params to Dynamic[Top].
420
+ # For a union receiver we keep the conservative answer: only return block param types when every
421
+ # member resolves the same arity and types (otherwise the call sites would have to thread
422
+ # per-member binders, which the slice does not support yet). Mismatches degrade to the empty
423
+ # array so the binder defaults all params to Dynamic[Top].
494
424
  def probe_block_param_types_union(receiver, method_name, args, environment)
495
425
  results = receiver.members.map do |member|
496
426
  probe_block_param_types_one(member, method_name, args, environment)
@@ -553,11 +483,10 @@ module Rigor
553
483
  )
554
484
  end
555
485
 
556
- # `RBS::Types::Block#type` is normally an `RBS::Types::Function`
557
- # carrying the block's parameter list; some signatures use
558
- # `RBS::Types::UntypedFunction` (a `(?)` block) which exposes
559
- # no parameter types -- we treat it as "no information" and
560
- # return an empty array so the binder defaults every slot.
486
+ # `RBS::Types::Block#type` is normally an `RBS::Types::Function` carrying the block's parameter
487
+ # list; some signatures use `RBS::Types::UntypedFunction` (a `(?)` block) which exposes no
488
+ # parameter types -- we treat it as "no information" and return an empty array so the binder
489
+ # defaults every slot.
561
490
  def translate_block_positional_params(block, self_type:, instance_type:, type_vars:)
562
491
  fun = block.type
563
492
  return [] unless fun.respond_to?(:required_positionals)
@@ -5,25 +5,18 @@ require_relative "../../type"
5
5
  module Rigor
6
6
  module Inference
7
7
  module MethodDispatcher
8
- # Stable-sort an overload list so that "receiver-affinity"
9
- # arms come first. An overload is receiver-affinity-matching
10
- # when every positional param's class equals `self_type`'s
11
- # class name OR is one of its proper RBS ancestors. The
12
- # canonical case the helper exists for: when `bigdecimal`'s
13
- # stdlib RBS reopens `Integer#+` at the FRONT of the
14
- # overload list with `(BigDecimal) -> BigDecimal`, that
15
- # disjoint-sibling arm would win every dispatch for
16
- # `Integer#+(?)` by overload-list position alone, returning
17
- # a spurious `BigDecimal` for plain integer arithmetic.
18
- # Demoting the arm honours the coerce convention: when the
19
- # arg type is unknown or itself an Integer, the
20
- # receiver-preserving `(Integer) -> Integer` arm should win.
8
+ # Stable-sort an overload list so that "receiver-affinity" arms come first. An overload is
9
+ # receiver-affinity-matching when every positional param's class equals `self_type`'s class name OR
10
+ # is one of its proper RBS ancestors. The canonical case the helper exists for: when `bigdecimal`'s
11
+ # stdlib RBS reopens `Integer#+` at the FRONT of the overload list with `(BigDecimal) -> BigDecimal`,
12
+ # that disjoint-sibling arm would win every dispatch for `Integer#+(?)` by overload-list position
13
+ # alone, returning a spurious `BigDecimal` for plain integer arithmetic. Demoting the arm honours the
14
+ # coerce convention: when the arg type is unknown or itself an Integer, the receiver-preserving
15
+ # `(Integer) -> Integer` arm should win.
21
16
  #
22
- # No-op when (a) the environment can't answer
23
- # `class_ordering` (nil env), or (b) the receiver isn't a
24
- # nominal / singleton carrying a class name. The partition
25
- # is stable, so within each bucket the RBS-declared order
26
- # is preserved.
17
+ # No-op when (a) the environment can't answer `class_ordering` (nil env), or (b) the receiver isn't a
18
+ # nominal / singleton carrying a class name. The partition is stable, so within each bucket the
19
+ # RBS-declared order is preserved.
27
20
  module ReceiverAffinity
28
21
  module_function
29
22
 
@@ -56,12 +49,10 @@ module Rigor
56
49
  params.all? { |param| param_class_in_ancestry?(param.type, self_class_name, environment) }
57
50
  end
58
51
 
59
- # Walks Optional and Union one level so `(Numeric?)` and
60
- # `(Integer | Float)` still classify when every branch
61
- # sits in the ancestry. Non-`ClassInstance` shapes
62
- # (Alias / Interface / Intersection / type variables)
63
- # don't carry a clean class identity and therefore
64
- # disqualify the overload from the affinity bucket.
52
+ # Walks Optional and Union one level so `(Numeric?)` and `(Integer | Float)` still classify when
53
+ # every branch sits in the ancestry. Non-`ClassInstance` shapes (Alias / Interface / Intersection
54
+ # / type variables) don't carry a clean class identity and therefore disqualify the overload from
55
+ # the affinity bucket.
65
56
  def param_class_in_ancestry?(rbs_type, self_class_name, environment)
66
57
  case rbs_type
67
58
  when RBS::Types::ClassInstance