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
@@ -5,9 +5,8 @@ require "prism"
5
5
  module Rigor
6
6
  module Plugin
7
7
  class Sorbet < Rigor::Plugin::Base
8
- # Maps Sorbet's type expressions (the AST inside a `sig`
9
- # block's `params(...)` and `returns(...)` clauses) into
10
- # Rigor's internal type carriers.
8
+ # Maps Sorbet's type expressions (the AST inside a `sig` block's `params(...)` and `returns(...)`
9
+ # clauses) into Rigor's internal type carriers.
11
10
  #
12
11
  # | Sorbet form | Rigor carrier |
13
12
  # | ------------------------ | ---------------------------------------- |
@@ -32,18 +31,14 @@ module Rigor
32
31
  # | `{a: A, b: B}` (shape) | `HashShape{a: A, b: B}` (closed) |
33
32
  # | `Foo::Bar[A, B]` (user) | `Nominal["Foo::Bar", [A, B]]` |
34
33
  #
35
- # Anything else (`T.proc`, `T.attached_class`,
36
- # `T.self_type`, `T.type_parameter`, `T::Struct` / `T::Enum`
37
- # subclasses, …) degrades silently to `Dynamic[top]`. The
38
- # `dynamic.sorbet.unsupported` diagnostic for degraded
39
- # forms is deferred.
34
+ # Anything else (`T.proc`, `T.attached_class`, `T.self_type`, `T.type_parameter`, `T::Struct` /
35
+ # `T::Enum` subclasses, …) degrades silently to `Dynamic[top]`. The `dynamic.sorbet.unsupported`
36
+ # diagnostic for degraded forms is deferred.
40
37
  module TypeTranslator
41
38
  BOOLEAN_NAME = "Boolean"
42
39
 
43
- # `T::*` constants whose `[]` application maps directly
44
- # onto a Rigor `Nominal` with the matching standard-
45
- # library class name. Ordering matches the table above
46
- # for ease of reading.
40
+ # `T::*` constants whose `[]` application maps directly onto a Rigor `Nominal` with the matching
41
+ # standard-library class name. Ordering matches the table above for ease of reading.
47
42
  T_GENERIC_CLASSES = {
48
43
  "Array" => "Array",
49
44
  "Hash" => "Hash",
@@ -58,8 +53,7 @@ module Rigor
58
53
  module_function
59
54
 
60
55
  # @param node [Prism::Node, nil]
61
- # @return [Rigor::Type] never `nil`; unrecognised forms
62
- # degrade to `Type::Combinator.untyped`.
56
+ # @return [Rigor::Type] never `nil`; unrecognised forms degrade to `Type::Combinator.untyped`.
63
57
  def translate(node)
64
58
  return Rigor::Type::Combinator.untyped if node.nil?
65
59
 
@@ -86,8 +80,8 @@ module Rigor
86
80
  name = constant_path_name(node)
87
81
  return degraded if name.nil?
88
82
 
89
- # Sorbet's `T::Boolean` is a special alias rather than a
90
- # nominal class, expressed as the Boolean type alias.
83
+ # Sorbet's `T::Boolean` is a special alias rather than a nominal class, expressed as the Boolean
84
+ # type alias.
91
85
  return boolean_type if name == "T::Boolean"
92
86
 
93
87
  Rigor::Type::Combinator.nominal_of(name)
@@ -95,20 +89,16 @@ module Rigor
95
89
 
96
90
  # `Prism::CallNode` covers three distinct surfaces:
97
91
  #
98
- # 1. `T.something(...)` — `untyped` / `anything` /
99
- # `noreturn` / `nilable` / `any` / `all` / `class_of`.
100
- # 2. `T::SomeClass[...]` — the `[]` method on a generic
101
- # `T::*` constant (slice 3 widening). Maps to
102
- # `Nominal[name, type_args]`.
103
- # 3. `Some::User::Generic[...]` the `[]` method on any
104
- # OTHER constant (a user-defined generic application,
105
- # e.g. `Mangrove::Result::Ok[String, StandardError]`).
106
- # Maps to `Nominal[name, type_args]` so generic carriers
107
- # authored outside Sorbet's `T::*` set round-trip with
108
- # their instantiation intact (the unwrap-site receiver a
109
- # plugin like rigor-mangrove reads `type_args` from).
110
- # Without this branch such forms degraded to `untyped`,
111
- # silently dropping the receiver's generic arguments.
92
+ # 1. `T.something(...)` — `untyped` / `anything` / `noreturn` / `nilable` / `any` / `all` /
93
+ # `class_of`.
94
+ # 2. `T::SomeClass[...]` — the `[]` method on a generic `T::*` constant (slice 3 widening). Maps
95
+ # to `Nominal[name, type_args]`.
96
+ # 3. `Some::User::Generic[...]` — the `[]` method on any OTHER constant (a user-defined generic
97
+ # application, e.g. `Mangrove::Result::Ok[String, StandardError]`). Maps to `Nominal[name,
98
+ # type_args]` so generic carriers authored outside Sorbet's `T::*` set round-trip with their
99
+ # instantiation intact (the unwrap-site receiver a plugin like rigor-mangrove reads `type_args`
100
+ # from). Without this branch such forms degraded to `untyped`, silently dropping the
101
+ # receiver's generic arguments.
112
102
  def translate_call(node)
113
103
  return translate_t_method(node) if sorbet_t_namespaced?(node.receiver)
114
104
  return translate_t_subscript(node) if sorbet_subscript?(node)
@@ -154,11 +144,9 @@ module Rigor
154
144
  Rigor::Type::Combinator.intersection(*args.map { |arg| translate(arg) })
155
145
  end
156
146
 
157
- # `T.class_of(C)` — singleton-class type for a single
158
- # constant. Sorbet docs note `T.class_of(MyInterface)`
159
- # rarely means what users expect (it's the singleton
160
- # class of `MyInterface`, not "any class implementing
161
- # the interface"); we honour the literal meaning here
147
+ # `T.class_of(C)` — singleton-class type for a single constant. Sorbet docs note
148
+ # `T.class_of(MyInterface)` rarely means what users expect (it's the singleton class of
149
+ # `MyInterface`, not "any class implementing the interface"); we honour the literal meaning here
162
150
  # and translate to `Singleton[C]`.
163
151
  def translate_class_of(node)
164
152
  target = first_argument(node)
@@ -168,14 +156,10 @@ module Rigor
168
156
  Rigor::Type::Combinator.singleton_of(name)
169
157
  end
170
158
 
171
- # Handles `T::Array[E]`, `T::Hash[K, V]`, etc. The Prism
172
- # AST for `T::Array[Integer]` is a `CallNode` whose
173
- # receiver is the `T::Array` `ConstantPathNode` and
174
- # whose `name` is `:[]`. `T::Class[T]` lands here too;
175
- # we collapse it to `Singleton[name]` (a deliberate
176
- # narrowing — `T::Class` is structurally generic in
177
- # Sorbet, but Rigor's `Singleton` carries class identity
178
- # only).
159
+ # Handles `T::Array[E]`, `T::Hash[K, V]`, etc. The Prism AST for `T::Array[Integer]` is a
160
+ # `CallNode` whose receiver is the `T::Array` `ConstantPathNode` and whose `name` is `:[]`.
161
+ # `T::Class[T]` lands here too; we collapse it to `Singleton[name]` (a deliberate narrowing —
162
+ # `T::Class` is structurally generic in Sorbet, but Rigor's `Singleton` carries class identity only).
179
163
  def translate_t_subscript(node)
180
164
  base_name = sorbet_subscript_base(node.receiver)
181
165
  args = call_arguments(node).map { |arg| translate(arg) }
@@ -190,14 +174,11 @@ module Rigor
190
174
  end
191
175
  end
192
176
 
193
- # A user-defined generic application — a `[]` call on a
194
- # constant that is NOT `T`-rooted, e.g.
195
- # `Mangrove::Result::Ok[String, StandardError]` or a
196
- # top-level `Box[Integer]`. Translates to
197
- # `Nominal[name, type_args]`, recursively translating each
198
- # argument (so nested `T::Array[...]` inside a user generic
199
- # still resolves). Ordered AFTER `translate_t_subscript` in
200
- # `translate_call`, so the `T::*` forms never reach here.
177
+ # A user-defined generic application — a `[]` call on a constant that is NOT `T`-rooted, e.g.
178
+ # `Mangrove::Result::Ok[String, StandardError]` or a top-level `Box[Integer]`. Translates to
179
+ # `Nominal[name, type_args]`, recursively translating each argument (so nested `T::Array[...]`
180
+ # inside a user generic still resolves). Ordered AFTER `translate_t_subscript` in `translate_call`,
181
+ # so the `T::*` forms never reach here.
201
182
  def user_generic_subscript?(node)
202
183
  return false unless node.name == :[]
203
184
 
@@ -205,15 +186,14 @@ module Rigor
205
186
  return false unless receiver.is_a?(Prism::ConstantReadNode) ||
206
187
  receiver.is_a?(Prism::ConstantPathNode)
207
188
 
208
- # `T::Foo[...]` is handled by translate_t_subscript; only
209
- # non-`T`-rooted constants are user generics.
189
+ # `T::Foo[...]` is handled by translate_t_subscript; only non-`T`-rooted constants are user
190
+ # generics.
210
191
  !sorbet_t_qualified?(receiver)
211
192
  end
212
193
 
213
194
  def translate_user_subscript(node)
214
- # Parity with translate_constant_path: the constant's
215
- # rendered name (carrying a leading `::` for absolute
216
- # paths) becomes the nominal class name.
195
+ # Parity with translate_constant_path: the constant's rendered name (carrying a leading `::` for
196
+ # absolute paths) becomes the nominal class name.
217
197
  name = constant_path_name(node.receiver)
218
198
  return degraded if name.nil?
219
199
 
@@ -221,13 +201,10 @@ module Rigor
221
201
  Rigor::Type::Combinator.nominal_of(name, type_args: args)
222
202
  end
223
203
 
224
- # `T::Class[T]` — Sorbet's "any class object whose
225
- # instances are at least `T`". Rigor has no exact
226
- # analogue (Singleton names a specific class); the
227
- # closest faithful translation is `Singleton[name]`
228
- # when `T` is a constant, or `Singleton[Object]` for
229
- # broader applications. Lossy — the `dynamic.sorbet.degraded`
230
- # diagnostic for this case is deferred.
204
+ # `T::Class[T]` — Sorbet's "any class object whose instances are at least `T`". Rigor has no exact
205
+ # analogue (Singleton names a specific class); the closest faithful translation is `Singleton[name]`
206
+ # when `T` is a constant, or `Singleton[Object]` for broader applications. Lossy — the
207
+ # `dynamic.sorbet.degraded` diagnostic for this case is deferred.
231
208
  def translate_t_class_subscript(args)
232
209
  inner = args.first
233
210
  return Rigor::Type::Combinator.singleton_of("Class") if inner.nil?
@@ -238,20 +215,16 @@ module Rigor
238
215
  end
239
216
  end
240
217
 
241
- # Tuple types in `sig` position appear as bare array
242
- # literals: `sig { returns([String, Integer]) }`. Each
243
- # element is itself a type expression we translate
244
- # recursively.
218
+ # Tuple types in `sig` position appear as bare array literals: `sig { returns([String, Integer]) }`.
219
+ # Each element is itself a type expression we translate recursively.
245
220
  def translate_tuple(node)
246
221
  elements = node.elements.map { |element| translate(element) }
247
222
  Rigor::Type::Combinator.tuple_of(*elements)
248
223
  end
249
224
 
250
- # Shape types in `sig` position appear as bare hash
251
- # literals with symbol keys:
252
- # `sig { returns({a: Integer, b: String}) }`. Each
253
- # value is a type expression; the resulting `HashShape`
254
- # is closed (no extra keys allowed).
225
+ # Shape types in `sig` position appear as bare hash literals with symbol keys:
226
+ # `sig { returns({a: Integer, b: String}) }`. Each value is a type expression; the resulting
227
+ # `HashShape` is closed (no extra keys allowed).
255
228
  def translate_shape(node)
256
229
  pairs = []
257
230
  node.elements.each do |element|
@@ -263,9 +236,8 @@ module Rigor
263
236
  Rigor::Type::Combinator.hash_shape_of(pairs)
264
237
  end
265
238
 
266
- # Renders a constant-path node (`Foo::Bar`, `::Foo::Bar`)
267
- # as a `::`-joined String. Mirrors the helper used by
268
- # rigor-activerecord's ModelDiscoverer for parity.
239
+ # Renders a constant-path node (`Foo::Bar`, `::Foo::Bar`) as a `::`-joined String. Mirrors the
240
+ # helper used by rigor-activerecord's ModelDiscoverer for parity.
269
241
  def constant_path_name(node)
270
242
  return nil if node.nil?
271
243
 
@@ -294,9 +266,8 @@ module Rigor
294
266
  receiver.is_a?(Prism::ConstantReadNode) && receiver.name == :T
295
267
  end
296
268
 
297
- # `T::Array[Integer]` parses as `CallNode(receiver: T::Array, name: :[])`.
298
- # The receiver is a `ConstantPathNode` rooted at the
299
- # `T` constant.
269
+ # `T::Array[Integer]` parses as `CallNode(receiver: T::Array, name: :[])`. The receiver is a
270
+ # `ConstantPathNode` rooted at the `T` constant.
300
271
  def sorbet_subscript?(node)
301
272
  node.name == :[] && sorbet_t_qualified?(node.receiver)
302
273
  end
@@ -304,16 +275,14 @@ module Rigor
304
275
  def sorbet_t_qualified?(node)
305
276
  return false unless node.is_a?(Prism::ConstantPathNode)
306
277
 
307
- # Walk to the root; require that it terminates at a
308
- # `T` ConstantReadNode (not an absolute `::T`).
278
+ # Walk to the root; require that it terminates at a `T` ConstantReadNode (not an absolute `::T`).
309
279
  current = node
310
280
  current = current.parent while current.is_a?(Prism::ConstantPathNode)
311
281
  current.is_a?(Prism::ConstantReadNode) && current.name == :T
312
282
  end
313
283
 
314
- # Strips the leading `T::` from a `T::Foo::Bar`
315
- # constant-path node, returning `"Foo::Bar"`. Returns
316
- # nil for shapes that aren't `T`-rooted.
284
+ # Strips the leading `T::` from a `T::Foo::Bar` constant-path node, returning `"Foo::Bar"`.
285
+ # Returns nil for shapes that aren't `T`-rooted.
317
286
  def sorbet_subscript_base(node)
318
287
  return nil unless sorbet_t_qualified?(node)
319
288
 
@@ -338,11 +307,9 @@ module Rigor
338
307
  Rigor::Type::Combinator.untyped
339
308
  end
340
309
 
341
- # `T::Boolean` corresponds to the union of the singleton
342
- # `true` / `false` values, matching how RBS's `bool`
343
- # would translate. Built from `Constant[true]` /
344
- # `Constant[false]` so the analyzer's flow-sensitive
345
- # narrowing recognises the discriminating shape.
310
+ # `T::Boolean` corresponds to the union of the singleton `true` / `false` values, matching how
311
+ # RBS's `bool` would translate. Built from `Constant[true]` / `Constant[false]` so the analyzer's
312
+ # flow-sensitive narrowing recognises the discriminating shape.
346
313
  def boolean_type
347
314
  Rigor::Type::Combinator.union(
348
315
  Rigor::Type::Combinator.constant_of(true),