rigortype 0.2.7 → 0.2.9

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 (433) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/data/core_overlay/csv.rbs +28 -0
  4. data/data/core_overlay/psych.rbs +22 -0
  5. data/docs/handbook/01-getting-started.md +9 -1
  6. data/docs/handbook/02-everyday-types.md +4 -1
  7. data/docs/handbook/08-understanding-errors.md +3 -3
  8. data/docs/manual/01-installation.md +1 -0
  9. data/docs/manual/02-cli-reference.md +16 -7
  10. data/docs/manual/04-diagnostics.md +7 -4
  11. data/docs/manual/06-baseline.md +5 -2
  12. data/docs/manual/07-plugins.md +1 -1
  13. data/docs/manual/14-rails-quickstart.md +4 -2
  14. data/docs/manual/15-type-protection-coverage.md +27 -4
  15. data/docs/manual/plugins/rigor-actionpack.md +1 -1
  16. data/docs/manual/plugins/rigor-activerecord.md +12 -5
  17. data/docs/manual/plugins/rigor-rails-routes.md +11 -0
  18. data/lib/rigor/analysis/baseline.rb +56 -96
  19. data/lib/rigor/analysis/buffer_binding.rb +13 -20
  20. data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +29 -48
  21. data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +35 -54
  22. data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +23 -37
  23. data/lib/rigor/analysis/check_rules/main_pass_collector.rb +16 -23
  24. data/lib/rigor/analysis/check_rules/rule_walk.rb +48 -71
  25. data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +19 -28
  26. data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +48 -67
  27. data/lib/rigor/analysis/check_rules.rb +174 -274
  28. data/lib/rigor/analysis/dependency_recorder.rb +26 -38
  29. data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +13 -25
  30. data/lib/rigor/analysis/dependency_source_inference/builder.rb +17 -30
  31. data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +15 -26
  32. data/lib/rigor/analysis/dependency_source_inference/index.rb +45 -76
  33. data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +23 -40
  34. data/lib/rigor/analysis/dependency_source_inference/walker.rb +50 -83
  35. data/lib/rigor/analysis/dependency_source_inference.rb +6 -10
  36. data/lib/rigor/analysis/diagnostic.rb +48 -75
  37. data/lib/rigor/analysis/erb_template_detector.rb +13 -18
  38. data/lib/rigor/analysis/fact_store.rb +12 -22
  39. data/lib/rigor/analysis/incremental.rb +47 -63
  40. data/lib/rigor/analysis/incremental_session.rb +74 -100
  41. data/lib/rigor/analysis/project_scan.rb +12 -23
  42. data/lib/rigor/analysis/result.rb +3 -5
  43. data/lib/rigor/analysis/rule_catalog.rb +67 -95
  44. data/lib/rigor/analysis/run_stats.rb +38 -61
  45. data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +101 -160
  46. data/lib/rigor/analysis/runner/pool_coordinator.rb +121 -188
  47. data/lib/rigor/analysis/runner/project_pre_passes.rb +62 -96
  48. data/lib/rigor/analysis/runner/run_snapshots.rb +12 -18
  49. data/lib/rigor/analysis/runner.rb +220 -333
  50. data/lib/rigor/analysis/self_call_resolution_recorder.rb +30 -43
  51. data/lib/rigor/analysis/worker_session.rb +64 -102
  52. data/lib/rigor/ast/type_node.rb +6 -8
  53. data/lib/rigor/ast.rb +6 -10
  54. data/lib/rigor/bleeding_edge.rb +27 -35
  55. data/lib/rigor/builtins/hkt_builtins.rb +7 -14
  56. data/lib/rigor/builtins/imported_refinements.rb +106 -149
  57. data/lib/rigor/builtins/predefined_constant_refinements.rb +51 -65
  58. data/lib/rigor/builtins/regex_refinement.rb +32 -43
  59. data/lib/rigor/builtins/static_return_refinements.rb +57 -81
  60. data/lib/rigor/cache/descriptor.rb +58 -94
  61. data/lib/rigor/cache/incremental_snapshot.rb +32 -48
  62. data/lib/rigor/cache/rbs_cache_producer.rb +10 -15
  63. data/lib/rigor/cache/rbs_class_ancestor_table.rb +10 -16
  64. data/lib/rigor/cache/rbs_class_type_param_names.rb +10 -16
  65. data/lib/rigor/cache/rbs_constant_table.rb +8 -13
  66. data/lib/rigor/cache/rbs_descriptor.rb +8 -13
  67. data/lib/rigor/cache/rbs_environment.rb +11 -19
  68. data/lib/rigor/cache/rbs_environment_marshal_patch.rb +11 -19
  69. data/lib/rigor/cache/rbs_known_class_names.rb +8 -12
  70. data/lib/rigor/cache/store.rb +248 -186
  71. data/lib/rigor/cli/annotate_command.rb +51 -88
  72. data/lib/rigor/cli/baseline_command.rb +10 -17
  73. data/lib/rigor/cli/check_command.rb +121 -199
  74. data/lib/rigor/cli/check_runner_factory.rb +8 -14
  75. data/lib/rigor/cli/ci_detector.rb +9 -14
  76. data/lib/rigor/cli/command.rb +8 -14
  77. data/lib/rigor/cli/coverage_command.rb +62 -48
  78. data/lib/rigor/cli/coverage_mutation.rb +14 -19
  79. data/lib/rigor/cli/coverage_report.rb +0 -2
  80. data/lib/rigor/cli/coverage_scan.rb +7 -11
  81. data/lib/rigor/cli/diagnostic_formats.rb +46 -62
  82. data/lib/rigor/cli/diff_command.rb +10 -20
  83. data/lib/rigor/cli/docs_command.rb +26 -40
  84. data/lib/rigor/cli/doctor_command.rb +8 -9
  85. data/lib/rigor/cli/explain_command.rb +4 -7
  86. data/lib/rigor/cli/fused_protection_renderer.rb +4 -5
  87. data/lib/rigor/cli/fused_protection_report.rb +6 -8
  88. data/lib/rigor/cli/lsp_command.rb +11 -19
  89. data/lib/rigor/cli/mcp_command.rb +4 -6
  90. data/lib/rigor/cli/mutation_protection_renderer.rb +3 -4
  91. data/lib/rigor/cli/mutation_protection_report.rb +6 -9
  92. data/lib/rigor/cli/options.rb +11 -19
  93. data/lib/rigor/cli/plugin_command.rb +18 -30
  94. data/lib/rigor/cli/plugins_command.rb +29 -51
  95. data/lib/rigor/cli/plugins_renderer.rb +12 -20
  96. data/lib/rigor/cli/prism_colorizer.rb +13 -19
  97. data/lib/rigor/cli/protection_fork_scan.rb +55 -0
  98. data/lib/rigor/cli/protection_renderer.rb +5 -7
  99. data/lib/rigor/cli/protection_report.rb +34 -18
  100. data/lib/rigor/cli/renderable.rb +4 -6
  101. data/lib/rigor/cli/show_bleedingedge_command.rb +5 -8
  102. data/lib/rigor/cli/sig_gen_command.rb +14 -26
  103. data/lib/rigor/cli/skill_command.rb +30 -47
  104. data/lib/rigor/cli/skill_describe.rb +40 -64
  105. data/lib/rigor/cli/trace_command.rb +9 -16
  106. data/lib/rigor/cli/trace_renderer.rb +35 -51
  107. data/lib/rigor/cli/triage_command.rb +6 -10
  108. data/lib/rigor/cli/triage_renderer.rb +1 -2
  109. data/lib/rigor/cli/type_of_command.rb +14 -23
  110. data/lib/rigor/cli/type_of_renderer.rb +3 -5
  111. data/lib/rigor/cli/type_scan_command.rb +6 -10
  112. data/lib/rigor/cli/type_scan_renderer.rb +3 -5
  113. data/lib/rigor/cli/type_scan_report.rb +2 -3
  114. data/lib/rigor/cli/upgrade_command.rb +2 -3
  115. data/lib/rigor/cli.rb +16 -28
  116. data/lib/rigor/config_audit.rb +35 -44
  117. data/lib/rigor/configuration/dependencies.rb +41 -70
  118. data/lib/rigor/configuration/severity_profile.rb +28 -42
  119. data/lib/rigor/configuration.rb +150 -241
  120. data/lib/rigor/environment/bundle_sig_discovery.rb +74 -118
  121. data/lib/rigor/environment/class_registry.rb +19 -26
  122. data/lib/rigor/environment/constant_type_cache_holder.rb +14 -21
  123. data/lib/rigor/environment/hkt_registry_holder.rb +6 -12
  124. data/lib/rigor/environment/lockfile_resolver.rb +31 -47
  125. data/lib/rigor/environment/missing_gem_constant_index.rb +128 -0
  126. data/lib/rigor/environment/rbs_collection_discovery.rb +39 -63
  127. data/lib/rigor/environment/rbs_coverage_report.rb +24 -42
  128. data/lib/rigor/environment/rbs_loader.rb +420 -518
  129. data/lib/rigor/environment/reflection.rb +28 -53
  130. data/lib/rigor/environment/reporters.rb +13 -24
  131. data/lib/rigor/environment.rb +225 -304
  132. data/lib/rigor/flow_contribution/conflict.rb +16 -27
  133. data/lib/rigor/flow_contribution/element.rb +7 -12
  134. data/lib/rigor/flow_contribution/fact.rb +33 -57
  135. data/lib/rigor/flow_contribution/merge_result.rb +6 -9
  136. data/lib/rigor/flow_contribution/merger.rb +32 -47
  137. data/lib/rigor/flow_contribution.rb +37 -55
  138. data/lib/rigor/inference/acceptance.rb +133 -219
  139. data/lib/rigor/inference/block_parameter_binder.rb +52 -82
  140. data/lib/rigor/inference/body_fixpoint.rb +22 -30
  141. data/lib/rigor/inference/budget_trace.rb +43 -63
  142. data/lib/rigor/inference/builtins/array_catalog.rb +4 -6
  143. data/lib/rigor/inference/builtins/comparable_catalog.rb +4 -6
  144. data/lib/rigor/inference/builtins/complex_catalog.rb +13 -19
  145. data/lib/rigor/inference/builtins/date_catalog.rb +38 -67
  146. data/lib/rigor/inference/builtins/encoding_catalog.rb +22 -36
  147. data/lib/rigor/inference/builtins/enumerable_catalog.rb +4 -6
  148. data/lib/rigor/inference/builtins/exception_catalog.rb +38 -57
  149. data/lib/rigor/inference/builtins/hash_catalog.rb +9 -14
  150. data/lib/rigor/inference/builtins/method_catalog.rb +29 -48
  151. data/lib/rigor/inference/builtins/numeric_catalog.rb +13 -18
  152. data/lib/rigor/inference/builtins/pathname_catalog.rb +8 -13
  153. data/lib/rigor/inference/builtins/proc_catalog.rb +38 -62
  154. data/lib/rigor/inference/builtins/random_catalog.rb +21 -32
  155. data/lib/rigor/inference/builtins/range_catalog.rb +12 -21
  156. data/lib/rigor/inference/builtins/rational_catalog.rb +9 -15
  157. data/lib/rigor/inference/builtins/re_catalog.rb +29 -48
  158. data/lib/rigor/inference/builtins/set_catalog.rb +18 -27
  159. data/lib/rigor/inference/builtins/string_catalog.rb +12 -19
  160. data/lib/rigor/inference/builtins/struct_catalog.rb +18 -30
  161. data/lib/rigor/inference/builtins/time_catalog.rb +28 -44
  162. data/lib/rigor/inference/closure_escape_analyzer.rb +44 -67
  163. data/lib/rigor/inference/coverage_scanner.rb +13 -18
  164. data/lib/rigor/inference/def_return_typer.rb +8 -14
  165. data/lib/rigor/inference/dynamic_origin.rb +23 -20
  166. data/lib/rigor/inference/expression_typer.rb +794 -1154
  167. data/lib/rigor/inference/fallback.rb +8 -12
  168. data/lib/rigor/inference/fallback_tracer.rb +4 -10
  169. data/lib/rigor/inference/flow_tracer.rb +25 -36
  170. data/lib/rigor/inference/fork_map.rb +87 -0
  171. data/lib/rigor/inference/hkt_body.rb +45 -68
  172. data/lib/rigor/inference/hkt_body_parser.rb +33 -52
  173. data/lib/rigor/inference/hkt_reducer.rb +38 -59
  174. data/lib/rigor/inference/hkt_registry.rb +50 -76
  175. data/lib/rigor/inference/indexed_narrowing.rb +55 -81
  176. data/lib/rigor/inference/macro_block_self_type.rb +21 -34
  177. data/lib/rigor/inference/method_dispatcher/array_to_h_folding.rb +11 -18
  178. data/lib/rigor/inference/method_dispatcher/block_folding.rb +49 -83
  179. data/lib/rigor/inference/method_dispatcher/call_context.rb +16 -23
  180. data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +13 -22
  181. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +307 -454
  182. data/lib/rigor/inference/method_dispatcher/data_folding.rb +24 -34
  183. data/lib/rigor/inference/method_dispatcher/file_folding.rb +22 -37
  184. data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +52 -81
  185. data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +51 -78
  186. data/lib/rigor/inference/method_dispatcher/literal_string_folding.rb +60 -97
  187. data/lib/rigor/inference/method_dispatcher/math_folding.rb +23 -34
  188. data/lib/rigor/inference/method_dispatcher/member_shape_projection.rb +18 -26
  189. data/lib/rigor/inference/method_dispatcher/method_folding.rb +37 -71
  190. data/lib/rigor/inference/method_dispatcher/overload_selector.rb +114 -182
  191. data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +122 -193
  192. data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +15 -24
  193. data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +64 -93
  194. data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +31 -45
  195. data/lib/rigor/inference/method_dispatcher/set_folding.rb +6 -9
  196. data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +356 -511
  197. data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +22 -32
  198. data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +15 -21
  199. data/lib/rigor/inference/method_dispatcher/struct_folding.rb +66 -82
  200. data/lib/rigor/inference/method_dispatcher/time_folding.rb +10 -15
  201. data/lib/rigor/inference/method_dispatcher/uri_folding.rb +9 -13
  202. data/lib/rigor/inference/method_dispatcher.rb +378 -524
  203. data/lib/rigor/inference/method_parameter_binder.rb +81 -114
  204. data/lib/rigor/inference/multi_target_binder.rb +51 -68
  205. data/lib/rigor/inference/mutation_widening.rb +115 -158
  206. data/lib/rigor/inference/narrowing.rb +627 -727
  207. data/lib/rigor/inference/origin_lookup.rb +38 -0
  208. data/lib/rigor/inference/parameter_inference_collector.rb +154 -109
  209. data/lib/rigor/inference/precision_scanner.rb +26 -35
  210. data/lib/rigor/inference/project_patched_methods.rb +20 -32
  211. data/lib/rigor/inference/project_patched_scanner.rb +23 -37
  212. data/lib/rigor/inference/protection_scanner.rb +16 -18
  213. data/lib/rigor/inference/rbs_type_translator.rb +49 -66
  214. data/lib/rigor/inference/scope_indexer.rb +473 -821
  215. data/lib/rigor/inference/statement_evaluator.rb +754 -1114
  216. data/lib/rigor/inference/struct_fold_safety.rb +34 -48
  217. data/lib/rigor/inference/synthetic_method.rb +9 -16
  218. data/lib/rigor/inference/synthetic_method_index.rb +20 -35
  219. data/lib/rigor/inference/synthetic_method_scanner.rb +63 -103
  220. data/lib/rigor/language_server/buffer_resolution.rb +6 -9
  221. data/lib/rigor/language_server/buffer_table.rb +11 -18
  222. data/lib/rigor/language_server/completion_provider.rb +69 -116
  223. data/lib/rigor/language_server/debouncer.rb +16 -25
  224. data/lib/rigor/language_server/diagnostic_publisher.rb +26 -40
  225. data/lib/rigor/language_server/document_symbol_provider.rb +14 -19
  226. data/lib/rigor/language_server/folding_range_provider.rb +11 -19
  227. data/lib/rigor/language_server/hover_provider.rb +8 -11
  228. data/lib/rigor/language_server/hover_renderer.rb +56 -93
  229. data/lib/rigor/language_server/loop.rb +14 -19
  230. data/lib/rigor/language_server/project_context.rb +46 -74
  231. data/lib/rigor/language_server/selection_range_provider.rb +9 -12
  232. data/lib/rigor/language_server/server.rb +55 -83
  233. data/lib/rigor/language_server/signature_help_provider.rb +29 -46
  234. data/lib/rigor/language_server/synchronized_writer.rb +4 -7
  235. data/lib/rigor/language_server/uri.rb +8 -13
  236. data/lib/rigor/language_server.rb +4 -6
  237. data/lib/rigor/mcp/loop.rb +2 -3
  238. data/lib/rigor/mcp/server.rb +4 -7
  239. data/lib/rigor/mcp.rb +3 -6
  240. data/lib/rigor/plugin/access_denied_error.rb +5 -8
  241. data/lib/rigor/plugin/additional_initializer.rb +21 -31
  242. data/lib/rigor/plugin/base.rb +335 -518
  243. data/lib/rigor/plugin/blueprint.rb +14 -23
  244. data/lib/rigor/plugin/box.rb +18 -29
  245. data/lib/rigor/plugin/fact_store.rb +16 -26
  246. data/lib/rigor/plugin/inflector.rb +37 -53
  247. data/lib/rigor/plugin/io_boundary.rb +33 -56
  248. data/lib/rigor/plugin/isolation.rb +42 -55
  249. data/lib/rigor/plugin/load_error.rb +10 -15
  250. data/lib/rigor/plugin/loader.rb +30 -49
  251. data/lib/rigor/plugin/macro/block_as_method.rb +20 -32
  252. data/lib/rigor/plugin/macro/heredoc_template.rb +35 -58
  253. data/lib/rigor/plugin/macro/nested_class_template.rb +22 -36
  254. data/lib/rigor/plugin/macro/trait_registry.rb +34 -51
  255. data/lib/rigor/plugin/macro.rb +10 -15
  256. data/lib/rigor/plugin/manifest.rb +85 -144
  257. data/lib/rigor/plugin/node_context.rb +14 -22
  258. data/lib/rigor/plugin/node_rule_walk.rb +49 -74
  259. data/lib/rigor/plugin/protocol_contract.rb +25 -39
  260. data/lib/rigor/plugin/registry.rb +132 -205
  261. data/lib/rigor/plugin/services.rb +21 -33
  262. data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -19
  263. data/lib/rigor/plugin/trust_policy.rb +24 -38
  264. data/lib/rigor/plugin/type_node_resolver.rb +15 -24
  265. data/lib/rigor/protection/diagnostic_oracle.rb +11 -13
  266. data/lib/rigor/protection/mutation_scanner.rb +27 -35
  267. data/lib/rigor/protection/mutator.rb +50 -70
  268. data/lib/rigor/protection/test_suite_oracle.rb +20 -27
  269. data/lib/rigor/rbs_extended/conformance_checker.rb +48 -68
  270. data/lib/rigor/rbs_extended/hkt_directives.rb +28 -54
  271. data/lib/rigor/rbs_extended/reporter.rb +24 -40
  272. data/lib/rigor/rbs_extended.rb +107 -197
  273. data/lib/rigor/reflection.rb +68 -86
  274. data/lib/rigor/scope/discovery_index.rb +14 -19
  275. data/lib/rigor/scope.rb +255 -310
  276. data/lib/rigor/sig_gen/classification.rb +6 -10
  277. data/lib/rigor/sig_gen/generator.rb +197 -323
  278. data/lib/rigor/sig_gen/layout_index.rb +12 -20
  279. data/lib/rigor/sig_gen/method_candidate.rb +12 -17
  280. data/lib/rigor/sig_gen/observation_collector.rb +38 -70
  281. data/lib/rigor/sig_gen/observed_call.rb +13 -23
  282. data/lib/rigor/sig_gen/path_mapper.rb +17 -29
  283. data/lib/rigor/sig_gen/renderer.rb +7 -13
  284. data/lib/rigor/sig_gen/type_elaborator.rb +15 -28
  285. data/lib/rigor/sig_gen/write_result.rb +8 -16
  286. data/lib/rigor/sig_gen/writer.rb +95 -174
  287. data/lib/rigor/sig_gen.rb +3 -6
  288. data/lib/rigor/signature_path_audit.rb +24 -30
  289. data/lib/rigor/source/constant_path.rb +10 -14
  290. data/lib/rigor/source/literals.rb +31 -45
  291. data/lib/rigor/source/node_locator.rb +9 -11
  292. data/lib/rigor/source/node_walker.rb +9 -13
  293. data/lib/rigor/source.rb +3 -4
  294. data/lib/rigor/testing.rb +16 -20
  295. data/lib/rigor/triage/catalogue.rb +38 -62
  296. data/lib/rigor/triage.rb +31 -52
  297. data/lib/rigor/trinary.rb +9 -13
  298. data/lib/rigor/type/acceptance_router.rb +4 -6
  299. data/lib/rigor/type/accepts_result.rb +10 -14
  300. data/lib/rigor/type/app.rb +19 -27
  301. data/lib/rigor/type/bot.rb +4 -6
  302. data/lib/rigor/type/bound_method.rb +10 -15
  303. data/lib/rigor/type/combinator.rb +165 -257
  304. data/lib/rigor/type/constant.rb +23 -34
  305. data/lib/rigor/type/data_class.rb +10 -15
  306. data/lib/rigor/type/data_instance.rb +14 -20
  307. data/lib/rigor/type/difference.rb +21 -32
  308. data/lib/rigor/type/dynamic.rb +3 -5
  309. data/lib/rigor/type/hash_shape.rb +32 -18
  310. data/lib/rigor/type/integer_range.rb +11 -16
  311. data/lib/rigor/type/intersection.rb +27 -42
  312. data/lib/rigor/type/nominal.rb +10 -15
  313. data/lib/rigor/type/plain_lattice.rb +9 -13
  314. data/lib/rigor/type/refined.rb +67 -114
  315. data/lib/rigor/type/singleton.rb +4 -6
  316. data/lib/rigor/type/struct_class.rb +11 -16
  317. data/lib/rigor/type/struct_instance.rb +15 -21
  318. data/lib/rigor/type/tuple.rb +14 -19
  319. data/lib/rigor/type/union.rb +30 -42
  320. data/lib/rigor/type_node/generic.rb +14 -26
  321. data/lib/rigor/type_node/identifier.rb +12 -19
  322. data/lib/rigor/type_node.rb +3 -12
  323. data/lib/rigor/value_semantics.rb +16 -21
  324. data/lib/rigor/version.rb +1 -1
  325. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +18 -30
  326. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +16 -29
  327. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +12 -23
  328. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +22 -39
  329. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +26 -46
  330. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +51 -87
  331. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +10 -17
  332. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +26 -39
  333. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +141 -184
  334. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +30 -51
  335. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +57 -92
  336. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +92 -108
  337. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +13 -22
  338. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +15 -25
  339. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +8 -13
  340. data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +16 -24
  341. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +40 -48
  342. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +140 -129
  343. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +56 -59
  344. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +27 -41
  345. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +16 -24
  346. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +172 -0
  347. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +168 -241
  348. data/plugins/rigor-activerecord/lib/rigor-activerecord.rb +3 -5
  349. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +8 -14
  350. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +9 -15
  351. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +4 -7
  352. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +23 -41
  353. data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +3 -5
  354. data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +6 -10
  355. data/plugins/rigor-activesupport-core-ext/lib/rigor-activesupport-core-ext.rb +8 -11
  356. data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +32 -0
  357. data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +30 -45
  358. data/plugins/rigor-devise/lib/rigor-devise.rb +3 -5
  359. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +43 -69
  360. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +26 -35
  361. data/plugins/rigor-dry-schema/lib/rigor-dry-schema.rb +3 -5
  362. data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +30 -47
  363. data/plugins/rigor-dry-struct/lib/rigor-dry-struct.rb +3 -5
  364. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +67 -113
  365. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +29 -46
  366. data/plugins/rigor-dry-types/lib/rigor-dry-types.rb +3 -5
  367. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -20
  368. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +14 -23
  369. data/plugins/rigor-dry-validation/lib/rigor-dry-validation.rb +2 -3
  370. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +22 -37
  371. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +28 -46
  372. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +13 -17
  373. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +30 -47
  374. data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +52 -80
  375. data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +21 -31
  376. data/plugins/rigor-graphql/lib/rigor-graphql.rb +3 -5
  377. data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +11 -17
  378. data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +20 -34
  379. data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +45 -75
  380. data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +22 -36
  381. data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +22 -41
  382. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +17 -32
  383. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +6 -12
  384. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +4 -8
  385. data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +17 -32
  386. data/plugins/rigor-rails/lib/rigor-rails.rb +11 -18
  387. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +58 -92
  388. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +20 -34
  389. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +20 -31
  390. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +49 -82
  391. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +55 -92
  392. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +51 -90
  393. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +17 -30
  394. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/grape_api_discoverer.rb +189 -0
  395. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +38 -70
  396. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +61 -75
  397. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +319 -505
  398. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +91 -96
  399. data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +32 -54
  400. data/plugins/rigor-rbs-inline/lib/rigor-rbs-inline.rb +8 -13
  401. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +9 -16
  402. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +24 -39
  403. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +13 -22
  404. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +34 -56
  405. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/scope_walker.rb +22 -42
  406. data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +43 -75
  407. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +27 -39
  408. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/http_status_codes.rb +14 -19
  409. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +20 -34
  410. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +28 -47
  411. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +21 -37
  412. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +13 -22
  413. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +18 -31
  414. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +6 -10
  415. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +14 -29
  416. data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +23 -41
  417. data/plugins/rigor-sinatra/lib/rigor-sinatra.rb +3 -5
  418. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +23 -38
  419. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +57 -96
  420. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +22 -35
  421. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +41 -69
  422. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb +6 -10
  423. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +24 -41
  424. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +29 -50
  425. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +55 -88
  426. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +159 -262
  427. data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +21 -29
  428. data/plugins/rigor-statesman/lib/rigor-statesman.rb +3 -5
  429. data/plugins/rigor-typescript-utility-types/lib/rigor/plugin/typescript_utility_types.rb +23 -37
  430. data/plugins/rigor-typescript-utility-types/lib/rigor-typescript-utility-types.rb +4 -6
  431. data/sig/rigor/environment.rbs +1 -0
  432. data/sig/rigor/scope.rbs +6 -0
  433. metadata +9 -1
@@ -8,22 +8,17 @@ require_relative "../source/constant_path"
8
8
 
9
9
  module Rigor
10
10
  module Inference
11
- # ADR-17 slice 2 — pre-pass scanner. Walks every file the user
12
- # listed under `pre_eval:` and harvests every `def` /
13
- # `def self.` declaration inside a class / module body into a
14
- # {ProjectPatchedMethods} registry the dispatcher consults
15
- # below the plugin tier.
11
+ # ADR-17 slice 2 — pre-pass scanner. Walks every file the user listed under `pre_eval:` and
12
+ # harvests every `def` / `def self.` declaration inside a class / module body into a
13
+ # {ProjectPatchedMethods} registry the dispatcher consults below the plugin tier.
16
14
  #
17
- # The walker is intentionally a strict subset of
18
- # {Rigor::Inference::ScopeIndexer}'s machinery: it only needs
19
- # `class C; def m; end; end` shape recognition, not full
20
- # inference. Parse errors degrade to a fail-soft `:warning`
21
- # `pre-eval.parse-error` diagnostic accumulated alongside
22
- # the registry; per ADR-17 § "Failure modes" a parse failure
23
- # in a pre-eval file MUST NOT abort the rest of the run.
15
+ # The walker is intentionally a strict subset of {Rigor::Inference::ScopeIndexer}'s machinery: it
16
+ # only needs `class C; def m; end; end` shape recognition, not full inference. Parse errors degrade
17
+ # to a fail-soft `:warning` `pre-eval.parse-error` diagnostic accumulated alongside the registry;
18
+ # per ADR-17 § "Failure modes" a parse failure in a pre-eval file MUST NOT abort the rest of the run.
24
19
  module ProjectPatchedScanner
25
- # Frozen scan outcome carrying the populated registry and
26
- # the per-file warnings the runner emits at run start.
20
+ # Frozen scan outcome carrying the populated registry and the per-file warnings the runner emits
21
+ # at run start.
27
22
  class Result < Data.define(:registry, :diagnostics)
28
23
  def initialize(registry:, diagnostics: [])
29
24
  super(
@@ -35,18 +30,13 @@ module Rigor
35
30
 
36
31
  module_function
37
32
 
38
- # @param paths [Array<String>] absolute paths to the
39
- # pre-eval files. The runner has already validated that
40
- # each path exists (slice-1 `pre-eval.file-not-found`
41
- # `:error` covers missing entries); the scanner does NOT
42
- # re-check existence.
43
- # @param buffer [Rigor::Analysis::BufferBinding, nil]
44
- # editor-mode buffer binding. When set, the scanner reads
45
- # the buffer's physical bytes if a pre-eval entry matches
46
- # the logical path, so users editing a monkey-patch file
47
- # see the in-flight version in their analysis.
48
- # @return [Result] the populated registry plus any
49
- # per-file warnings.
33
+ # @param paths [Array<String>] absolute paths to the pre-eval files. The runner has already
34
+ # validated that each path exists (slice-1 `pre-eval.file-not-found` `:error` covers missing
35
+ # entries); the scanner does NOT re-check existence.
36
+ # @param buffer [Rigor::Analysis::BufferBinding, nil] editor-mode buffer binding. When set, the
37
+ # scanner reads the buffer's physical bytes if a pre-eval entry matches the logical path, so
38
+ # users editing a monkey-patch file see the in-flight version in their analysis.
39
+ # @return [Result] the populated registry plus any per-file warnings.
50
40
  def scan(paths, buffer: nil)
51
41
  entries = []
52
42
  diagnostics = []
@@ -58,13 +48,10 @@ module Rigor
58
48
  )
59
49
  end
60
50
 
61
- # ADR-17 § "Failure modes" — when two pre-eval entries
62
- # declare the same `(class_name, method_name, kind)` triple,
63
- # emit one `:info` `pre-eval.duplicate-declaration`
64
- # diagnostic per collision. The registry's first-write-wins
65
- # behaviour is unchanged; the diagnostic just makes the
66
- # shadowing visible so users notice when a later patch
67
- # is silently masked.
51
+ # ADR-17 § "Failure modes" — when two pre-eval entries declare the same `(class_name, method_name,
52
+ # kind)` triple, emit one `:info` `pre-eval.duplicate-declaration` diagnostic per collision. The
53
+ # registry's first-write-wins behaviour is unchanged; the diagnostic just makes the shadowing
54
+ # visible so users notice when a later patch is silently masked.
68
55
  def duplicate_declaration_diagnostics(entries)
69
56
  seen = {}
70
57
  entries.each_with_object([]) do |entry, acc|
@@ -129,10 +116,9 @@ module Rigor
129
116
  end
130
117
  private_class_method :parse_error_diagnostic
131
118
 
132
- # Builds a diagnostic Hash-shape the runner translates to a
133
- # `Rigor::Analysis::Diagnostic`. The scanner intentionally
134
- # does NOT depend on the analysis layer (it's a pre-pass);
135
- # the runner adapts at the call site.
119
+ # Builds a diagnostic Hash-shape the runner translates to a `Rigor::Analysis::Diagnostic`. The
120
+ # scanner intentionally does NOT depend on the analysis layer (it's a pre-pass); the runner
121
+ # adapts at the call site.
136
122
  def build_diagnostic(path:, line:, column:, severity:, rule:, message:)
137
123
  { path: path, line: line, column: column, severity: severity, rule: rule, message: message }
138
124
  end
@@ -1,22 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "scope_indexer"
4
+ require_relative "origin_lookup"
4
5
  require_relative "../source/node_walker"
5
6
 
6
7
  module Rigor
7
8
  module Inference
8
- # ADR-63 Tier 1 — the static type-protection proxy. Walks every dispatch
9
- # site (a method call with an explicit receiver) and classifies it by
10
- # whether the receiver types to a concrete (non-`Dynamic`) type i.e. a
11
- # site where Rigor's call rules *can* bite (undefined-method / wrong-arity /
12
- # argument-type-mismatch). A `Dynamic` / `Top` receiver (or a union with such
13
- # an arm — gradually valid) is *unprotected*: Rigor is blind there, and a
14
- # type annotation on it would buy real catching power.
9
+ # ADR-63 Tier 1 — the static type-protection proxy. Walks every dispatch site (a method call with an
10
+ # explicit receiver) and classifies it by whether the receiver types to a concrete (non-`Dynamic`)
11
+ # type i.e. a site where Rigor's call rules *can* bite (undefined-method / wrong-arity /
12
+ # argument-type-mismatch). A `Dynamic` / `Top` receiver (or a union with such an arm — gradually
13
+ # valid) is *unprotected*: Rigor is blind there, and a type annotation on it would buy real catching
14
+ # power.
15
15
  #
16
- # This is a sound UPPER BOUND on protection — a concrete receiver is
17
- # necessary but not sufficient for a diagnostic to actually fire — and it is
18
- # one `type_of` pass, so it runs interactively and in CI. The truth tier
19
- # (does a diagnostic fire) is the phased mutation tier.
16
+ # This is a sound UPPER BOUND on protection — a concrete receiver is necessary but not sufficient
17
+ # for a diagnostic to actually fire — and it is one `type_of` pass, so it runs interactively and in
18
+ # CI. The truth tier (does a diagnostic fire) is the phased mutation tier.
20
19
  class ProtectionScanner
21
20
  # A single unprotected call site.
22
21
  Site = Data.define(:line, :receiver, :method_name, :dynamic_origin)
@@ -24,8 +23,8 @@ module Rigor
24
23
  FileResult = Data.define(:protected_count, :unprotected_count, :sites) do
25
24
  def total = protected_count + unprotected_count
26
25
 
27
- # Protected ratio; a file with no dispatch sites is vacuously fully
28
- # protected (nothing to get wrong).
26
+ # Protected ratio; a file with no dispatch sites is vacuously fully protected (nothing to get
27
+ # wrong).
29
28
  def ratio = total.zero? ? 1.0 : protected_count.to_f / total
30
29
  end
31
30
 
@@ -48,7 +47,7 @@ module Rigor
48
47
  if concrete_receiver?(receiver_type)
49
48
  protected_count += 1
50
49
  else
51
- origin = scope.dynamic_origins[node.receiver]
50
+ origin = OriginLookup.origin_for(scope, node.receiver)
52
51
  sites << Site.new(
53
52
  line: node.location.start_line,
54
53
  receiver: safe_describe(receiver_type),
@@ -67,10 +66,9 @@ module Rigor
67
66
  node.is_a?(Prism::CallNode) && !node.receiver.nil?
68
67
  end
69
68
 
70
- # A receiver Rigor can reason about: anything that is not `Dynamic` /
71
- # `Top`, and (for a union) only when every arm is concrete — a single
72
- # `Dynamic` arm makes the whole call gradually valid, so the rules stay
73
- # silent there.
69
+ # A receiver Rigor can reason about: anything that is not `Dynamic` / `Top`, and (for a union)
70
+ # only when every arm is concrete — a single `Dynamic` arm makes the whole call gradually valid,
71
+ # so the rules stay silent there.
74
72
  def concrete_receiver?(type)
75
73
  case type
76
74
  when Type::Dynamic, Type::Top then false
@@ -8,45 +8,37 @@ module Rigor
8
8
  module Inference
9
9
  # Translates `RBS::Types::*` instances into `Rigor::Type` values.
10
10
  #
11
- # Slice 4 phase 2d adds two pieces of generic plumbing:
12
- # - `RBS::Types::ClassInstance` arguments are translated recursively
13
- # so `Array[Integer]` becomes `Nominal["Array", [Nominal["Integer"]]]`
14
- # (and `Hash[Symbol, Integer]` becomes `Nominal["Hash", [...]]`).
15
- # - `RBS::Types::Variable` consults a caller-supplied substitution
16
- # map (`type_vars:`) keyed by the variable's RBS name. When the
17
- # variable is bound, the bound `Rigor::Type` is returned unchanged;
18
- # when it is not bound, the variable degrades to `Dynamic[Top]` so
19
- # uninstantiated generics keep their fail-soft behavior.
11
+ # Generic plumbing:
12
+ # - `RBS::Types::ClassInstance` arguments are translated recursively so `Array[Integer]` becomes
13
+ # `Nominal["Array", [Nominal["Integer"]]]` (and `Hash[Symbol, Integer]` becomes
14
+ # `Nominal["Hash", [...]]`).
15
+ # - `RBS::Types::Variable` consults a caller-supplied substitution map (`type_vars:`) keyed by the
16
+ # variable's RBS name. When the variable is bound, the bound `Rigor::Type` is returned unchanged;
17
+ # when it is not bound, the variable degrades to `Dynamic[Top]` so uninstantiated generics keep
18
+ # their fail-soft behavior.
20
19
  #
21
- # Slice 5 phase 1 maps tuples and records to their dedicated shape
22
- # carriers:
23
- # - `RBS::Types::Tuple` becomes `Rigor::Type::Tuple[...]` so the
24
- # arity and per-position element types survive the boundary.
25
- # - `RBS::Types::Record` becomes an exact closed
26
- # `Rigor::Type::HashShape{...}`, carrying required and optional
27
- # fields intact.
28
- # Element and value types are translated recursively under the
29
- # caller's `self_type` / `instance_type` / `type_vars` context.
20
+ # Shape carriers:
21
+ # - `RBS::Types::Tuple` becomes `Rigor::Type::Tuple[...]` so the arity and per-position element
22
+ # types survive the boundary.
23
+ # - `RBS::Types::Record` becomes an exact closed `Rigor::Type::HashShape{...}`, carrying required
24
+ # and optional fields intact.
25
+ # Element and value types are translated recursively under the caller's `self_type` /
26
+ # `instance_type` / `type_vars` context.
30
27
  #
31
- # Interface and intersection types still degrade to `Dynamic[Top]`;
32
- # they are bound to acceptance and dispatch rules that Slice 5+
33
- # will replace.
28
+ # Interface and intersection types still degrade to `Dynamic[Top]`; they are bound to acceptance
29
+ # and dispatch rules not yet implemented.
34
30
  #
35
- # The optional `self_type:` and `instance_type:` arguments are the
36
- # Rigor counterparts of RBS's `self` and `instance` tokens:
37
- # - `self_type` substitutes for `Bases::Self`. Inside an instance
38
- # method body it is `Nominal[C]`; inside a singleton method body
39
- # it is `Singleton[C]`.
40
- # - `instance_type` substitutes for `Bases::Instance` and is always
41
- # `Nominal[C]` regardless of which method body we are in.
42
- # When either argument is omitted, the corresponding token degrades
43
- # to Dynamic[Top].
31
+ # The optional `self_type:` and `instance_type:` arguments are the Rigor counterparts of RBS's
32
+ # `self` and `instance` tokens:
33
+ # - `self_type` substitutes for `Bases::Self`. Inside an instance method body it is `Nominal[C]`;
34
+ # inside a singleton method body it is `Singleton[C]`.
35
+ # - `instance_type` substitutes for `Bases::Instance` and is always `Nominal[C]` regardless of which
36
+ # method body we are in.
37
+ # When either argument is omitted, the corresponding token degrades to Dynamic[Top].
44
38
  module RbsTypeTranslator
45
- # Hash-based dispatch keeps `translate` linear and dodges the
46
- # bookkeeping costs of a 20-arm `case` (RuboCop AbcSize/CCN/Length
47
- # all spike on that shape). Anonymous RBS-type subclasses are not
48
- # expected; the table only maps the concrete leaf classes shipped
49
- # by the `rbs` gem.
39
+ # Hash-based dispatch keeps `translate` linear and dodges the bookkeeping costs of a 20-arm `case`
40
+ # (RuboCop AbcSize/CCN/Length all spike on that shape). Anonymous RBS-type subclasses are not
41
+ # expected; the table only maps the concrete leaf classes shipped by the `rbs` gem.
50
42
  TRANSLATORS = {
51
43
  RBS::Types::Bases::Top => :translate_top,
52
44
  RBS::Types::Bases::Bottom => :translate_bot,
@@ -78,13 +70,11 @@ module Rigor
78
70
  class << self
79
71
  # @param rbs_type [RBS::Types::Bases::Base, RBS::Types::ClassInstance, ...]
80
72
  # @param self_type [Rigor::Type, nil] substitute for `Bases::Self`.
81
- # @param instance_type [Rigor::Type, nil] substitute for
82
- # `Bases::Instance`. Defaults to `nil`, which degrades to
83
- # Dynamic[Top].
84
- # @param type_vars [Hash{Symbol => Rigor::Type}] substitution map
85
- # for `Bases::Variable`. Keys are the RBS variable names (e.g.,
86
- # `:Elem`); values are Rigor types that replace the variable.
87
- # Variables that are not bound in the map degrade to Dynamic[Top].
73
+ # @param instance_type [Rigor::Type, nil] substitute for `Bases::Instance`. Defaults to `nil`,
74
+ # which degrades to Dynamic[Top].
75
+ # @param type_vars [Hash{Symbol => Rigor::Type}] substitution map for `Bases::Variable`. Keys
76
+ # are the RBS variable names (e.g., `:Elem`); values are Rigor types that replace the
77
+ # variable. Variables that are not bound in the map degrade to Dynamic[Top].
88
78
  # @return [Rigor::Type]
89
79
  def translate(rbs_type, self_type: nil, instance_type: nil, type_vars: EMPTY_TYPE_VARS)
90
80
  handler = TRANSLATORS[rbs_type.class]
@@ -111,10 +101,9 @@ module Rigor
111
101
  Type::Combinator.constant_of(nil)
112
102
  end
113
103
 
114
- # `bool` in RBS denotes `true | false`. We fold it to that union
115
- # eagerly so downstream comparisons (e.g., `result == Constant[true]`)
116
- # remain structural. Memoized at the module level because the
117
- # union is value-equal across calls.
104
+ # `bool` in RBS denotes `true | false`. We fold it to that union eagerly so downstream
105
+ # comparisons (e.g., `result == Constant[true]`) remain structural. Memoized at the module
106
+ # level because the union is value-equal across calls.
118
107
  def translate_bool(_rbs_type, _self_type, _instance_type, _type_vars)
119
108
  BOOL_UNION
120
109
  end
@@ -149,10 +138,9 @@ module Rigor
149
138
  Type::Combinator.constant_of(rbs_type.literal)
150
139
  end
151
140
 
152
- # Slice 4 phase 2d translates the type arguments recursively so
153
- # `Array[Integer]` round-trips into `Nominal["Array", [Nominal["Integer"]]]`.
154
- # Variables inside the args participate in substitution through
155
- # the same `type_vars:` map.
141
+ # Translates the type arguments recursively so `Array[Integer]` round-trips into
142
+ # `Nominal["Array", [Nominal["Integer"]]]`. Variables inside the args participate in
143
+ # substitution through the same `type_vars:` map.
156
144
  def translate_class_instance(rbs_type, self_type, instance_type, type_vars)
157
145
  name = rbs_type.name.relative!.to_s
158
146
  translated_args = rbs_type.args.map do |arg|
@@ -161,10 +149,9 @@ module Rigor
161
149
  Type::Combinator.nominal_of(name, type_args: translated_args)
162
150
  end
163
151
 
164
- # Slice 5 phase 1: preserve tuple precision through the
165
- # boundary. Each positional element type is translated
166
- # recursively under the caller's substitution context, and the
167
- # resulting list is wrapped in a `Rigor::Type::Tuple`.
152
+ # Preserves tuple precision through the boundary. Each positional element type is translated
153
+ # recursively under the caller's substitution context, and the resulting list is wrapped in a
154
+ # `Rigor::Type::Tuple`.
168
155
  def translate_tuple(rbs_type, self_type, instance_type, type_vars)
169
156
  elements = rbs_type.types.map do |t|
170
157
  translate(t, self_type: self_type, instance_type: instance_type, type_vars: type_vars)
@@ -172,10 +159,9 @@ module Rigor
172
159
  Type::Combinator.tuple_of(*elements)
173
160
  end
174
161
 
175
- # Slice 5: preserve hash-record precision through the boundary.
176
- # RBS records use Symbol keys; the translator keeps them as
177
- # Symbol keys on the resulting exact closed HashShape so
178
- # erasure can round-trip back to `{ a: T, ?b: U }` syntax.
162
+ # Preserves hash-record precision through the boundary. RBS records use Symbol keys; the
163
+ # translator keeps them as Symbol keys on the resulting exact closed HashShape so erasure can
164
+ # round-trip back to `{ a: T, ?b: U }` syntax.
179
165
  def translate_record(rbs_type, self_type, instance_type, type_vars)
180
166
  pairs = rbs_type.fields.each_with_object({}) do |(key, value), acc|
181
167
  acc[key] = translate(value, self_type: self_type, instance_type: instance_type, type_vars: type_vars)
@@ -195,19 +181,16 @@ module Rigor
195
181
  Type::Combinator.nominal_of(Proc)
196
182
  end
197
183
 
198
- # `singleton(Foo)` is the type of the constant `Foo` itself
199
- # (the class object). With the dedicated Singleton type added in
200
- # Slice 4 phase 2b, we map directly to `Singleton[Foo]`.
184
+ # `singleton(Foo)` is the type of the constant `Foo` itself (the class object). With the
185
+ # dedicated Singleton type, we map directly to `Singleton[Foo]`.
201
186
  def translate_class_singleton(rbs_type, _self_type, _instance_type, _type_vars)
202
187
  name = rbs_type.name.relative!.to_s
203
188
  Type::Combinator.singleton_of(name)
204
189
  end
205
190
 
206
- # Slice 4 phase 2d. Looks up the variable's RBS name in the
207
- # substitution map; bound variables are replaced inline, free
208
- # variables degrade to Dynamic[Top]. We use `fetch` with a
209
- # default rather than `[]` so a deliberate `nil` binding (a
210
- # caller mistake) is never silently consumed.
191
+ # Looks up the variable's RBS name in the substitution map; bound variables are replaced
192
+ # inline, free variables degrade to Dynamic[Top]. We use `fetch` with a default rather than
193
+ # `[]` so a deliberate `nil` binding (a caller mistake) is never silently consumed.
211
194
  def translate_variable(rbs_type, _self_type, _instance_type, type_vars)
212
195
  type_vars.fetch(rbs_type.name) { Type::Combinator.untyped }
213
196
  end