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
@@ -21,36 +21,28 @@ require_relative "type_node/name_scope"
21
21
  require_relative "type_node/resolver_chain"
22
22
 
23
23
  module Rigor
24
- # The engine's view of the type universe outside the current scope.
25
- # Slice 1 exposed only the class registry; Slice 4 added the RBS loader,
26
- # which threads through ExpressionTyper and MethodDispatcher to type
27
- # constant references and method calls that the literal-typer and
28
- # constant-folding tiers cannot answer.
24
+ # The engine's view of the type universe outside the current scope. Slice 1 exposed only the class
25
+ # registry; Slice 4 added the RBS loader, which threads through ExpressionTyper and MethodDispatcher to
26
+ # type constant references and method calls that the literal-typer and constant-folding tiers cannot
27
+ # answer.
29
28
  #
30
29
  # See docs/internal-spec/inference-engine.md for the binding contract.
31
30
  class Environment # rubocop:disable Metrics/ClassLength
32
31
  DEFAULT_PROJECT_SIG_DIR = "sig"
33
32
  private_constant :DEFAULT_PROJECT_SIG_DIR
34
33
 
35
- # Slice A stdlib expansion. Stdlib libraries that
36
- # `Environment.for_project` loads on top of RBS core unless
37
- # the caller passes an explicit `libraries:` array. Each
38
- # entry MUST be a stdlib library name accepted by
39
- # `RBS::EnvironmentLoader#has_library?`; unknown libraries
40
- # MUST fail-soft (`RbsLoader#build_env` already filters
41
- # through `has_library?`). The default set covers the common
42
- # stdlib surface a Ruby program is likely to import
43
- # (`pathname`, `optparse`, `json`, `yaml`, `fileutils`,
44
- # `tempfile`, `uri`, `logger`, `date`) plus the analyzer-
45
- # adjacent gems shipping their own RBS in this bundle
46
- # (`prism`, `rbs`). On hosts where one of these libraries is
47
- # not installed, the loader silently drops it.
34
+ # Slice A stdlib expansion. Stdlib libraries that `Environment.for_project` loads on top of RBS core
35
+ # unless the caller passes an explicit `libraries:` array. Each entry MUST be a stdlib library name
36
+ # accepted by `RBS::EnvironmentLoader#has_library?`; unknown libraries MUST fail-soft
37
+ # (`RbsLoader#build_env` already filters through `has_library?`). The default set covers the common
38
+ # stdlib surface a Ruby program is likely to import (`pathname`, `optparse`, `json`, `yaml`, `fileutils`,
39
+ # `tempfile`, `uri`, `logger`, `date`) plus the analyzer-adjacent gems shipping their own RBS in this
40
+ # bundle (`prism`, `rbs`). On hosts where one of these libraries is not installed, the loader silently
41
+ # drops it.
48
42
  #
49
- # Callers MAY add to the default by passing
50
- # `libraries: %w[csv ...]`; the explicit list is appended to
51
- # `DEFAULT_LIBRARIES` and de-duplicated. Callers that need
52
- # a strictly RBS-core view MUST construct an `RbsLoader`
53
- # directly instead of going through `for_project`.
43
+ # Callers MAY add to the default by passing `libraries: %w[csv ...]`; the explicit list is appended to
44
+ # `DEFAULT_LIBRARIES` and de-duplicated. Callers that need a strictly RBS-core view MUST construct an
45
+ # `RbsLoader` directly instead of going through `for_project`.
54
46
  DEFAULT_LIBRARIES = %w[
55
47
  pathname optparse json yaml fileutils tempfile tmpdir
56
48
  stringio forwardable digest securerandom
@@ -65,11 +57,10 @@ module Rigor
65
57
  prism rbs
66
58
  ].freeze
67
59
 
68
- # ADR-72 — a Gemfile.lock gem name mapped to the opt-in plugin id
69
- # that ships the SAME core-ext RBS. When that plugin is loaded the
70
- # auto-overlay for the gem stands down, so the two never both
71
- # declare the methods (which would raise a duplicate-declaration
72
- # error). Keyed on the gem name `RbsCoverageReport` reports.
60
+ # ADR-72 — a Gemfile.lock gem name mapped to the opt-in plugin id that ships the SAME core-ext RBS. When
61
+ # that plugin is loaded the auto-overlay for the gem stands down, so the two never both declare the
62
+ # methods (which would raise a duplicate-declaration error). Keyed on the gem name `RbsCoverageReport`
63
+ # reports.
73
64
  GEM_OVERLAY_PLUGIN_IDS = { "activesupport" => "activesupport-core-ext" }.freeze
74
65
 
75
66
  attr_reader :class_registry, :rbs_loader, :plugin_registry, :dependency_source_index,
@@ -77,24 +68,17 @@ module Rigor
77
68
  :synthetic_method_index, :project_patched_methods
78
69
 
79
70
  # @param class_registry [Rigor::Environment::ClassRegistry]
80
- # @param rbs_loader [Rigor::Environment::RbsLoader, nil] when nil the
81
- # environment is "RBS-blind"; useful in tests that want to assert
82
- # how the engine behaves without RBS data. The default Environment
83
- # wires the shared core loader, which is itself lazy: requesting an
84
- # environment instance does NOT load RBS until a method or class
85
- # query actually consults the loader.
86
- # @param plugin_registry [Rigor::Plugin::Registry, nil] v0.1.1
87
- # Track 2 slice 7. The per-run plugin registry the
88
- # inference engine consults at call sites for plugin
89
- # `dynamic_return` rules. When nil (the
90
- # default), no plugin-level return-type contribution
91
- # participates — useful for tests, the `Environment.default`
92
- # facade, and analyses that don't load plugins.
93
- # @param dependency_source_index [Rigor::Analysis::DependencySourceInference::Index, nil]
94
- # ADR-10 slice 2b-ii. The per-run index of opt-in gem
95
- # sources the dispatcher consults BELOW RBS dispatch.
96
- # When nil (the default), no dep-source contribution
97
- # participates and the dispatcher tier is a no-op.
71
+ # @param rbs_loader [Rigor::Environment::RbsLoader, nil] when nil the environment is "RBS-blind"; useful
72
+ # in tests that want to assert how the engine behaves without RBS data. The default Environment wires
73
+ # the shared core loader, which is itself lazy: requesting an environment instance does NOT load RBS
74
+ # until a method or class query actually consults the loader.
75
+ # @param plugin_registry [Rigor::Plugin::Registry, nil] v0.1.1 Track 2 slice 7. The per-run plugin
76
+ # registry the inference engine consults at call sites for plugin `dynamic_return` rules. When nil
77
+ # (the default), no plugin-level return-type contribution participates — useful for tests, the
78
+ # `Environment.default` facade, and analyses that don't load plugins.
79
+ # @param dependency_source_index [Rigor::Analysis::DependencySourceInference::Index, nil] ADR-10 slice
80
+ # 2b-ii. The per-run index of opt-in gem sources the dispatcher consults BELOW RBS dispatch. When nil
81
+ # (the default), no dep-source contribution participates and the dispatcher tier is a no-op.
98
82
  def initialize(class_registry: ClassRegistry.default, rbs_loader: nil, # rubocop:disable Metrics/ParameterLists
99
83
  plugin_registry: nil, dependency_source_index: nil,
100
84
  rbs_extended_reporter: nil, boundary_cross_reporter: nil,
@@ -105,11 +89,9 @@ module Rigor
105
89
  @rbs_loader = rbs_loader
106
90
  @plugin_registry = plugin_registry
107
91
  @dependency_source_index = dependency_source_index
108
- # ADR-pending — reporters live in a mutable container so
109
- # long-lived integrations (LSP `ProjectContext`) can swap
110
- # them per `Runner.run` without rebuilding the env. The
111
- # existing `#rbs_extended_reporter` / `#boundary_cross_reporter`
112
- # accessors below preserve the public lookup shape.
92
+ # ADR-pending — reporters live in a mutable container so long-lived integrations (LSP `ProjectContext`)
93
+ # can swap them per `Runner.run` without rebuilding the env. The existing `#rbs_extended_reporter` /
94
+ # `#boundary_cross_reporter` accessors below preserve the public lookup shape.
113
95
  @reporters = Reporters.new(
114
96
  rbs_extended: rbs_extended_reporter,
115
97
  boundary_cross: boundary_cross_reporter,
@@ -117,19 +99,13 @@ module Rigor
117
99
  )
118
100
  @synthetic_method_index = synthetic_method_index || Inference::SyntheticMethodIndex::EMPTY
119
101
  @project_patched_methods = project_patched_methods || Inference::ProjectPatchedMethods::EMPTY
120
- # ADR-20 slice 2c + 2e — the per-env HKT registry
121
- # consulted by the reducer when resolving `Type::App`
122
- # carriers. Defaults to {Inference::HktRegistry::EMPTY};
123
- # the {.default} / {.for_project} class methods seed it
124
- # with the bundled builtins (`json::value`, …) plus any
125
- # `%a{rigor:v1:hkt_register / hkt_define}` annotations
126
- # the RBS loader exposes. The hkt_registry getter
127
- # (defined below) MEMOIZES the result of merging the
128
- # base with the RBS scan so the scan is paid at most
129
- # once per Environment lifetime — and only when first
130
- # consulted, leaving fast paths like `rigor check
131
- # --cache-stats --no-stats` from doing the RBS env
132
- # build at all.
102
+ # ADR-20 slice 2c + 2e — the per-env HKT registry consulted by the reducer when resolving `Type::App`
103
+ # carriers. Defaults to {Inference::HktRegistry::EMPTY}; the {.default} / {.for_project} class methods
104
+ # seed it with the bundled builtins (`json::value`, …) plus any `%a{rigor:v1:hkt_register /
105
+ # hkt_define}` annotations the RBS loader exposes. The hkt_registry getter (defined below) MEMOIZES
106
+ # the result of merging the base with the RBS scan so the scan is paid at most once per Environment
107
+ # lifetime and only when first consulted, leaving fast paths like `rigor check --cache-stats
108
+ # --no-stats` from doing the RBS env build at all.
133
109
  @hkt_registry_base = hkt_registry || Inference::HktRegistry::EMPTY
134
110
  @hkt_registry_holder = HktRegistryHolder.new
135
111
  @constant_type_cache = ConstantTypeCacheHolder.new
@@ -137,14 +113,10 @@ module Rigor
137
113
  freeze
138
114
  end
139
115
 
140
- # ADR-20 slices 2e + 6 — lazy HKT registry getter.
141
- # Merge order on first call: builtins (base) plugin
142
- # manifest aggregation RBS env scan. Last-write-wins on
143
- # URI collisions so user-authored `.rbs` overlays beat
144
- # plugin entries, which beat the bundled JSON_VALUE.
145
- # Memoised; single-threaded use only (under the Ractor
146
- # pool path each worker has its own Environment so
147
- # cross-worker mutation is impossible; the LSP
116
+ # ADR-20 slices 2e + 6 — lazy HKT registry getter. Merge order on first call: builtins (base) ← plugin
117
+ # manifest aggregation ← RBS env scan. Last-write-wins on URI collisions so user-authored `.rbs` overlays
118
+ # beat plugin entries, which beat the bundled JSON_VALUE. Memoised; single-threaded use only (under the
119
+ # Ractor pool path each worker has its own Environment so cross-worker mutation is impossible; the LSP
148
120
  # single-publish-at-a-time invariant serialises here).
149
121
  def hkt_registry
150
122
  @hkt_registry_holder.fetch do
@@ -161,10 +133,9 @@ module Rigor
161
133
  end
162
134
  end
163
135
 
164
- # Backwards-compatible reporter accessors — every existing
165
- # consumer (rbs_extended, method_dispatcher) calls these. The
166
- # frozen `@reporters` container is mutable for slot reassignment
167
- # via {#attach_reporters!} below.
136
+ # Backwards-compatible reporter accessors — every existing consumer (rbs_extended, method_dispatcher)
137
+ # calls these. The frozen `@reporters` container is mutable for slot reassignment via
138
+ # {#attach_reporters!} below.
168
139
  def rbs_extended_reporter
169
140
  @reporters.rbs_extended
170
141
  end
@@ -173,29 +144,22 @@ module Rigor
173
144
  @reporters.boundary_cross
174
145
  end
175
146
 
176
- # ADR-32 WD6 — the per-run accumulator for synthesizer
177
- # failure events. `Environment.for_project` records
178
- # `[:error, message]` returns from a plugin's
179
- # `source_rbs_synthesizer` here so the Runner can emit
180
- # `source-rbs-synthesis-failed` `:info` diagnostics after
181
- # analysis completes. Nil when no plugin contributes a
182
- # synthesizer.
147
+ # ADR-32 WD6 — the per-run accumulator for synthesizer failure events. `Environment.for_project` records
148
+ # `[:error, message]` returns from a plugin's `source_rbs_synthesizer` here so the Runner can emit
149
+ # `source-rbs-synthesis-failed` `:info` diagnostics after analysis completes. Nil when no plugin
150
+ # contributes a synthesizer.
183
151
  def source_rbs_synthesis_reporter
184
152
  @reporters.source_rbs_synthesis
185
153
  end
186
154
 
187
- # Replaces the env's per-run reporter slots. Intended for
188
- # long-lived integrations (LSP `ProjectContext`) that share one
189
- # Environment instance across many `Runner.run` calls: each call
190
- # attaches its own fresh reporter pair so per-call diagnostic
191
- # events stay scoped to that call rather than accumulating
192
- # across publishes.
155
+ # Replaces the env's per-run reporter slots. Intended for long-lived integrations (LSP `ProjectContext`)
156
+ # that share one Environment instance across many `Runner.run` calls: each call attaches its own fresh
157
+ # reporter pair so per-call diagnostic events stay scoped to that call rather than accumulating across
158
+ # publishes.
193
159
  #
194
- # Single-threaded use only. Concurrent publishes against one
195
- # Environment must serialise the LSP `Server` debouncer +
196
- # synchronized writer already enforces this for the editor
197
- # path. The Ractor pool path builds a per-worker Environment
198
- # and does not reach this surface.
160
+ # Single-threaded use only. Concurrent publishes against one Environment must serialise — the LSP
161
+ # `Server` debouncer + synchronized writer already enforces this for the editor path. The Ractor pool
162
+ # path builds a per-worker Environment and does not reach this surface.
199
163
  def attach_reporters!(rbs_extended_reporter:, boundary_cross_reporter:)
200
164
  @reporters.rbs_extended = rbs_extended_reporter
201
165
  @reporters.boundary_cross = boundary_cross_reporter
@@ -210,26 +174,20 @@ module Rigor
210
174
  ).freeze
211
175
  end
212
176
 
213
- # Builds an Environment that consults the project's local
214
- # signatures and any opt-in stdlib libraries on top of RBS core.
177
+ # Builds an Environment that consults the project's local signatures and any opt-in stdlib libraries on
178
+ # top of RBS core.
215
179
  #
216
- # @param root [String, Pathname] project root used to auto-detect
217
- # the default signature path. Defaults to the current working
218
- # directory.
219
- # @param libraries [Array<String, Symbol>] additional stdlib
220
- # libraries to load on top of {DEFAULT_LIBRARIES}. The
221
- # final list is the union of the two, de-duplicated while
222
- # preserving order. Pass an empty array (the default) to
223
- # load only the defaults.
224
- # @param signature_paths [Array<String, Pathname>, nil] explicit
225
- # list of `sig/`-style directories. When `nil` (the default),
226
- # the canonical project layout `<root>/sig` is used if it
227
- # exists, otherwise no signature path is loaded.
228
- # @param cache_store [Rigor::Cache::Store, nil] persistent cache
229
- # threaded into the underlying {Environment::RbsLoader} so
230
- # constant lookups (and, in later v0.0.9 slices, other
231
- # reflection artefacts) consult the cache. Pass `nil` (the
232
- # default) to skip caching for this environment.
180
+ # @param root [String, Pathname] project root used to auto-detect the default signature path. Defaults
181
+ # to the current working directory.
182
+ # @param libraries [Array<String, Symbol>] additional stdlib libraries to load on top of
183
+ # {DEFAULT_LIBRARIES}. The final list is the union of the two, de-duplicated while preserving order.
184
+ # Pass an empty array (the default) to load only the defaults.
185
+ # @param signature_paths [Array<String, Pathname>, nil] explicit list of `sig/`-style directories. When
186
+ # `nil` (the default), the canonical project layout `<root>/sig` is used if it exists, otherwise no
187
+ # signature path is loaded.
188
+ # @param cache_store [Rigor::Cache::Store, nil] persistent cache threaded into the underlying
189
+ # {Environment::RbsLoader} so constant lookups (and, in later v0.0.9 slices, other reflection
190
+ # artefacts) consult the cache. Pass `nil` (the default) to skip caching for this environment.
233
191
  # @return [Rigor::Environment]
234
192
  # rubocop:disable Metrics/MethodLength, Metrics/ParameterLists
235
193
  def for_project(root: Dir.pwd, libraries: [], signature_paths: nil, cache_store: nil,
@@ -242,21 +200,15 @@ module Rigor
242
200
  synthetic_method_index: nil, project_patched_methods: nil,
243
201
  source_files: [])
244
202
  resolved_paths = signature_paths || default_signature_paths(root)
245
- # O4 MVP — append per-gem `sig/` directories discovered
246
- # under the target project's bundler install root. Empty
247
- # array when neither an explicit path nor auto-detection
248
- # finds a bundle. Order: user `signature_paths:` win first
249
- # (semantic precedence inside `RbsLoader.build_env_for`);
250
- # gem-shipped sigs append last so user overrides stay
251
- # authoritative.
203
+ # O4 MVP — append per-gem `sig/` directories discovered under the target project's bundler install
204
+ # root. Empty array when neither an explicit path nor auto-detection finds a bundle. Order: user
205
+ # `signature_paths:` win first (semantic precedence inside `RbsLoader.build_env_for`); gem-shipped
206
+ # sigs append last so user overrides stay authoritative.
252
207
  #
253
- # O4 Layer 3 — when a Gemfile.lock is available (explicit
254
- # `bundler_lockfile:` or auto-detected next to the project
255
- # root), use the locked gem set to filter the discovered
256
- # `sig/` directories. Stale gems in the bundle install
257
- # tree (out-of-band installs, version drift after a
258
- # `bundle update`) are silently dropped so only gems the
259
- # project actually declares contribute RBS.
208
+ # O4 Layer 3 — when a Gemfile.lock is available (explicit `bundler_lockfile:` or auto-detected next
209
+ # to the project root), use the locked gem set to filter the discovered `sig/` directories. Stale
210
+ # gems in the bundle install tree (out-of-band installs, version drift after a `bundle update`) are
211
+ # silently dropped so only gems the project actually declares contribute RBS.
260
212
  locked = LockfileResolver.locked_gems(
261
213
  lockfile_path: bundler_lockfile,
262
214
  project_root: root,
@@ -268,19 +220,13 @@ module Rigor
268
220
  auto_detect: bundler_auto_detect,
269
221
  locked_gems: locked.empty? ? nil : locked
270
222
  ).map(&:to_s)
271
- # O4 Layer 3 slice 2 — when `rbs collection install`
272
- # has been run for the target project, parse the
273
- # resulting `rbs_collection.lock.yaml` and feed each
274
- # gem's `<collection_path>/<name>/<version>/` directory
275
- # into `signature_paths:`. Stdlib-typed entries are
276
- # skipped (already covered by `DEFAULT_LIBRARIES`), as
277
- # are gems whose RBS rigor already loads from another
278
- # source — stdlib-extracted default gems (`cgi`,
279
- # `logger`, …, shipped by the collection under a `git`
280
- # source) and the `data/vendored_gem_sigs/` bundle
281
- # (`redis`, `nokogiri`, `pg`, …). `skip_gem_names:`
282
- # passes both sets so the collection copy doesn't
283
- # double-declare against rigor's bundled RBS (the
223
+ # O4 Layer 3 slice 2 — when `rbs collection install` has been run for the target project, parse the
224
+ # resulting `rbs_collection.lock.yaml` and feed each gem's `<collection_path>/<name>/<version>/`
225
+ # directory into `signature_paths:`. Stdlib-typed entries are skipped (already covered by
226
+ # `DEFAULT_LIBRARIES`), as are gems whose RBS rigor already loads from another source —
227
+ # stdlib-extracted default gems (`cgi`, `logger`, …, shipped by the collection under a `git` source)
228
+ # and the `data/vendored_gem_sigs/` bundle (`redis`, `nokogiri`, `pg`, …). `skip_gem_names:` passes
229
+ # both sets so the collection copy doesn't double-declare against rigor's bundled RBS (the
284
230
  # `RBS::DuplicatedDeclarationError` hazard).
285
231
  merged_libraries = (DEFAULT_LIBRARIES + libraries.map(&:to_s)).uniq
286
232
  skip_gem_names = merged_libraries + RbsLoader.vendored_gem_names
@@ -290,25 +236,18 @@ module Rigor
290
236
  auto_detect: rbs_collection_auto_detect,
291
237
  skip_gem_names: skip_gem_names
292
238
  ).map(&:to_s)
293
- # ADR-25 — RBS signature directories contributed by loaded
294
- # plugins via their manifest `signature_paths:`. Resolved
295
- # to absolute dirs by `Plugin::Base#signature_paths`;
296
- # additive, ranked below the user's explicit
297
- # `signature_paths:` and above the opportunistic bundle /
298
- # collection discovery. A duplicate-declaration conflict
299
- # degrades through the same O7 failure-memo path.
239
+ # ADR-25 — RBS signature directories contributed by loaded plugins via their manifest
240
+ # `signature_paths:`. Resolved to absolute dirs by `Plugin::Base#signature_paths`; additive, ranked
241
+ # below the user's explicit `signature_paths:` and above the opportunistic bundle / collection
242
+ # discovery. A duplicate-declaration conflict degrades through the same O7 failure-memo path.
300
243
  plugin_sig_paths = plugin_registry ? plugin_registry.signature_paths.map(&:to_s) : []
301
- # ADR-72 — Gemfile.lock-gated bundled RBS overlays. For each
302
- # locked gem that ships no RBS through any resolution path
303
- # (`:missing`) and has a Rigor-bundled overlay, load that
304
- # overlay so its core-class extensions resolve (e.g.
305
- # `Integer#minutes` on a Rails project) turning a systematic
306
- # false `call.undefined-method` into a no-op while a project
307
- # WITHOUT the gem still sees the genuine diagnostic. Appended
308
- # last so any RBS the project already supplies wins, and skipped
309
- # for a gem whose opt-in plugin twin is loaded (no duplicate
310
- # declaration). The paths ride in `loader_signature_paths`, so
311
- # the env cache descriptor digests them for free.
244
+ # ADR-72 — Gemfile.lock-gated bundled RBS overlays. For each locked gem that ships no RBS through any
245
+ # resolution path (`:missing`) and has a Rigor-bundled overlay, load that overlay so its core-class
246
+ # extensions resolve (e.g. `Integer#minutes` on a Rails project) turning a systematic false
247
+ # `call.undefined-method` into a no-op while a project WITHOUT the gem still sees the genuine
248
+ # diagnostic. Appended last so any RBS the project already supplies wins, and skipped for a gem whose
249
+ # opt-in plugin twin is loaded (no duplicate declaration). The paths ride in
250
+ # `loader_signature_paths`, so the env cache descriptor digests them for free.
312
251
  overlay_paths = gem_overlay_paths(
313
252
  locked: locked, default_libraries: merged_libraries,
314
253
  bundle_sig_paths: gem_sig_paths, rbs_collection_paths: collection_paths,
@@ -316,22 +255,15 @@ module Rigor
316
255
  )
317
256
  loader_signature_paths = resolved_paths + plugin_sig_paths + gem_sig_paths +
318
257
  collection_paths + overlay_paths
319
- # ADR-32 WD4 + WD5 — invoke each loaded plugin's
320
- # `source_rbs_synthesizer` once per project source file
321
- # and collect non-nil `[filename, rbs_source]` pairs.
322
- # The synthesizer-emitting plugin (currently only
323
- # `rigor-rbs-inline`) is responsible for its own
324
- # fail-soft on parse errors per WD6; this loop only
325
- # filters `nil` returns.
258
+ # ADR-32 WD4 + WD5 — invoke each loaded plugin's `source_rbs_synthesizer` once per project source
259
+ # file and collect non-nil `[filename, rbs_source]` pairs. The synthesizer-emitting plugin (currently
260
+ # only `rigor-rbs-inline`) is responsible for its own fail-soft on parse errors per WD6; this loop
261
+ # only filters `nil` returns.
326
262
  #
327
- # When a `cache_store` is supplied, each synthesizer
328
- # invocation is memoised per
329
- # `(file path + content SHA, plugin id + version + config_hash)`
330
- # WD5's cache key so a second run with unchanged
331
- # source skips the rbs-inline parse cost. The empty
332
- # string is the sentinel for "no contribution" so the
333
- # Store (which treats `nil` as cache miss) can persist
334
- # the no-contribution decision too.
263
+ # When a `cache_store` is supplied, each synthesizer invocation is memoised per `(file path + content
264
+ # SHA, plugin id + version + config_hash)` — WD5's cache key — so a second run with unchanged source
265
+ # skips the rbs-inline parse cost. The empty string is the sentinel for "no contribution" so the
266
+ # Store (which treats `nil` as cache miss) can persist the no-contribution decision too.
335
267
  virtual_rbs = collect_virtual_rbs(plugin_registry, source_files, cache_store,
336
268
  source_rbs_synthesis_reporter)
337
269
  loader = RbsLoader.new(
@@ -340,15 +272,11 @@ module Rigor
340
272
  cache_store: cache_store,
341
273
  virtual_rbs: virtual_rbs
342
274
  )
343
- # ADR-20 slice 2c + 2e — seed hkt_registry with the
344
- # bundled builtins. The Environment's `#hkt_registry`
345
- # getter then LAZILY merges in the RBS env scan on
346
- # first call so fast paths that don't consult HKT
347
- # (e.g. `rigor check --cache-stats --no-stats`) don't
348
- # pay the eager env-build cost up front. URI
349
- # collisions let the user-authored overlay win over
350
- # the bundled builtin (last-write-wins per ADR-20
351
- # OQ3 tentative).
275
+ # ADR-20 slice 2c + 2e — seed hkt_registry with the bundled builtins. The Environment's
276
+ # `#hkt_registry` getter then LAZILY merges in the RBS env scan on first call so fast paths that
277
+ # don't consult HKT (e.g. `rigor check --cache-stats --no-stats`) don't pay the eager env-build cost
278
+ # up front. URI collisions let the user-authored overlay win over the bundled builtin
279
+ # (last-write-wins per ADR-20 OQ3 tentative).
352
280
  new(
353
281
  rbs_loader: loader,
354
282
  plugin_registry: plugin_registry,
@@ -370,13 +298,11 @@ module Rigor
370
298
  sig.directory? ? [sig] : []
371
299
  end
372
300
 
373
- # ADR-72 — resolve the bundled RBS overlay directories to load for
374
- # this project. A gem is eligible when it is locked in the
375
- # Gemfile.lock, classified `:missing` by {RbsCoverageReport}
376
- # (no RBS through default-library / vendored / bundle-`sig/` /
377
- # rbs-collection), and its conflicting opt-in plugin (if any) is
378
- # not loaded. Returns `[Pathname]`, deterministically ordered, or
379
- # `[]` when no lockfile / no eligible gem.
301
+ # ADR-72 — resolve the bundled RBS overlay directories to load for this project. A gem is eligible when
302
+ # it is locked in the Gemfile.lock, classified `:missing` by {RbsCoverageReport} (no RBS through
303
+ # default-library / vendored / bundle-`sig/` / rbs-collection), and its conflicting opt-in plugin (if
304
+ # any) is not loaded. Returns `[Pathname]`, deterministically ordered, or `[]` when no lockfile / no
305
+ # eligible gem.
380
306
  def gem_overlay_paths(locked:, default_libraries:, bundle_sig_paths:,
381
307
  rbs_collection_paths:, plugin_registry:)
382
308
  return [] if locked.empty?
@@ -394,27 +320,19 @@ module Rigor
394
320
  RbsLoader.gem_overlay_sig_paths(eligible)
395
321
  end
396
322
 
397
- # ADR-32 WD4 + WD5 — for each project source file, invoke
398
- # every plugin-registered synthesizer once and collect
399
- # non-nil returns. The returned array is `[[virtual_filename,
400
- # rbs_source], ...]`; the loader threads it through to
401
- # `RbsLoader.new(virtual_rbs: ...)`.
323
+ # ADR-32 WD4 + WD5 — for each project source file, invoke every plugin-registered synthesizer once and
324
+ # collect non-nil returns. The returned array is `[[virtual_filename, rbs_source], ...]`; the loader
325
+ # threads it through to `RbsLoader.new(virtual_rbs: ...)`.
402
326
  #
403
- # `virtual_filename` is the source file path prefixed with
404
- # the plugin id so RBS parse errors point back to the
405
- # contributing plugin in their diagnostic location string.
327
+ # `virtual_filename` is the source file path prefixed with the plugin id so RBS parse errors point back
328
+ # to the contributing plugin in their diagnostic location string.
406
329
  #
407
- # When no plugin declares a synthesizer (the common case),
408
- # the registry's `source_rbs_synthesizers` is empty and
409
- # this method short-circuits to `[]` without walking the
410
- # file list.
330
+ # When no plugin declares a synthesizer (the common case), the registry's `source_rbs_synthesizers` is
331
+ # empty and this method short-circuits to `[]` without walking the file list.
411
332
  #
412
- # WD5 — when `cache_store` is supplied, each (file, plugin)
413
- # synthesizer call is memoised through `Cache::Store`. The
414
- # cache key composes the file's content SHA with the
415
- # plugin's `PluginEntry` (id + version + config_hash) so a
416
- # config change or content change invalidates the entry
417
- # automatically.
333
+ # WD5 — when `cache_store` is supplied, each (file, plugin) synthesizer call is memoised through
334
+ # `Cache::Store`. The cache key composes the file's content SHA with the plugin's `PluginEntry` (id +
335
+ # version + config_hash) so a config change or content change invalidates the entry automatically.
418
336
  def collect_virtual_rbs(plugin_registry, source_files, cache_store, reporter)
419
337
  return [] if plugin_registry.nil?
420
338
 
@@ -436,14 +354,10 @@ module Rigor
436
354
  result
437
355
  end
438
356
 
439
- # ADR-32 WD5 — cache wrapper around a single (plugin,
440
- # file) invocation. The cache stores the empty string
441
- # `""` as the "no contribution" sentinel because
442
- # `Cache::Store` treats `nil` as a cache miss. Error
443
- # tuples are stored as the canonical
444
- # `[:error, message_string]` Array so the same wrapper
445
- # short-circuits subsequent runs against unchanged broken
446
- # input.
357
+ # ADR-32 WD5 — cache wrapper around a single (plugin, file) invocation. The cache stores the empty
358
+ # string `""` as the "no contribution" sentinel because `Cache::Store` treats `nil` as a cache miss.
359
+ # Error tuples are stored as the canonical `[:error, message_string]` Array so the same wrapper
360
+ # short-circuits subsequent runs against unchanged broken input.
447
361
  def synthesizer_output_for(plugin, callable, path, cache_store)
448
362
  return invoke_synthesizer_safely(callable, path) if cache_store.nil?
449
363
  return invoke_synthesizer_safely(callable, path) unless File.file?(path)
@@ -456,17 +370,14 @@ module Rigor
456
370
  ) { invoke_synthesizer_safely(callable, path) || "" }
457
371
  end
458
372
 
459
- # ADR-32 WD6 — route a synthesizer return value through
460
- # the per-run failure reporter. The synthesizer's contract
461
- # (declared in `plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb`)
462
- # admits three return shapes:
373
+ # ADR-32 WD6 — route a synthesizer return value through the per-run failure reporter. The
374
+ # synthesizer's contract (declared in
375
+ # `plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb`) admits three return shapes:
463
376
  # - `String` (non-empty) → successful RBS source
464
377
  # - `nil` / `""` → no contribution
465
378
  # - `[:error, message]` → parse failed
466
- # The error tuple is converted into a reporter entry +
467
- # treated as "no contribution" so the analysis pipeline
468
- # continues. Reporter is `nil` for callers that don't care
469
- # (legacy Environment.new, tests).
379
+ # The error tuple is converted into a reporter entry + treated as "no contribution" so the analysis
380
+ # pipeline continues. Reporter is `nil` for callers that don't care (legacy Environment.new, tests).
470
381
  def interpret_synthesizer_outcome(outcome, plugin, path, reporter)
471
382
  return outcome unless outcome.is_a?(Array) && outcome[0] == :error
472
383
 
@@ -495,8 +406,7 @@ module Rigor
495
406
  def synthesizer_input_digest(path)
496
407
  Digest::SHA256.hexdigest(File.binread(path))
497
408
  rescue ::SystemCallError
498
- # Unreadable file → key on the path alone; the
499
- # synthesizer's File.file?/File.read will see the same
409
+ # Unreadable file → key on the path alone; the synthesizer's File.file?/File.read will see the same
500
410
  # failure and return nil.
501
411
  Digest::SHA256.hexdigest(path.to_s)
502
412
  end
@@ -504,23 +414,19 @@ module Rigor
504
414
  def invoke_synthesizer_safely(callable, path)
505
415
  callable.call(path.to_s)
506
416
  rescue StandardError
507
- # WD6 fail-soft — a synthesizer that raises does NOT crash
508
- # analysis. Unlike the `[:error, msg]` return path (which
509
- # the runner surfaces as `source-rbs-synthesis-failed`),
510
- # an unhandled raise is swallowed silently; the
511
- # unexamined-raise channel is deliberately silent per WD6.
417
+ # WD6 fail-soft — a synthesizer that raises does NOT crash analysis. Unlike the `[:error, msg]`
418
+ # return path (which the runner surfaces as `source-rbs-synthesis-failed`), an unhandled raise is
419
+ # swallowed silently; the unexamined-raise channel is deliberately silent per WD6.
512
420
  nil
513
421
  end
514
422
  end
515
423
 
516
- # Resolves a constant name to a Rigor::Type::Nominal (the *instance*
517
- # type carrier). Consults the static class registry first (cheap,
518
- # hardcoded), then falls back to the RBS loader. Returns nil when
519
- # the name is unknown to both.
424
+ # Resolves a constant name to a Rigor::Type::Nominal (the *instance* type carrier). Consults the static
425
+ # class registry first (cheap, hardcoded), then falls back to the RBS loader. Returns nil when the name
426
+ # is unknown to both.
520
427
  #
521
- # NOTE: This is the construction helper for "an instance of class
522
- # `Foo`". For "the class object `Foo` itself" (the value of the
523
- # constant), use {#singleton_for_name} instead.
428
+ # NOTE: This is the construction helper for "an instance of class `Foo`". For "the class object `Foo`
429
+ # itself" (the value of the constant), use {#singleton_for_name} instead.
524
430
  def nominal_for_name(name)
525
431
  registered = class_registry.nominal_for_name(name)
526
432
  return registered if registered
@@ -528,36 +434,29 @@ module Rigor
528
434
  class_known_in_rbs?(name) ? Type::Combinator.nominal_of(name.to_s) : nil
529
435
  end
530
436
 
531
- # Resolves a constant name to a Rigor::Type::Singleton (the *class
532
- # object* carrier). The expression `Foo` evaluates to the class
533
- # object, whose RBS type is `singleton(Foo)` -- this method is the
534
- # corresponding Rigor construction helper.
437
+ # Resolves a constant name to a Rigor::Type::Singleton (the *class object* carrier). The expression `Foo`
438
+ # evaluates to the class object, whose RBS type is `singleton(Foo)` -- this method is the corresponding
439
+ # Rigor construction helper.
535
440
  #
536
- # The lookup uses the same registry/RBS chain as {#nominal_for_name}
537
- # so a class is either known to both queries or to neither.
441
+ # The lookup uses the same registry/RBS chain as {#nominal_for_name} so a class is either known to both
442
+ # queries or to neither.
538
443
  def singleton_for_name(name)
539
444
  return nil unless class_known?(name)
540
445
 
541
446
  Type::Combinator.singleton_of(name.to_s)
542
447
  end
543
448
 
544
- # Slice A constant-value lookup. Returns the translated
545
- # `Rigor::Type` for an RBS-declared **non-class** constant
546
- # (`Rigor::Analysis::FactStore::BUCKETS: Array[Symbol]`,
547
- # `Rigor::Configuration::DEFAULT_PATH: String`, ...) or `nil`
548
- # when no RBS constant declaration covers `name`. This is the
549
- # value-bearing counterpart of {#singleton_for_name}, which
550
- # only resolves names that name a class or module. Callers
551
- # that need to type a `Prism::ConstantReadNode`/
552
- # `Prism::ConstantPathNode` MUST consult {#singleton_for_name}
553
- # first and fall through to this query when the constant is
554
- # not a class.
449
+ # Slice A constant-value lookup. Returns the translated `Rigor::Type` for an RBS-declared **non-class**
450
+ # constant (`Rigor::Analysis::FactStore::BUCKETS: Array[Symbol]`, `Rigor::Configuration::DEFAULT_PATH:
451
+ # String`, ...) or `nil` when no RBS constant declaration covers `name`. This is the value-bearing
452
+ # counterpart of {#singleton_for_name}, which only resolves names that name a class or module. Callers
453
+ # that need to type a `Prism::ConstantReadNode`/ `Prism::ConstantPathNode` MUST consult
454
+ # {#singleton_for_name} first and fall through to this query when the constant is not a class.
555
455
  def constant_for_name(name)
556
456
  return nil if rbs_loader.nil?
557
457
 
558
- # Pure function of `name` for this Environment's lifetime — the
559
- # refinement table and the RBS constant table are both fixed so
560
- # memoise across the lexical-candidate ladder's heavy name reuse.
458
+ # Pure function of `name` for this Environment's lifetime — the refinement table and the RBS constant
459
+ # table are both fixed so memoise across the lexical-candidate ladder's heavy name reuse.
561
460
  key = name.to_s
562
461
  @constant_type_cache.fetch(key) do
563
462
  Builtins::PredefinedConstantRefinements.lookup(key) ||
@@ -565,50 +464,39 @@ module Rigor
565
464
  end
566
465
  end
567
466
 
568
- # Returns true when the constant name is known to either the static
569
- # registry or the RBS loader. Useful for callers that only need a
570
- # presence check without materialising a type carrier.
467
+ # Returns true when the constant name is known to either the static registry or the RBS loader. Useful
468
+ # for callers that only need a presence check without materialising a type carrier.
571
469
  def class_known?(name)
572
470
  return true if class_registry.nominal_for_name(name)
573
471
  return true if class_known_in_rbs?(name)
574
472
 
575
- # ADR-36 nested-class emission — a variant subclass the
576
- # substrate synthesised (e.g. `Shape::Circle` from a
577
- # `variants do variant Circle, Float end` block) is a real
578
- # class for resolution purposes even though no RBS / source
579
- # declares it.
473
+ # ADR-36 nested-class emission — a variant subclass the substrate synthesised (e.g. `Shape::Circle`
474
+ # from a `variants do variant Circle, Float end` block) is a real class for resolution purposes even
475
+ # though no RBS / source declares it.
580
476
  @synthetic_method_index&.knows_class?(name) || false
581
477
  end
582
478
 
583
- # ADR-15 Phase 2b — returns the loader's read-only,
584
- # `Ractor.shareable?` query surface as a frozen
585
- # {Environment::Reflection}. Built lazily on first
586
- # access; subsequent calls return the same instance.
587
- # Returns `nil` when the environment carries no RBS
588
- # loader (test-only `Environment.new` without
479
+ # ADR-15 Phase 2b — returns the loader's read-only, `Ractor.shareable?` query surface as a frozen
480
+ # {Environment::Reflection}. Built lazily on first access; subsequent calls return the same instance.
481
+ # Returns `nil` when the environment carries no RBS loader (test-only `Environment.new` without
589
482
  # `rbs_loader:`).
590
483
  def reflection
591
484
  @rbs_loader&.reflection
592
485
  end
593
486
 
594
- # Returns true when the RBS environment carries the named
595
- # declaration as a Module (not a Class). Used by the
596
- # `user_class_fallback_receiver` tier to detect a module-mixin
597
- # receiver (e.g. `PP::ObjectMixin`) so the dispatcher can route
598
- # unresolved method calls through the `Nominal[Object]`
599
- # fallback — every concrete includer of M honours Kernel /
600
- # Object instance methods through its own ancestor chain.
487
+ # Returns true when the RBS environment carries the named declaration as a Module (not a Class). Used by
488
+ # the `user_class_fallback_receiver` tier to detect a module-mixin receiver (e.g. `PP::ObjectMixin`) so
489
+ # the dispatcher can route unresolved method calls through the `Nominal[Object]` fallback every
490
+ # concrete includer of M honours Kernel / Object instance methods through its own ancestor chain.
601
491
  def rbs_module?(name)
602
492
  return false unless rbs_loader
603
493
 
604
494
  rbs_loader.rbs_module?(name)
605
495
  end
606
496
 
607
- # Compares two class/module names using analyzer-owned class data.
608
- # Returns `:equal`, `:subclass`, `:superclass`, `:disjoint`, or
609
- # `:unknown`. The static registry handles built-ins cheaply; the RBS
610
- # loader handles project/stdlib classes without relying on host Ruby
611
- # constants being loaded.
497
+ # Compares two class/module names using analyzer-owned class data. Returns `:equal`, `:subclass`,
498
+ # `:superclass`, `:disjoint`, or `:unknown`. The static registry handles built-ins cheaply; the RBS
499
+ # loader handles project/stdlib classes without relying on host Ruby constants being loaded.
612
500
  def class_ordering(lhs, rhs)
613
501
  lhs = normalize_class_name(lhs)
614
502
  rhs = normalize_class_name(rhs)
@@ -634,14 +522,11 @@ module Rigor
634
522
  name.to_s.delete_prefix("::")
635
523
  end
636
524
 
637
- # ADR-13 slice 3b — composes the per-run plugin-supplied
638
- # {Rigor::TypeNode::ResolverChain} into a single
639
- # {Rigor::TypeNode::NameScope} that the RBS::Extended
640
- # directive parser threads down to the
641
- # {Rigor::Builtins::ImportedRefinements::Resolver}. Returns
642
- # `nil` when no plugin contributes a type-node resolver so
643
- # the parser short-circuits the chain consultation and
644
- # behaves bit-for-bit like the v0.1.0 → v0.1.3 default.
525
+ # ADR-13 slice 3b — composes the per-run plugin-supplied {Rigor::TypeNode::ResolverChain} into a single
526
+ # {Rigor::TypeNode::NameScope} that the RBS::Extended directive parser threads down to the
527
+ # {Rigor::Builtins::ImportedRefinements::Resolver}. Returns `nil` when no plugin contributes a type-node
528
+ # resolver so the parser short-circuits the chain consultation and behaves bit-for-bit like the v0.1.0 →
529
+ # v0.1.3 default.
645
530
  def build_name_scope
646
531
  return nil if @plugin_registry.nil? || @plugin_registry.empty?
647
532