rigortype 0.3.8 → 0.4.0

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 (634) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/data/capability_roles/capability_roles.rbs +36 -0
  4. data/data/core_overlay/enumerable.rbs +51 -0
  5. data/data/core_overlay/enumerator.rbs +84 -0
  6. data/data/core_overlay/hash_rbs3.rbs +41 -0
  7. data/data/core_overlay/process.rbs +40 -0
  8. data/data/core_overlay/string_io.rbs +33 -0
  9. data/data/effects/core.yml +3 -3
  10. data/data/gem_overlay/activesupport/core_ext.rbs +236 -17
  11. data/docs/handbook/02-everyday-types.md +17 -14
  12. data/docs/handbook/03-narrowing.md +132 -14
  13. data/docs/handbook/04-tuples-and-shapes.md +8 -6
  14. data/docs/handbook/05-methods-and-blocks.md +1 -1
  15. data/docs/handbook/06-classes.md +2 -2
  16. data/docs/handbook/07-rbs-and-extended.md +19 -1
  17. data/docs/handbook/10-sorbet.md +9 -10
  18. data/docs/handbook/11-sig-gen.md +525 -13
  19. data/docs/handbook/README.md +1 -1
  20. data/docs/handbook/appendix-elixir.md +2 -2
  21. data/docs/handbook/appendix-go.md +2 -2
  22. data/docs/handbook/appendix-java-csharp.md +2 -2
  23. data/docs/handbook/appendix-mypy.md +2 -2
  24. data/docs/handbook/appendix-phpstan.md +1 -1
  25. data/docs/handbook/appendix-rust.md +1 -1
  26. data/docs/handbook/appendix-type-theory.md +4 -4
  27. data/docs/handbook/appendix-typescript.md +1 -1
  28. data/docs/llms.txt +2 -0
  29. data/docs/manual/02-cli-reference.md +95 -6
  30. data/docs/manual/03-configuration.md +18 -0
  31. data/docs/manual/04-diagnostics.md +15 -0
  32. data/docs/manual/07-plugins.md +15 -5
  33. data/docs/manual/08-skills.md +23 -2
  34. data/docs/manual/10-mcp-server.md +3 -2
  35. data/docs/manual/11-ci.md +9 -0
  36. data/docs/manual/15-type-protection-coverage.md +8 -0
  37. data/docs/manual/16-rbs-extended-annotations.md +46 -8
  38. data/docs/manual/18-removing-dead-code.md +10 -8
  39. data/docs/manual/19-effect-labels.md +10 -0
  40. data/docs/manual/plugins/README.md +7 -0
  41. data/docs/manual/plugins/rigor-actioncable.md +8 -1
  42. data/docs/manual/plugins/rigor-actionmailer.md +7 -0
  43. data/docs/manual/plugins/rigor-actionpack.md +261 -0
  44. data/docs/manual/plugins/rigor-active-model-serializers.md +153 -0
  45. data/docs/manual/plugins/rigor-activejob.md +7 -0
  46. data/docs/manual/plugins/rigor-activerecord.md +138 -4
  47. data/docs/manual/plugins/rigor-activestorage.md +8 -1
  48. data/docs/manual/plugins/rigor-activesupport-core-ext.md +43 -7
  49. data/docs/manual/plugins/rigor-grape.md +106 -0
  50. data/docs/manual/plugins/rigor-graphql.md +23 -2
  51. data/docs/manual/plugins/rigor-pundit.md +8 -1
  52. data/docs/manual/plugins/rigor-rails-i18n.md +10 -5
  53. data/docs/manual/plugins/rigor-rails-routes.md +7 -0
  54. data/docs/manual/plugins/rigor-rbs-inline.md +229 -1
  55. data/docs/manual/plugins/rigor-sidekiq.md +8 -1
  56. data/docs/manual/plugins/rigor-sorbet.md +21 -5
  57. data/exe/rigor +19 -4
  58. data/lib/rigor/analysis/baseline.rb +3 -3
  59. data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +1 -1
  60. data/lib/rigor/analysis/check_rules/dead_version_guard_arms.rb +1 -5
  61. data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +167 -2
  62. data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +10 -2
  63. data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +189 -0
  64. data/lib/rigor/analysis/check_rules/main_pass_collector.rb +6 -4
  65. data/lib/rigor/analysis/check_rules/published_constant_guard.rb +15 -6
  66. data/lib/rigor/analysis/check_rules/rule_ids.rb +21 -6
  67. data/lib/rigor/analysis/check_rules/rule_walk.rb +41 -5
  68. data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +1 -1
  69. data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +1 -1
  70. data/lib/rigor/analysis/check_rules/source_arity.rb +323 -0
  71. data/lib/rigor/analysis/check_rules/special_global_setters.rb +146 -0
  72. data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +38 -4
  73. data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +0 -1
  74. data/lib/rigor/analysis/check_rules.rb +718 -79
  75. data/lib/rigor/analysis/crash_signature.rb +8 -24
  76. data/lib/rigor/analysis/dependency_recorder.rb +23 -0
  77. data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +1 -1
  78. data/lib/rigor/analysis/dependency_source_inference/builder.rb +0 -2
  79. data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +0 -2
  80. data/lib/rigor/analysis/dependency_source_inference/index.rb +5 -5
  81. data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +1 -2
  82. data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
  83. data/lib/rigor/analysis/effects_cache_probe.rb +3 -4
  84. data/lib/rigor/analysis/erb_template_detector.rb +1 -2
  85. data/lib/rigor/analysis/fact_store.rb +15 -1
  86. data/lib/rigor/analysis/incremental.rb +42 -0
  87. data/lib/rigor/analysis/incremental_session.rb +117 -26
  88. data/lib/rigor/analysis/plugin_fact_fingerprint.rb +0 -1
  89. data/lib/rigor/analysis/project_scan.rb +11 -1
  90. data/lib/rigor/analysis/reachability/graph.rb +3 -5
  91. data/lib/rigor/analysis/reachability/plugin_roots.rb +5 -5
  92. data/lib/rigor/analysis/reachability/project_files.rb +2 -2
  93. data/lib/rigor/analysis/reachability/scan.rb +5 -5
  94. data/lib/rigor/analysis/reachability/scan_cache.rb +3 -2
  95. data/lib/rigor/analysis/reachability/signature_scan.rb +2 -2
  96. data/lib/rigor/analysis/result.rb +1 -3
  97. data/lib/rigor/analysis/rule_catalog.rb +131 -1
  98. data/lib/rigor/analysis/run_cache_key.rb +21 -12
  99. data/lib/rigor/analysis/run_cache_probe.rb +3 -5
  100. data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +6 -8
  101. data/lib/rigor/analysis/runner/declaration_position.rb +1 -2
  102. data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +340 -33
  103. data/lib/rigor/analysis/runner/effect_annotation_residual_pass.rb +2 -3
  104. data/lib/rigor/analysis/runner/effect_envelope_pass.rb +18 -14
  105. data/lib/rigor/analysis/runner/pool_coordinator.rb +357 -97
  106. data/lib/rigor/analysis/runner/project_pre_passes.rb +38 -13
  107. data/lib/rigor/analysis/runner/run_snapshots.rb +6 -1
  108. data/lib/rigor/analysis/runner.rb +407 -51
  109. data/lib/rigor/analysis/template_unit_collector.rb +303 -0
  110. data/lib/rigor/analysis/template_unit_paths.rb +91 -0
  111. data/lib/rigor/analysis/template_unit_positions.rb +293 -0
  112. data/lib/rigor/analysis/template_units.rb +399 -0
  113. data/lib/rigor/analysis/worker_session.rb +62 -20
  114. data/lib/rigor/bleeding_edge.rb +10 -24
  115. data/lib/rigor/builtins/hkt_builtins.rb +3 -2
  116. data/lib/rigor/builtins/imported_refinements.rb +159 -21
  117. data/lib/rigor/builtins/predefined_constant_refinements.rb +5 -7
  118. data/lib/rigor/builtins/regex_refinement.rb +21 -13
  119. data/lib/rigor/builtins/static_return_refinements.rb +7 -6
  120. data/lib/rigor/cache/annotation_location.rb +2 -4
  121. data/lib/rigor/cache/descriptor.rb +63 -20
  122. data/lib/rigor/cache/engine_source.rb +33 -5
  123. data/lib/rigor/cache/file_digest.rb +9 -1
  124. data/lib/rigor/cache/incremental_snapshot.rb +72 -6
  125. data/lib/rigor/cache/rbs_cache_producer.rb +4 -0
  126. data/lib/rigor/cache/rbs_class_ancestor_table.rb +0 -3
  127. data/lib/rigor/cache/rbs_class_type_param_names.rb +0 -3
  128. data/lib/rigor/cache/rbs_constant_table.rb +0 -3
  129. data/lib/rigor/cache/rbs_descriptor.rb +112 -14
  130. data/lib/rigor/cache/rbs_environment.rb +8 -4
  131. data/lib/rigor/cache/rbs_known_class_names.rb +0 -3
  132. data/lib/rigor/cache/store.rb +76 -32
  133. data/lib/rigor/ci_detector.rb +1 -0
  134. data/lib/rigor/cli/annotate_command.rb +5 -6
  135. data/lib/rigor/cli/check_command.rb +57 -10
  136. data/lib/rigor/cli/check_invocation.rb +6 -11
  137. data/lib/rigor/cli/check_runner_factory.rb +1 -5
  138. data/lib/rigor/cli/coverage_command.rb +1 -1
  139. data/lib/rigor/cli/coverage_mutation.rb +12 -3
  140. data/lib/rigor/cli/coverage_scan.rb +1 -5
  141. data/lib/rigor/cli/diff_command.rb +1 -1
  142. data/lib/rigor/cli/doc_links.rb +4 -4
  143. data/lib/rigor/cli/docs_command.rb +6 -6
  144. data/lib/rigor/cli/doctor_command.rb +85 -38
  145. data/lib/rigor/cli/effects_command.rb +2 -2
  146. data/lib/rigor/cli/effects_diff_renderer.rb +3 -3
  147. data/lib/rigor/cli/effects_snapshot_command.rb +1 -1
  148. data/lib/rigor/cli/explain_command.rb +34 -1
  149. data/lib/rigor/cli/fused_protection_report.rb +7 -1
  150. data/lib/rigor/cli/lsp_command.rb +1 -1
  151. data/lib/rigor/cli/mcp_command.rb +1 -1
  152. data/lib/rigor/cli/measurement_integrity_warning.rb +4 -5
  153. data/lib/rigor/cli/mutation_fork_scan.rb +6 -6
  154. data/lib/rigor/cli/mutation_protection_report.rb +7 -1
  155. data/lib/rigor/cli/plugin_command.rb +4 -4
  156. data/lib/rigor/cli/plugins_command.rb +2 -1
  157. data/lib/rigor/cli/prism_colorizer.rb +1 -2
  158. data/lib/rigor/cli/protection_fork_scan.rb +6 -6
  159. data/lib/rigor/cli/show_bleedingedge_command.rb +1 -1
  160. data/lib/rigor/cli/sig_gen_command.rb +212 -31
  161. data/lib/rigor/cli/skill_command.rb +2 -2
  162. data/lib/rigor/cli/skill_deep_probe.rb +4 -4
  163. data/lib/rigor/cli/skill_describe.rb +35 -35
  164. data/lib/rigor/cli/trace_command.rb +4 -4
  165. data/lib/rigor/cli/trace_renderer.rb +5 -6
  166. data/lib/rigor/cli/triage_command.rb +1 -1
  167. data/lib/rigor/cli/type_of_command.rb +29 -11
  168. data/lib/rigor/cli/type_of_renderer.rb +20 -9
  169. data/lib/rigor/cli/type_of_template_probe.rb +189 -0
  170. data/lib/rigor/cli/type_scan_command.rb +4 -4
  171. data/lib/rigor/cli/unused_command.rb +11 -3
  172. data/lib/rigor/cli/upgrade_command.rb +1 -1
  173. data/lib/rigor/cli.rb +89 -9
  174. data/lib/rigor/config_audit.rb +30 -5
  175. data/lib/rigor/configuration/severity_profile.rb +25 -9
  176. data/lib/rigor/configuration.rb +109 -7
  177. data/lib/rigor/effects/ancestry_recorder.rb +191 -0
  178. data/lib/rigor/effects/attribution.rb +12 -5
  179. data/lib/rigor/effects/callee_rule.rb +368 -0
  180. data/lib/rigor/effects/catalog.rb +7 -4
  181. data/lib/rigor/effects/collector.rb +11 -5
  182. data/lib/rigor/effects/config_envelopes.rb +15 -10
  183. data/lib/rigor/effects/definition_context.rb +179 -0
  184. data/lib/rigor/effects/definition_lines.rb +25 -6
  185. data/lib/rigor/effects/effect_table.rb +11 -4
  186. data/lib/rigor/effects/entry_points.rb +0 -2
  187. data/lib/rigor/effects/envelope_check.rb +9 -9
  188. data/lib/rigor/effects/envelope_index.rb +20 -8
  189. data/lib/rigor/effects/file_collection.rb +59 -5
  190. data/lib/rigor/effects/framework_units.rb +5 -7
  191. data/lib/rigor/effects/identity.rb +20 -6
  192. data/lib/rigor/effects/inline_anchor.rb +7 -7
  193. data/lib/rigor/effects/label_intent.rb +3 -4
  194. data/lib/rigor/effects/liskov_check.rb +8 -8
  195. data/lib/rigor/effects/local_ownership.rb +38 -12
  196. data/lib/rigor/effects/method_key.rb +22 -1
  197. data/lib/rigor/effects/mutation_classifier.rb +23 -12
  198. data/lib/rigor/effects/plugin_facts.rb +47 -37
  199. data/lib/rigor/effects/propagator.rb +297 -19
  200. data/lib/rigor/effects/registry.rb +1 -1
  201. data/lib/rigor/effects/scanner.rb +122 -73
  202. data/lib/rigor/effects/signature_sources.rb +4 -6
  203. data/lib/rigor/effects/snapshot.rb +12 -11
  204. data/lib/rigor/effects/snapshot_diff.rb +1 -1
  205. data/lib/rigor/effects/summary.rb +27 -4
  206. data/lib/rigor/effects/unit_scan.rb +393 -38
  207. data/lib/rigor/effects/unknown_label_check.rb +3 -8
  208. data/lib/rigor/effects/unknown_label_report.rb +3 -4
  209. data/lib/rigor/effects/visibility.rb +101 -0
  210. data/lib/rigor/environment/bundle_sig_discovery.rb +6 -6
  211. data/lib/rigor/environment/class_registry.rb +3 -1
  212. data/lib/rigor/environment/failure_slot.rb +2 -2
  213. data/lib/rigor/environment/installed_gem_set.rb +85 -0
  214. data/lib/rigor/environment/lockfile_resolver.rb +68 -4
  215. data/lib/rigor/environment/member_consistency/comparator.rb +708 -0
  216. data/lib/rigor/environment/member_consistency.rb +298 -0
  217. data/lib/rigor/environment/missing_gem_constant_index.rb +4 -4
  218. data/lib/rigor/environment/rbs_collection_discovery.rb +5 -5
  219. data/lib/rigor/environment/rbs_coverage_report.rb +5 -5
  220. data/lib/rigor/environment/rbs_hierarchy.rb +3 -1
  221. data/lib/rigor/environment/rbs_loader.rb +674 -79
  222. data/lib/rigor/environment.rb +174 -24
  223. data/lib/rigor/flow_contribution/merger.rb +0 -2
  224. data/lib/rigor/flow_contribution.rb +11 -13
  225. data/lib/rigor/hashing/xxh3.rb +264 -0
  226. data/lib/rigor/inference/acceptance.rb +292 -17
  227. data/lib/rigor/inference/block_auto_splat.rb +216 -0
  228. data/lib/rigor/inference/block_call_timing.rb +338 -0
  229. data/lib/rigor/inference/block_parameter_binder.rb +75 -30
  230. data/lib/rigor/inference/block_repetition.rb +71 -0
  231. data/lib/rigor/inference/body_fixpoint.rb +7 -6
  232. data/lib/rigor/inference/budget_trace.rb +3 -6
  233. data/lib/rigor/inference/builtins/method_catalog.rb +2 -1
  234. data/lib/rigor/inference/builtins/string_catalog.rb +1 -1
  235. data/lib/rigor/inference/captured_locals.rb +389 -18
  236. data/lib/rigor/inference/closure_escape_analyzer.rb +159 -17
  237. data/lib/rigor/inference/content_join.rb +200 -27
  238. data/lib/rigor/inference/coverage_scanner.rb +4 -6
  239. data/lib/rigor/inference/def_return_typer.rb +11 -7
  240. data/lib/rigor/inference/define_method_block_self.rb +64 -0
  241. data/lib/rigor/inference/dynamic_origin.rb +1 -1
  242. data/lib/rigor/inference/element_read_widening.rb +180 -0
  243. data/lib/rigor/inference/error_info.rb +196 -0
  244. data/lib/rigor/inference/expression_typer.rb +2124 -468
  245. data/lib/rigor/inference/external_ancestor_resolution.rb +267 -0
  246. data/lib/rigor/inference/fork_map.rb +5 -7
  247. data/lib/rigor/inference/fresh_frame_blocks.rb +127 -0
  248. data/lib/rigor/inference/global_write_census.rb +239 -0
  249. data/lib/rigor/inference/guard_rebinding.rb +447 -0
  250. data/lib/rigor/inference/hash_lookup_mutation.rb +88 -0
  251. data/lib/rigor/inference/hkt_reducer.rb +2 -3
  252. data/lib/rigor/inference/hkt_registry.rb +4 -7
  253. data/lib/rigor/inference/index_write_widening.rb +16 -7
  254. data/lib/rigor/inference/indexed_narrowing.rb +61 -9
  255. data/lib/rigor/inference/jump_targets.rb +82 -0
  256. data/lib/rigor/inference/last_line/implicit_self.rb +210 -0
  257. data/lib/rigor/inference/last_line/self_evidence.rb +329 -0
  258. data/lib/rigor/inference/last_line.rb +340 -0
  259. data/lib/rigor/inference/last_status.rb +144 -0
  260. data/lib/rigor/inference/macro_block_self_type.rb +168 -21
  261. data/lib/rigor/inference/match_rebinding/calls.rb +281 -0
  262. data/lib/rigor/inference/match_rebinding/frame.rb +148 -0
  263. data/lib/rigor/inference/match_rebinding/operands.rb +236 -0
  264. data/lib/rigor/inference/match_rebinding/self_calls.rb +83 -0
  265. data/lib/rigor/inference/match_rebinding.rb +392 -0
  266. data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +36 -0
  267. data/lib/rigor/inference/method_dispatcher/block_folding.rb +87 -33
  268. data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +1 -1
  269. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +305 -19
  270. data/lib/rigor/inference/method_dispatcher/data_folding.rb +1 -1
  271. data/lib/rigor/inference/method_dispatcher/facet_distribution.rb +147 -0
  272. data/lib/rigor/inference/method_dispatcher/file_folding.rb +1 -1
  273. data/lib/rigor/inference/method_dispatcher/hash_transform_keys_folding.rb +191 -0
  274. data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +6 -2
  275. data/lib/rigor/inference/method_dispatcher/json_folding.rb +1 -1
  276. data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +7 -1
  277. data/lib/rigor/inference/method_dispatcher/match_data_folding.rb +159 -0
  278. data/lib/rigor/inference/method_dispatcher/math_folding.rb +41 -3
  279. data/lib/rigor/inference/method_dispatcher/method_folding.rb +2 -5
  280. data/lib/rigor/inference/method_dispatcher/overload_selector.rb +165 -111
  281. data/lib/rigor/inference/method_dispatcher/process_folding.rb +56 -0
  282. data/lib/rigor/inference/method_dispatcher/proven_overload.rb +72 -0
  283. data/lib/rigor/inference/method_dispatcher/random_folding.rb +82 -0
  284. data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +1046 -69
  285. data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +25 -4
  286. data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +2 -8
  287. data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +1 -1
  288. data/lib/rigor/inference/method_dispatcher/self_substitute.rb +142 -0
  289. data/lib/rigor/inference/method_dispatcher/set_folding.rb +1 -1
  290. data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +129 -54
  291. data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +1 -1
  292. data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +1 -2
  293. data/lib/rigor/inference/method_dispatcher/struct_folding.rb +5 -6
  294. data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +85 -4
  295. data/lib/rigor/inference/method_dispatcher/time_folding.rb +1 -1
  296. data/lib/rigor/inference/method_dispatcher/universal_object_dispatch.rb +1 -2
  297. data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
  298. data/lib/rigor/inference/method_dispatcher.rb +225 -25
  299. data/lib/rigor/inference/method_parameter_binder.rb +12 -9
  300. data/lib/rigor/inference/multi_target_binder.rb +341 -55
  301. data/lib/rigor/inference/mutation_rejoin.rb +171 -0
  302. data/lib/rigor/inference/mutation_widening.rb +156 -85
  303. data/lib/rigor/inference/narrowing.rb +835 -162
  304. data/lib/rigor/inference/operand_effects.rb +167 -0
  305. data/lib/rigor/inference/operand_walk.rb +88 -0
  306. data/lib/rigor/inference/optimistic_origin.rb +153 -16
  307. data/lib/rigor/inference/origin_lookup.rb +2 -3
  308. data/lib/rigor/inference/parameter_inference_collector.rb +7 -7
  309. data/lib/rigor/inference/pre_eval_constants.rb +6 -5
  310. data/lib/rigor/inference/precision_scanner.rb +3 -4
  311. data/lib/rigor/inference/project_method_ownership.rb +136 -0
  312. data/lib/rigor/inference/project_patched_methods.rb +9 -4
  313. data/lib/rigor/inference/project_patched_scanner.rb +10 -6
  314. data/lib/rigor/inference/protection_scanner.rb +1 -2
  315. data/lib/rigor/inference/range_constant.rb +57 -0
  316. data/lib/rigor/inference/rbs_type_translator.rb +49 -11
  317. data/lib/rigor/inference/receiver_alias.rb +93 -4
  318. data/lib/rigor/inference/receiver_blind_block.rb +219 -0
  319. data/lib/rigor/inference/refinement_mutation.rb +76 -0
  320. data/lib/rigor/inference/repeated_or_writes.rb +463 -0
  321. data/lib/rigor/inference/return_barrier.rb +54 -0
  322. data/lib/rigor/inference/rewrite_mutation.rb +120 -0
  323. data/lib/rigor/inference/scope_indexer.rb +5228 -627
  324. data/lib/rigor/inference/statement_evaluator.rb +3452 -595
  325. data/lib/rigor/inference/stored_block_call.rb +54 -0
  326. data/lib/rigor/inference/string_mutation.rb +97 -0
  327. data/lib/rigor/inference/struct_fold_safety.rb +6 -7
  328. data/lib/rigor/inference/synthetic_method_index.rb +1 -2
  329. data/lib/rigor/inference/synthetic_method_scanner.rb +4 -6
  330. data/lib/rigor/inference/unknown_store_widening.rb +200 -0
  331. data/lib/rigor/inference/unthreaded_rebinds.rb +282 -0
  332. data/lib/rigor/inference/version_guard.rb +28 -21
  333. data/lib/rigor/inference/void_origin.rb +3 -3
  334. data/lib/rigor/inference/void_tail_summary.rb +2 -4
  335. data/lib/rigor/language_server/buffer_table.rb +4 -4
  336. data/lib/rigor/language_server/completion_provider.rb +1 -1
  337. data/lib/rigor/language_server/debouncer.rb +0 -1
  338. data/lib/rigor/language_server/diagnostic_publisher.rb +7 -6
  339. data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
  340. data/lib/rigor/language_server/folding_range_provider.rb +1 -1
  341. data/lib/rigor/language_server/hover_provider.rb +1 -1
  342. data/lib/rigor/language_server/hover_renderer.rb +4 -4
  343. data/lib/rigor/language_server/incremental_sync.rb +6 -6
  344. data/lib/rigor/language_server/project_context.rb +7 -8
  345. data/lib/rigor/language_server/publish_batcher.rb +2 -2
  346. data/lib/rigor/language_server/selection_range_provider.rb +2 -2
  347. data/lib/rigor/language_server/server.rb +9 -9
  348. data/lib/rigor/language_server/signature_help_provider.rb +1 -1
  349. data/lib/rigor/language_server/uri.rb +1 -1
  350. data/lib/rigor/mcp/server.rb +2 -1
  351. data/lib/rigor/plugin/base.rb +258 -26
  352. data/lib/rigor/plugin/box_probe.rb +91 -0
  353. data/lib/rigor/plugin/bundled_catalog.rb +167 -0
  354. data/lib/rigor/plugin/effect_attribution.rb +65 -11
  355. data/lib/rigor/plugin/effect_entry_points.rb +3 -3
  356. data/lib/rigor/plugin/fact_store.rb +6 -6
  357. data/lib/rigor/plugin/io_boundary.rb +93 -8
  358. data/lib/rigor/plugin/isolation.rb +29 -6
  359. data/lib/rigor/plugin/loader.rb +33 -13
  360. data/lib/rigor/plugin/macro/block_as_method.rb +45 -6
  361. data/lib/rigor/plugin/macro/heredoc_template.rb +1 -1
  362. data/lib/rigor/plugin/macro/trait_registry.rb +1 -1
  363. data/lib/rigor/plugin/manifest.rb +94 -11
  364. data/lib/rigor/plugin/registry.rb +76 -12
  365. data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +21 -4
  366. data/lib/rigor/plugin/template_unit.rb +196 -0
  367. data/lib/rigor/plugin/trust_policy.rb +2 -4
  368. data/lib/rigor/plugin/type_node_resolver.rb +3 -3
  369. data/lib/rigor/plugin.rb +1 -0
  370. data/lib/rigor/plugin_gap_advisory.rb +96 -0
  371. data/lib/rigor/project_environment.rb +138 -0
  372. data/lib/rigor/protection/analysis_guard.rb +93 -14
  373. data/lib/rigor/protection/closure_kill_oracle.rb +67 -23
  374. data/lib/rigor/protection/dependency_closure.rb +5 -8
  375. data/lib/rigor/protection/diagnostic_oracle.rb +2 -2
  376. data/lib/rigor/protection/discovery_seed.rb +14 -12
  377. data/lib/rigor/protection/kill_signature.rb +1 -4
  378. data/lib/rigor/protection/measurement_integrity.rb +1 -3
  379. data/lib/rigor/protection/mutation_cache.rb +7 -11
  380. data/lib/rigor/protection/mutation_scanner.rb +12 -15
  381. data/lib/rigor/protection/mutator.rb +2 -1
  382. data/lib/rigor/protection/test_suite_oracle.rb +5 -5
  383. data/lib/rigor/rbs_extended/conformance_checker.rb +4 -3
  384. data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
  385. data/lib/rigor/rbs_extended/reporter.rb +36 -10
  386. data/lib/rigor/rbs_extended.rb +88 -21
  387. data/lib/rigor/reflection/constant_ancestors.rb +97 -0
  388. data/lib/rigor/reflection/constant_path.rb +139 -0
  389. data/lib/rigor/reflection.rb +93 -110
  390. data/lib/rigor/runtime/jit.rb +6 -8
  391. data/lib/rigor/scope/discovery_index.rb +165 -2
  392. data/lib/rigor/scope.rb +1041 -32
  393. data/lib/rigor/sig_gen/alias_index.rb +289 -0
  394. data/lib/rigor/sig_gen/classification.rb +22 -5
  395. data/lib/rigor/sig_gen/declaration_equivalence.rb +127 -0
  396. data/lib/rigor/sig_gen/effect_annotation.rb +202 -0
  397. data/lib/rigor/sig_gen/generator.rb +673 -53
  398. data/lib/rigor/sig_gen/inline_declarations.rb +184 -0
  399. data/lib/rigor/sig_gen/layout_index.rb +3 -4
  400. data/lib/rigor/sig_gen/meta_class_shape.rb +3 -5
  401. data/lib/rigor/sig_gen/method_candidate.rb +47 -3
  402. data/lib/rigor/sig_gen/observation_collector.rb +18 -16
  403. data/lib/rigor/sig_gen/path_mapper.rb +4 -6
  404. data/lib/rigor/sig_gen/rbs_validity.rb +4 -4
  405. data/lib/rigor/sig_gen/renderer.rb +128 -14
  406. data/lib/rigor/sig_gen/skip_reason_catalog.rb +154 -0
  407. data/lib/rigor/sig_gen/superclass_spelling.rb +27 -0
  408. data/lib/rigor/sig_gen/type_elaborator.rb +1 -3
  409. data/lib/rigor/sig_gen/write_result.rb +19 -3
  410. data/lib/rigor/sig_gen/writer.rb +189 -41
  411. data/lib/rigor/sig_gen.rb +3 -0
  412. data/lib/rigor/signature_path_audit.rb +153 -6
  413. data/lib/rigor/source/literals.rb +0 -23
  414. data/lib/rigor/source/node_children.rb +0 -2
  415. data/lib/rigor/source/node_locator.rb +5 -11
  416. data/lib/rigor/source/node_walker.rb +0 -6
  417. data/lib/rigor/source/parameter_envelope.rb +72 -0
  418. data/lib/rigor/source.rb +1 -0
  419. data/lib/rigor/triage/catalogue.rb +1 -3
  420. data/lib/rigor/triage.rb +3 -5
  421. data/lib/rigor/type/accepts_result.rb +24 -6
  422. data/lib/rigor/type/combinator.rb +144 -5
  423. data/lib/rigor/type/data_class.rb +2 -2
  424. data/lib/rigor/type/data_instance.rb +4 -4
  425. data/lib/rigor/type/difference.rb +1 -0
  426. data/lib/rigor/type/float_range.rb +128 -0
  427. data/lib/rigor/type/hash_shape.rb +6 -6
  428. data/lib/rigor/type/integer_range.rb +13 -8
  429. data/lib/rigor/type/nominal.rb +8 -2
  430. data/lib/rigor/type/refined.rb +4 -3
  431. data/lib/rigor/type/struct_class.rb +3 -3
  432. data/lib/rigor/type/struct_instance.rb +4 -4
  433. data/lib/rigor/type.rb +1 -0
  434. data/lib/rigor/type_node/generic.rb +1 -1
  435. data/lib/rigor/type_node/range_literal.rb +25 -0
  436. data/lib/rigor/type_node/resolver_chain.rb +1 -1
  437. data/lib/rigor/type_node.rb +1 -0
  438. data/lib/rigor/version.rb +1 -1
  439. data/lib/rigor.rb +1 -0
  440. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +0 -4
  441. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +0 -1
  442. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +0 -2
  443. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/effects.rb +1 -0
  444. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +10 -5
  445. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +0 -4
  446. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +3 -5
  447. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +1 -4
  448. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +14 -4
  449. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +32 -30
  450. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +0 -1
  451. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -3
  452. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_scan.rb +96 -0
  453. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/effects.rb +65 -8
  454. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +270 -0
  455. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/render_locals.rb +402 -0
  456. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +370 -0
  457. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_units.rb +132 -0
  458. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +264 -3
  459. data/plugins/rigor-actionpack/sig/action_controller.rbs +71 -0
  460. data/plugins/rigor-actionpack/sig/action_view.rbs +43 -0
  461. data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_discoverer.rb +220 -0
  462. data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_index.rb +56 -0
  463. data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers.rb +263 -0
  464. data/plugins/rigor-active-model-serializers/lib/rigor-active-model-serializers.rb +7 -0
  465. data/plugins/rigor-active-model-serializers/sig/active_model_serializers.rbs +45 -0
  466. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +0 -4
  467. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +2 -1
  468. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +0 -1
  469. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +0 -2
  470. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/recurring_scan.rb +1 -1
  471. data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +10 -5
  472. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +35 -3
  473. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +72 -12
  474. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +383 -7
  475. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +14 -6
  476. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +1 -2
  477. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +1 -2
  478. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +322 -41
  479. data/plugins/rigor-activerecord/sig/active_record/framework.rbs +123 -0
  480. data/plugins/rigor-activerecord/sig/active_record/relation.rbs +206 -31
  481. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +26 -14
  482. data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +9 -2
  483. data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +9 -2
  484. data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +290 -19
  485. data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +1 -0
  486. data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +3 -0
  487. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +9 -7
  488. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +7 -3
  489. data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +1 -0
  490. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +8 -6
  491. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +11 -7
  492. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -11
  493. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +9 -4
  494. data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +2 -0
  495. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +0 -5
  496. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +0 -1
  497. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +0 -1
  498. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +8 -1
  499. data/plugins/rigor-ffi/lib/rigor/plugin/ffi/types.rb +1 -1
  500. data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +36 -4
  501. data/plugins/rigor-ffi-rzmq/lib/rigor/plugin/ffi_rzmq.rb +1 -0
  502. data/plugins/rigor-grape/lib/rigor/plugin/grape.rb +141 -0
  503. data/plugins/rigor-grape/lib/rigor-grape.rb +6 -0
  504. data/plugins/rigor-grape/sig/grape.rbs +263 -0
  505. data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +8 -6
  506. data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +78 -5
  507. data/plugins/rigor-graphql/sig/graphql.rbs +485 -0
  508. data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +1 -0
  509. data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -1
  510. data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +2 -3
  511. data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +1 -0
  512. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +0 -5
  513. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/authorization_scan.rb +2 -2
  514. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +0 -1
  515. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +0 -1
  516. data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +12 -7
  517. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +0 -12
  518. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +1 -3
  519. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +0 -1
  520. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +36 -37
  521. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/acronyms.rb +5 -5
  522. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +0 -10
  523. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +5 -3
  524. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +3 -2
  525. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/grape_api_discoverer.rb +2 -2
  526. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +2 -2
  527. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +9 -10
  528. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +2 -3
  529. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +10 -17
  530. data/plugins/rigor-railties/lib/rigor/plugin/railties.rb +1 -0
  531. data/plugins/rigor-rbnacl/lib/rigor/plugin/rbnacl.rb +13 -1
  532. data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline/same_line_annotations.rb +149 -0
  533. data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +324 -18
  534. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +0 -3
  535. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +0 -3
  536. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +1 -5
  537. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +2 -3
  538. data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +1 -0
  539. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +0 -3
  540. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +1 -0
  541. data/plugins/rigor-sassc/lib/rigor/plugin/sassc.rb +1 -0
  542. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +1 -9
  543. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +1 -0
  544. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +0 -4
  545. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/effects.rb +1 -1
  546. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +2 -1
  547. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +0 -1
  548. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +0 -2
  549. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +10 -5
  550. data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +1 -0
  551. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +2 -5
  552. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +1 -4
  553. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +3 -9
  554. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +4 -4
  555. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +1 -2
  556. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +3 -5
  557. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +7 -5
  558. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +51 -6
  559. data/plugins/rigor-sorbet/sig/sorbet.rbs +277 -0
  560. data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +1 -0
  561. data/sig/rigor/analysis/baseline.rbs +69 -7
  562. data/sig/rigor/analysis/fact_store.rbs +1 -1
  563. data/sig/rigor/analysis/project_scan.rbs +74 -0
  564. data/sig/rigor/analysis/reachability/scan_cache.rbs +12 -0
  565. data/sig/rigor/cache.rbs +2 -3
  566. data/sig/rigor/effects/config_envelopes.rbs +100 -0
  567. data/sig/rigor/effects/effect_table.rbs +60 -0
  568. data/sig/rigor/effects/envelope.rbs +97 -0
  569. data/sig/rigor/effects/envelope_index.rbs +33 -0
  570. data/sig/rigor/effects/file_collection.rbs +81 -0
  571. data/sig/rigor/effects/label.rbs +26 -0
  572. data/sig/rigor/effects/label_set.rbs +46 -0
  573. data/sig/rigor/effects/method_key.rbs +24 -0
  574. data/sig/rigor/effects/origin.rbs +50 -0
  575. data/sig/rigor/effects/plugin_facts.rbs +141 -0
  576. data/sig/rigor/effects/registry.rbs +68 -0
  577. data/sig/rigor/effects/summary.rbs +50 -0
  578. data/sig/rigor/effects/taint_cause.rbs +12 -0
  579. data/sig/rigor/environment.rbs +17 -10
  580. data/sig/rigor/inference/optimistic_origin.rbs +10 -0
  581. data/sig/rigor/inference.rbs +9 -14
  582. data/sig/rigor/plugin/additional_initializer.rbs +36 -0
  583. data/sig/rigor/plugin/base.rbs +30 -7
  584. data/sig/rigor/plugin/effect_ancestry.rbs +27 -0
  585. data/sig/rigor/plugin/effect_attribution.rbs +66 -0
  586. data/sig/rigor/plugin/effect_edge.rbs +33 -0
  587. data/sig/rigor/plugin/effect_entry_points.rbs +25 -0
  588. data/sig/rigor/plugin/io_boundary.rbs +4 -0
  589. data/sig/rigor/plugin/loader.rbs +3 -3
  590. data/sig/rigor/plugin/manifest.rbs +51 -11
  591. data/sig/rigor/plugin/protocol_contract.rbs +68 -0
  592. data/sig/rigor/plugin/registry.rbs +62 -1
  593. data/sig/rigor/plugin.rbs +1 -1
  594. data/sig/rigor/rbs_extended.rbs +1 -1
  595. data/sig/rigor/reflection.rbs +9 -6
  596. data/sig/rigor/scope.rbs +148 -12
  597. data/sig/rigor/sig_gen/skip_reason_catalog.rbs +21 -0
  598. data/sig/rigor/source.rbs +4 -4
  599. data/sig/rigor/testing.rbs +10 -4
  600. data/sig/rigor/type.rbs +33 -1
  601. data/sig/rigor.rbs +39 -20
  602. data/skills/rigor-ask/SKILL.md +16 -11
  603. data/skills/rigor-baseline-reduce/SKILL.md +4 -6
  604. data/skills/rigor-ci-setup/SKILL.md +17 -21
  605. data/skills/rigor-doctor/SKILL.md +24 -22
  606. data/skills/rigor-doctor/references/01-checks.md +97 -33
  607. data/skills/rigor-editor-setup/SKILL.md +6 -4
  608. data/skills/rigor-mcp-setup/SKILL.md +5 -4
  609. data/skills/rigor-monkeypatch-resolve/SKILL.md +5 -3
  610. data/skills/rigor-next-steps/SKILL.md +4 -2
  611. data/skills/rigor-plugin-author/SKILL.md +19 -23
  612. data/skills/rigor-plugin-author/references/01-plan-and-scaffold.md +9 -8
  613. data/skills/rigor-plugin-author/references/02-walker-and-types.md +25 -27
  614. data/skills/rigor-plugin-author/references/03-test-and-ship.md +6 -8
  615. data/skills/rigor-plugin-review/SKILL.md +6 -4
  616. data/skills/rigor-plugin-review/references/01-best-practices-checklist.md +2 -1
  617. data/skills/rigor-plugin-tune/SKILL.md +4 -2
  618. data/skills/rigor-project-init/SKILL.md +15 -10
  619. data/skills/rigor-project-init/references/01-detect.md +13 -9
  620. data/skills/rigor-project-init/references/02-configure.md +43 -14
  621. data/skills/rigor-project-init/references/03-baseline-and-bugs.md +14 -14
  622. data/skills/rigor-project-init/references/04-sig-uplift.md +27 -14
  623. data/skills/rigor-project-init/references/06-agent-contract.md +67 -0
  624. data/skills/rigor-protection-uplift/SKILL.md +4 -6
  625. data/skills/rigor-rbs-setup/SKILL.md +4 -2
  626. data/skills/rigor-type-oracle/SKILL.md +226 -0
  627. data/skills/rigor-type-oracle/references/01-oracle-commands.md +265 -0
  628. data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +52 -0
  629. data/skills/rigor-type-oracle/references/03-gap-protocol.md +125 -0
  630. data/skills/rigor-unused-adjudicate/SKILL.md +12 -7
  631. data/skills/rigor-upgrade/SKILL.md +13 -8
  632. metadata +133 -3
  633. data/lib/rigor/cli/probe_environment.rb +0 -85
  634. data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../type"
4
+
5
+ module Rigor
6
+ module Inference
7
+ # Issue #963 — the lexical `self` of a `define_method(:name) { ... }` block.
8
+ #
9
+ # A block has no `self` of its own, so every block body enters with `Scope#entering_opaque_block`
10
+ # and the enclosing class body's `self_type` (`Singleton[C]`) rides along unchanged. For
11
+ # `define_method` that carrier is the wrong side of the class: `Module#define_method` turns the
12
+ # block into an INSTANCE method of the receiver, and Ruby runs its body with `self` bound to the
13
+ # receiving instance. A bare `text` inside the block therefore reaches `C`'s member / attr reader,
14
+ # while `Singleton[C]` answers only `C`'s class methods.
15
+ #
16
+ # The consequence #963 records is #618's veto going the wrong way: `ExpressionTyper#self_type_answers?`
17
+ # asked the singleton side, found nothing, and let a same-named top-level `def text` bind ahead of the
18
+ # reader — typing `text.upcase` inside `class Line < Struct.new(:text); define_method(:shout) { text.upcase }`
19
+ # as the top-level def's `nil`. Narrowing the block body's `self_type` to `Nominal[C]` makes the
20
+ # existing veto ask the instance side, which is the side Ruby dispatches on; nothing in the veto
21
+ # itself changes.
22
+ #
23
+ # The match is deliberately narrow — the receiver must be the class body's own `self`, and that `self`
24
+ # must be a known `Singleton[C]` on the instance side of the class. `Foo.define_method(...)` on some other
25
+ # receiver keeps the unmodelled-self answer, and so does a `class << ...` BODY, where `self` is the
26
+ # singleton class and the call defines a CLASS method: an instance reader is not in that MRO, MRI reaches
27
+ # the top-level `def` there, and Rigor must answer the same. The body is the exclusion, not the lexical
28
+ # singleton frame — a `def` reached from that body has the class object as its `self`, so the call defines
29
+ # an instance method and the narrowing applies. `Scope#singleton_class_body?` is what draws that line, and
30
+ # carrying it on the scope is what lets both block-entry paths apply it identically.
31
+ # A `module_function` module is the one shape where both answers are right at once: MRI makes the block
32
+ # BOTH an instance method, where the reader resolves, and a module function on the module object, where it
33
+ # does not. Narrowing silences the module-function half, which is the false-positive-averse direction
34
+ # AGENTS.md § Implementation Guidelines asks for.
35
+ module DefineMethodBlockSelf
36
+ module_function
37
+
38
+ # @return the block body's narrowed `self_type`, or `nil` when the call shape does not match.
39
+ def narrow_self_type_for(scope:, call_node:)
40
+ return nil if scope&.singleton_class_body?
41
+ return nil unless define_method_on_lexical_self?(call_node)
42
+
43
+ self_type = scope&.self_type
44
+ return nil unless self_type.is_a?(Type::Singleton)
45
+
46
+ class_name = self_type.class_name
47
+ return nil if class_name.nil?
48
+
49
+ instance_type_for(class_name, scope.environment)
50
+ end
51
+
52
+ def define_method_on_lexical_self?(call_node)
53
+ return false unless call_node.is_a?(Prism::CallNode)
54
+ return false unless call_node.name == :define_method
55
+
56
+ call_node.receiver.nil? || call_node.receiver.is_a?(Prism::SelfNode)
57
+ end
58
+
59
+ def instance_type_for(class_name, environment)
60
+ environment&.nominal_for_name(class_name) || Type::Nominal.new(class_name)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -60,7 +60,7 @@ module Rigor
60
60
 
61
61
  module_function
62
62
 
63
- # @return [Symbol, nil] the tractability category for a cause, or nil when the cause is unknown /
63
+ # @return the tractability category for a cause, or nil when the cause is unknown /
64
64
  # absent.
65
65
  def tractability(cause)
66
66
  TRACTABILITY[cause]
@@ -0,0 +1,180 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "prism"
4
+
5
+ require_relative "../type"
6
+ require_relative "mutation_widening"
7
+
8
+ module Rigor
9
+ module Inference
10
+ # Widens the element a mutator call reaches THROUGH a read, when the container is a local's
11
+ # literal-shape carrier. {MutationWidening} widens the bindings a receiver expression NAMES;
12
+ # this module covers the case where it names none because the receiver is an rvalue temp.
13
+ module ElementReadWidening
14
+ # Element reads that name ONE element of a container: the only receiver shapes whose mutation
15
+ # is attributable to a single position inside a local's literal-shape carrier. `first` / `last`
16
+ # with an argument return a sub-ARRAY, not an element, so they are excluded by arity below.
17
+ ELEMENT_READERS = %i[[] first last dig].to_set.freeze
18
+
19
+ module_function
20
+
21
+ # Widens an element read through an index / `first` / `last` / `dig` chain rooted at a LOCAL,
22
+ # when that read is the RECEIVER of a content mutator (issue #643).
23
+ #
24
+ # `c = [flag ? [1] : [2]]; c[0] << 5` mutates the rvalue temp `c[0]`, so
25
+ # {MutationWidening.widen_after_call} — which widens exactly the bindings the receiver expression NAMES —
26
+ # sees no variable and records nothing. `c` keeps `Tuple[[1] | [2]]`, and the later
27
+ # `c[0].last == 5` folds always-falsey on a value the program does hold. The nested plain
28
+ # literal (`b = [[[]]]; b[0][0] << 1`) reads `b[0][0].first` as `nil` for the same reason.
29
+ #
30
+ # The fix widens the element's pin ONE STEP INSIDE the container and writes the rebuilt
31
+ # container back to the local: `Tuple[[1] | [2]]` becomes `Tuple[Array[Integer]]`. The outer
32
+ # arity survives — mutating an element cannot change how many elements the container has —
33
+ # so `c.size == 1` keeps folding. A non-literal index widens every position instead, since
34
+ # which one was mutated is not decidable.
35
+ #
36
+ # Rooted at a local only: a mutation through a method call's result (`foo[0] << 5`) has no
37
+ # binding to write back to, and inventing one would be unsound.
38
+ def widen_element_read(call_node:, current_scope:, arg_types: MutationWidening::NO_ARG_TYPES)
39
+ return current_scope if MutationWidening.pure_self_returner?(call_node.name)
40
+
41
+ path = element_read_path(call_node.receiver)
42
+ return current_scope if path.nil?
43
+
44
+ read, steps = path
45
+ widened = widen_through_path(current_scope.local(read.name), steps, call_node.name, arg_types)
46
+ return current_scope if widened.nil?
47
+
48
+ current_scope.with_mutated_local(read.name, widened)
49
+ end
50
+
51
+ # True when `receiver` is an element read whose target element is a literal-shape carrier —
52
+ # the {#joinable_receiver?} counterpart for the element path, gating whether the caller types
53
+ # the mutator's arguments at all.
54
+ def joinable_element_read?(receiver, scope)
55
+ path = element_read_path(receiver)
56
+ return false if path.nil?
57
+
58
+ read, steps = path
59
+ !element_at_path(scope.local(read.name), steps).nil?
60
+ end
61
+
62
+ # `[<local read>, [step, …]]` for a chain of element reads rooted at a local variable, or
63
+ # `nil` when the expression is anything else. A step is an Integer position (negative counts
64
+ # from the end, as Ruby's own indexing does) or `:all` when the index is not a literal.
65
+ #
66
+ # Every mutation site's receiver is asked, and nearly every one is a plain variable read, so a
67
+ # receiver that is no call answers before the step list is allocated.
68
+ def element_read_path(node)
69
+ return nil unless node.is_a?(Prism::CallNode)
70
+
71
+ steps = []
72
+ cursor = node
73
+ while cursor.is_a?(Prism::CallNode)
74
+ step = element_read_step(cursor)
75
+ return nil if step.nil?
76
+
77
+ steps.unshift(*step)
78
+ cursor = cursor.receiver
79
+ end
80
+ return nil unless cursor.is_a?(Prism::LocalVariableReadNode) && !steps.empty?
81
+
82
+ [cursor, steps]
83
+ end
84
+
85
+ # The positions one element-read call selects, or `nil` when the call is not an element read.
86
+ # A block makes the call something other than a plain read (`arr.first { … }` is not one), and
87
+ # `[]` with anything but a single argument is a slice.
88
+ def element_read_step(call_node)
89
+ return nil unless ELEMENT_READERS.include?(call_node.name)
90
+ return nil if call_node.receiver.nil? || call_node.block
91
+
92
+ positional_steps(call_node.name, call_node.arguments&.arguments || [])
93
+ end
94
+
95
+ def positional_steps(name, args)
96
+ case name
97
+ when :[] then args.size == 1 ? [index_step(args.first)] : nil
98
+ when :first then args.empty? ? [0] : nil
99
+ when :last then args.empty? ? [-1] : nil
100
+ when :dig then args.empty? ? nil : args.map { |arg| index_step(arg) }
101
+ end
102
+ end
103
+
104
+ # `:all` stands for "some position, not statically known" — every position is widened, which
105
+ # is the only answer that cannot under-approximate.
106
+ def index_step(node)
107
+ node.is_a?(Prism::IntegerNode) ? node.value : :all
108
+ end
109
+
110
+ # The type at `steps` inside `type`, or `nil` when the path does not resolve to a widenable
111
+ # literal-shape carrier.
112
+ def element_at_path(type, steps)
113
+ return MutationWidening.shape_carrier?(type) ? type : nil if steps.empty?
114
+
115
+ case type
116
+ when Type::Tuple
117
+ tuple_positions(type, steps.first).lazy
118
+ .filter_map { |i| element_at_path(type.elements[i], steps.drop(1)) }
119
+ .first
120
+ when Type::Union
121
+ type.members.lazy.filter_map { |member| element_at_path(member, steps) }.first
122
+ end
123
+ end
124
+
125
+ # Rebuilds `type` with the element at `steps` widened against `method_name`, or `nil` when
126
+ # nothing along the path widened. A block, when given, replaces the straight-line widening of the
127
+ # element itself: it receives the element's type and answers the widened one, or `nil` to decline.
128
+ # {UnknownStoreWidening} passes one so a site on an element takes the same unknown-store widening a
129
+ # site on a variable does.
130
+ def widen_through_path(type, steps, method_name, arg_types, &element_widening)
131
+ if steps.empty?
132
+ return element_widening.call(type) if element_widening
133
+
134
+ return MutationWidening.widen_for_mutator(type, method_name, arg_types: arg_types)
135
+ end
136
+
137
+ case type
138
+ when Type::Tuple then widen_tuple_path(type, steps, method_name, arg_types, &element_widening)
139
+ when Type::Union then widen_union_path(type, steps, method_name, arg_types, &element_widening)
140
+ end
141
+ end
142
+
143
+ def widen_tuple_path(tuple, steps, method_name, arg_types, &)
144
+ elements = tuple.elements.dup
145
+ rest = steps.drop(1)
146
+ widened_any = false
147
+ tuple_positions(tuple, steps.first).each do |position|
148
+ inner = widen_through_path(elements[position], rest, method_name, arg_types, &)
149
+ next if inner.nil?
150
+
151
+ elements[position] = inner
152
+ widened_any = true
153
+ end
154
+ widened_any ? Type::Tuple.new(elements) : nil
155
+ end
156
+
157
+ def widen_union_path(union, steps, method_name, arg_types, &)
158
+ widened_any = false
159
+ members = union.members.map do |member|
160
+ widened = widen_through_path(member, steps, method_name, arg_types, &)
161
+ next member if widened.nil?
162
+
163
+ widened_any = true
164
+ widened
165
+ end
166
+ widened_any ? Type::Combinator.union(*members) : nil
167
+ end
168
+
169
+ # An out-of-range literal index selects nothing: the mutation cannot be attributed to any
170
+ # position of THIS tuple, so no widening is justified.
171
+ def tuple_positions(tuple, step)
172
+ size = tuple.elements.size
173
+ return (0...size).to_a if step == :all
174
+
175
+ position = step.negative? ? step + size : step
176
+ position.between?(0, size - 1) ? [position] : []
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,196 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "prism"
4
+
5
+ require_relative "../reflection"
6
+ require_relative "../source/node_children"
7
+ require_relative "../type"
8
+ require_relative "block_call_timing"
9
+
10
+ module Rigor
11
+ module Inference
12
+ # Issue #1360 — `$!`, the exception being rescued, and `$@`, its backtrace. Ruby does not keep them in the method
13
+ # frame's special-variable slot, as it keeps `$~` and `$_`: a read of `$!` walks the running execution context's
14
+ # frames to the nearest rescue frame. So:
15
+ #
16
+ # - inside a `rescue` clause, and inside a rescue modifier's fallback, `$!` is the exception that clause rescued,
17
+ # in every block the clause runs and every method it calls;
18
+ # - once the `begin` or the modifier exits, however it exits, `$!` is what it was before it started: `nil` at the
19
+ # top of a method called from nowhere special, the outer exception after a nested `begin` in a rescue clause;
20
+ # - an `else` clause and the body read that earlier value too, and an `ensure` clause reads it when the body or a
21
+ # rescue clause finished, but the exception in flight when one raised.
22
+ #
23
+ # A method body cannot know what its caller is rescuing, so it starts unbound; a thread's or fiber's root block
24
+ # runs in an execution context of its own, where `$!` is `nil` ({FreshFrameBlocks.entry}); and a closure's body
25
+ # runs whenever it is called, usually after the clause it is written in exited ({FreshFrameBlocks.closure_entry}).
26
+ module ErrorInfo
27
+ ERROR_INFO = :$!
28
+ BACKTRACE = :$@
29
+ NAMES = [ERROR_INFO, BACKTRACE].freeze
30
+ # The globals a rescue modifier's fallback reads differently from the modifier's entry ({.modifier_entry}).
31
+ MODIFIER_NAMES = [ERROR_INFO, BACKTRACE, :$?].freeze
32
+ EXCEPTION_ORDERINGS = Set[:equal, :subclass].freeze
33
+ DEFINERS = Set[:define_method, :define_singleton_method].freeze
34
+ # The class guards a clause may put on `$!` ({.guarded?}).
35
+ GUARDS = Set[:is_a?, :kind_of?, :instance_of?, :respond_to?].freeze
36
+ private_constant :ERROR_INFO, :BACKTRACE, :NAMES, :MODIFIER_NAMES, :EXCEPTION_ORDERINGS, :GUARDS, :DEFINERS
37
+
38
+ module_function
39
+
40
+ # The scope a `rescue` clause, or a rescue modifier's fallback, runs from: `$!` bound to the exception it rescued
41
+ # and `$@` to that exception's backtrace, with `$?` unbound. `exception_type` is what `rescue … => e` binds `e` to
42
+ # (`StatementEvaluator#rescue_exception_type`): the union of the named classes' instances, `StandardError` for a
43
+ # bare `rescue`. A member that is not a class RBS or the program places below `Exception` reads `Dynamic[top]`
44
+ # instead: a rescue list may name a module with its own `===` (`rescue NetworkErrors`), which matches exceptions
45
+ # that are not instances of it, and a class the analyzer cannot place may be such an object too. So does a class
46
+ # that it or a project ancestor gives its own singleton `===` (`class Matchy < StandardError; def self.===(o) =
47
+ # true`).
48
+ #
49
+ # `body` is the clause's statements or the fallback, and `reference` the name of the local a `rescue … => e`
50
+ # clause binds. When the body guards `$!`, or that local, which is the same object, by its class ({.guarded?}),
51
+ # the clause reads `$!` and `$@` unbound, as it did before issue #1360: `$!.key if e.is_a?(KeyError)` would report
52
+ # the bound `StandardError` against the guard (ADR-117, point 3), since narrowing `e` does not narrow `$!`. #1429
53
+ # made a class guard on `$!` itself narrow it; #1447 narrows this decline to the guards that still do not.
54
+ #
55
+ # `$@` calls the exception's `backtrace`, which is an `Array[String]` for a raised exception. It is left unbound
56
+ # in a program that defines a method named `backtrace` anywhere, which may return anything, and in a clause
57
+ # whose body calls `set_backtrace`, which may set it to nil.
58
+ #
59
+ # `$?` is unbound because the exception may have been raised while a subprocess waited: a backtick, `%x` or
60
+ # `system` sets `$?` to nil before it runs the child, so a `Timeout::Error`, an `Interrupt` or a `Thread#raise`
61
+ # there leaves it nil.
62
+ def rescue_entry(scope, exception_type, body = nil, reference = nil)
63
+ entered = scope.forget_error_info.forget_last_status
64
+ # Narrowed to the guards #1429 does not narrow in #1447.
65
+ return entered if guarded?(body, reference)
66
+
67
+ entered = entered.with_global(ERROR_INFO, rescued_type(exception_type, scope))
68
+ return entered if calls_set_backtrace?(body) || BlockCallTiming.project_defines_anywhere?(:backtrace, scope)
69
+
70
+ entered.with_global(BACKTRACE, backtrace_type)
71
+ end
72
+
73
+ # The scope a rescue modifier's fallback (`expr rescue fallback`) runs from, which rescues a `StandardError`.
74
+ def modifier_entry(scope, fallback = nil)
75
+ rescue_entry(scope, Type::Combinator.nominal_of("StandardError"), fallback)
76
+ end
77
+
78
+ # The class guards on `$!` that {.rescue_entry} declines on, anywhere in `node`: `$!.is_a?`, `kind_of?`,
79
+ # `instance_of?` or `respond_to?`, a `===` whose argument is `$!` (`KeyError === $!`), and `case $!`, and the
80
+ # same on a read of the local named `reference`.
81
+ def guarded?(node, reference = nil)
82
+ return false unless node.is_a?(Prism::Node)
83
+ return true if guard?(node, reference)
84
+
85
+ found = false
86
+ node.rigor_each_child { |child| found ||= guarded?(child, reference) }
87
+ found
88
+ end
89
+
90
+ def guard?(node, reference)
91
+ case node
92
+ when Prism::CallNode
93
+ (GUARDS.include?(node.name) && error_info_read?(node.receiver, reference)) ||
94
+ (node.name == :=== && error_info_read?(node.arguments&.arguments&.first, reference))
95
+ when Prism::CaseNode, Prism::CaseMatchNode then error_info_read?(node.predicate, reference)
96
+ else false
97
+ end
98
+ end
99
+
100
+ def error_info_read?(node, reference)
101
+ case node
102
+ when Prism::GlobalVariableReadNode then node.name == ERROR_INFO
103
+ when Prism::LocalVariableReadNode then !reference.nil? && node.name == reference
104
+ else false
105
+ end
106
+ end
107
+
108
+ # True when `node` calls `set_backtrace` anywhere, on any receiver: `$!.set_backtrace(nil)` makes `$@` nil.
109
+ def calls_set_backtrace?(node)
110
+ return false unless node.is_a?(Prism::Node)
111
+ return true if node.is_a?(Prism::CallNode) && node.name == :set_backtrace
112
+
113
+ found = false
114
+ node.rigor_each_child { |child| found ||= calls_set_backtrace?(child) }
115
+ found
116
+ end
117
+ private_class_method :guard?, :error_info_read?, :calls_set_backtrace?
118
+
119
+ # True when `node` reads `$!`, `$@` or `$?` anywhere in it: the gate on typing a rescue modifier's fallback
120
+ # under {.modifier_entry}, which most fallbacks (`rescue nil`) never need.
121
+ def read_in?(node)
122
+ return false unless node.is_a?(Prism::Node)
123
+ return MODIFIER_NAMES.include?(node.name) if node.is_a?(Prism::GlobalVariableReadNode)
124
+
125
+ found = false
126
+ node.rigor_each_child { |child| found ||= read_in?(child) }
127
+ found
128
+ end
129
+
130
+ # `scope` with `$!` and `$@` as `entry` binds them, and unbound where `entry` leaves them unbound: the scope past
131
+ # a `begin` or a rescue modifier that started from `entry`, whichever way it left.
132
+ def restore(scope, entry)
133
+ return scope if NAMES.all? { |name| scope.global(name).equal?(entry.global(name)) }
134
+
135
+ NAMES.reduce(scope.forget_error_info) do |acc, name|
136
+ bound = entry.global(name)
137
+ bound ? acc.with_global(name, bound) : acc
138
+ end
139
+ end
140
+
141
+ def rescued_type(exception_type, scope)
142
+ members = exception_type.is_a?(Type::Union) ? exception_type.members : [exception_type]
143
+ return exception_type if members.all? { |member| exception_instance?(member, scope) }
144
+
145
+ Type::Combinator.union(
146
+ *members.map { |member| exception_instance?(member, scope) ? member : Type::Combinator.untyped }
147
+ )
148
+ end
149
+
150
+ # True when `type` is an instance of a class below `Exception`: one RBS places there, or a project class whose
151
+ # superclass chain reaches one (`class MyError < StandardError`), which the RBS environment does not know.
152
+ def exception_instance?(type, scope)
153
+ return false unless type.is_a?(Type::Nominal)
154
+
155
+ class_name = type.class_name
156
+ return false if own_case_equality?(class_name, scope)
157
+ return true if exception_class?(class_name, scope)
158
+ return false unless scope.known_user_class?(class_name)
159
+
160
+ scope.external_ancestor_name_candidates(class_name, mixins: false).any? do |candidates|
161
+ known = candidates.find { |candidate| Reflection.rbs_class_known?(candidate, scope: scope) }
162
+ !known.nil? && exception_class?(known, scope)
163
+ end
164
+ rescue StandardError
165
+ false
166
+ end
167
+
168
+ # True when the program gives `class_name`, or a project ancestor of it, a singleton `===`, which `rescue` calls
169
+ # to match and which may accept an exception that is not an instance of it: a `def self.===` or `class << self`
170
+ # `def ===`, or, anywhere in the file being read, a `define_method` or `define_singleton_method` naming `===`
171
+ # ({.defines_case_equality?}), which the discovery tables do not place on a class, so it counts for every class.
172
+ def own_case_equality?(class_name, scope)
173
+ scope.discovery.defines_case_equality ||
174
+ !scope.singleton_def_through_ancestors(class_name, :===).first.nil?
175
+ end
176
+
177
+ # True when `node` is a `define_method` or `define_singleton_method` call whose literal name is `===`.
178
+ # `Inference::ScopeIndexer` records whether a file holds one ({Scope::DiscoveryIndex#defines_case_equality}).
179
+ def defines_case_equality?(node)
180
+ return false unless node.is_a?(Prism::CallNode) && DEFINERS.include?(node.name)
181
+
182
+ name = node.arguments&.arguments&.first
183
+ (name.is_a?(Prism::SymbolNode) || name.is_a?(Prism::StringNode)) && name.unescaped == "==="
184
+ end
185
+
186
+ def exception_class?(class_name, scope)
187
+ EXCEPTION_ORDERINGS.include?(scope.environment.class_ordering(class_name, "Exception"))
188
+ end
189
+
190
+ def backtrace_type
191
+ Type::Combinator.nominal_of("Array", type_args: [Type::Combinator.nominal_of("String")])
192
+ end
193
+ private_class_method :rescued_type, :exception_instance?, :own_case_equality?, :exception_class?, :backtrace_type
194
+ end
195
+ end
196
+ end