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,76 +5,55 @@ require_relative "../../type"
5
5
  module Rigor
6
6
  module Inference
7
7
  module MethodDispatcher
8
- # Dispatcher tier that lifts string-composition results into
9
- # the `literal-string` carrier when every operand is itself
10
- # literal-bearing. Sits between {ConstantFolding} (which
11
- # handles all-Constant cases) and {ShapeDispatch}; runs for:
8
+ # Dispatcher tier that lifts string-composition results into the `literal-string` carrier when every
9
+ # operand is itself literal-bearing. Sits between {ConstantFolding} (which handles all-Constant cases)
10
+ # and {ShapeDispatch}; runs for:
12
11
  #
13
- # - `String#+` / `String#*` / `String#<<` / `String#concat`
14
- # on string-typed receivers whose inputs the
15
- # ConstantFolding tier could not fold to a precise
16
- # `Constant<String>` (e.g. one operand is `literal-string`
17
- # rather than `Constant<String>`, or the multiplication
18
- # exceeds the constant-fold size cap).
19
- # - `Array#join` on `Tuple[…]` receivers whose every element
20
- # plus the separator argument (when given) is
21
- # literal-bearing.
22
- # - `Kernel#format` / `Kernel#sprintf` (any receiver) and
23
- # `String#%` (literal-bearing receiver) when every value
24
- # argument is literal-bearing or a Type::Constant of any
25
- # value.
12
+ # - `String#+` / `String#*` / `String#<<` / `String#concat` on string-typed receivers whose inputs
13
+ # the ConstantFolding tier could not fold to a precise `Constant<String>` (e.g. one operand is
14
+ # `literal-string` rather than `Constant<String>`, or the multiplication exceeds the constant-fold
15
+ # size cap).
16
+ # - `Array#join` on `Tuple[…]` receivers whose every element plus the separator argument (when given)
17
+ # is literal-bearing.
18
+ # - `Kernel#format` / `Kernel#sprintf` (any receiver) and `String#%` (literal-bearing receiver) when
19
+ # every value argument is literal-bearing or a Type::Constant of any value.
26
20
  #
27
21
  # Result rule:
28
22
  #
29
23
  # - `+`, `<<`, `concat`: receiver and argument MUST both be
30
- # `Type::Combinator.literal_string_compatible?`. The result
31
- # is `literal-string`. `<<` and `concat` mutate the
32
- # receiver at runtime; the analyzer does not track that
33
- # mutation against the local's binding, but the call's
34
- # *return value* is the receiver itself, and the receiver
35
- # stays literal-bearing because every appended slice was
36
- # literal-bearing too.
37
- # - `*`: receiver MUST be literal-bearing; argument MUST be
38
- # integer-typed. The result is `literal-string`.
39
- # - `join`: receiver MUST be `Tuple[…]` with every element
40
- # literal-string-compatible; the optional separator
41
- # argument MUST also be literal-string-compatible.
42
- # Result: `literal-string`. Empty `Tuple[]` lifts too —
43
- # `[].join` is the empty string at runtime, which is
44
- # literal-bearing trivially.
24
+ # `Type::Combinator.literal_string_compatible?`. The result is `literal-string`. `<<` and `concat`
25
+ # mutate the receiver at runtime; the analyzer does not track that mutation against the local's
26
+ # binding, but the call's *return value* is the receiver itself, and the receiver stays
27
+ # literal-bearing because every appended slice was literal-bearing too.
28
+ # - `*`: receiver MUST be literal-bearing; argument MUST be integer-typed. The result is
29
+ # `literal-string`.
30
+ # - `join`: receiver MUST be `Tuple[…]` with every element literal-string-compatible; the optional
31
+ # separator argument MUST also be literal-string-compatible. Result: `literal-string`. Empty
32
+ # `Tuple[]` lifts too — `[].join` is the empty string at runtime, which is literal-bearing
33
+ # trivially.
45
34
  #
46
- # Other receiver / argument shapes decline so the next tier
47
- # (ShapeDispatch / FileFolding / RbsDispatch) takes over and
48
- # the call site widens to the RBS-declared `Nominal[String]`
49
- # as before.
35
+ # Other receiver / argument shapes decline so the next tier (ShapeDispatch / FileFolding /
36
+ # RbsDispatch) takes over and the call site widens to the RBS-declared `Nominal[String]` as before.
50
37
  module LiteralStringFolding
51
38
  module_function
52
39
 
53
40
  CONCAT_METHODS = %i[+ << concat].freeze
54
41
  FORMAT_METHODS = %i[format sprintf].freeze
55
- # v0.1.1 Track 1 slice 5a — methods that, called with no
56
- # arguments on a literal-bearing receiver, return a value
57
- # that is also literal-bearing. `#strip` / `#lstrip` /
58
- # `#rstrip` / `#chomp` (no-arg) / `#chop` strip a known
59
- # subset of characters from the ends, so the survivors
60
- # are always a substring of an already-literal value.
61
- # `#scrub` (no-arg) replaces invalid bytes; a literal-string
62
- # value comes from source code and is always valid UTF-8,
63
- # so the result is identical to the receiver. None of
64
- # these preserve `non-empty-string`-ness (e.g. `" ".strip
65
- # == ""`); the carrier collapses from `non-empty-literal-string`
66
- # down to plain `literal-string`.
42
+ # v0.1.1 Track 1 slice 5a — methods that, called with no arguments on a literal-bearing receiver,
43
+ # return a value that is also literal-bearing. `#strip` / `#lstrip` / `#rstrip` / `#chomp` (no-arg)
44
+ # / `#chop` strip a known subset of characters from the ends, so the survivors are always a
45
+ # substring of an already-literal value. `#scrub` (no-arg) replaces invalid bytes; a literal-string
46
+ # value comes from source code and is always valid UTF-8, so the result is identical to the
47
+ # receiver. None of these preserve `non-empty-string`-ness (e.g. `" ".strip == ""`); the carrier
48
+ # collapses from `non-empty-literal-string` down to plain `literal-string`.
67
49
  LITERAL_PRESERVING_METHODS = %i[strip lstrip rstrip chomp chop scrub].freeze
68
- # Methods that preserve literal-bearing AND non-empty-string-ness.
69
- # Unlike `LITERAL_PRESERVING_METHODS` (strip/chomp/etc.) these do
70
- # not reduce the string they transform characters without
71
- # removing any, so a non-empty receiver stays non-empty.
50
+ # Methods that preserve literal-bearing AND non-empty-string-ness. Unlike `LITERAL_PRESERVING_METHODS`
51
+ # (strip/chomp/etc.) these do not reduce the string — they transform characters without removing
52
+ # any, so a non-empty receiver stays non-empty.
72
53
  NON_EMPTY_LITERAL_PRESERVING_METHODS = %i[upcase downcase capitalize swapcase reverse].freeze
73
- # v0.1.1 Track 1 slice 5c — width-padding methods. `center`
74
- # / `ljust` / `rjust` take a `width` Integer plus an
75
- # optional literal padding `String`. When the receiver
76
- # and the (default or supplied) padding are both
77
- # literal-bearing, the result is literal-bearing too.
54
+ # v0.1.1 Track 1 slice 5c — width-padding methods. `center` / `ljust` / `rjust` take a `width`
55
+ # Integer plus an optional literal padding `String`. When the receiver and the (default or
56
+ # supplied) padding are both literal-bearing, the result is literal-bearing too.
78
57
  WIDTH_PADDING_METHODS = %i[center ljust rjust].freeze
79
58
  private_constant :CONCAT_METHODS, :FORMAT_METHODS,
80
59
  :LITERAL_PRESERVING_METHODS, :NON_EMPTY_LITERAL_PRESERVING_METHODS,
@@ -106,15 +85,11 @@ module Rigor
106
85
  nil
107
86
  end
108
87
 
109
- # `String#center` / `#ljust` / `#rjust` — first argument is
110
- # the target width (Integer-typed), optional second
111
- # argument is the padding string (must be literal-bearing
112
- # for the result to stay literal). The default padding
113
- # (a space) is always literal so the no-second-arg form
114
- # passes through. Width is allowed to be any Integer
115
- # because Ruby's runtime accepts negative widths and
116
- # widths smaller than the receiver's length without
117
- # raising.
88
+ # `String#center` / `#ljust` / `#rjust` — first argument is the target width (Integer-typed),
89
+ # optional second argument is the padding string (must be literal-bearing for the result to stay
90
+ # literal). The default padding (a space) is always literal so the no-second-arg form passes
91
+ # through. Width is allowed to be any Integer because Ruby's runtime accepts negative widths and
92
+ # widths smaller than the receiver's length without raising.
118
93
  def fold_width_pad(args)
119
94
  return nil unless [1, 2].include?(args.size)
120
95
  return nil unless integer_typed?(args[0])
@@ -146,8 +121,8 @@ module Rigor
146
121
  Type::Combinator.literal_string
147
122
  end
148
123
 
149
- # Returns `non_empty_literal_string` when the receiver is provably
150
- # non-empty; otherwise collapses to plain `literal_string`.
124
+ # Returns `non_empty_literal_string` when the receiver is provably non-empty; otherwise collapses
125
+ # to plain `literal_string`.
151
126
  def non_empty_literal_result(receiver)
152
127
  if Type::Combinator.non_empty_string_compatible?(receiver)
153
128
  Type::Combinator.non_empty_literal_string
@@ -156,12 +131,10 @@ module Rigor
156
131
  end
157
132
  end
158
133
 
159
- # `[lit, lit].join(sep)` — receiver must be a Tuple
160
- # whose every element is literal-bearing; separator
161
- # (when given) must be literal-bearing too. Multi-arg
162
- # forms / `Array#join(*args)` splat shapes don't reach
163
- # here because the dispatcher only routes through this
164
- # tier when the call resolves to a single named method.
134
+ # `[lit, lit].join(sep)` — receiver must be a Tuple whose every element is literal-bearing;
135
+ # separator (when given) must be literal-bearing too. Multi-arg forms / `Array#join(*args)` splat
136
+ # shapes don't reach here because the dispatcher only routes through this tier when the call
137
+ # resolves to a single named method.
165
138
  def fold_array_join(receiver, args)
166
139
  return nil unless receiver.is_a?(Type::Tuple)
167
140
  return nil unless receiver.elements.all? { |el| Type::Combinator.literal_string_compatible?(el) }
@@ -171,15 +144,11 @@ module Rigor
171
144
  Type::Combinator.literal_string
172
145
  end
173
146
 
174
- # `format("hello %s", lit)` / `sprintf(...)` — template
175
- # plus every value argument must be literal-bearing
176
- # ({Type::Combinator.literal_string_compatible?}) or a
177
- # `Type::Constant` of any value (Constants are always
178
- # provably literal). The template arg specifically must
179
- # be literal-bearing — a Constant<Integer> first arg
180
- # would not be a valid format template, so the
181
- # `Type::Constant` allowance applies only to subsequent
182
- # value args.
147
+ # `format("hello %s", lit)` / `sprintf(...)` — template plus every value argument must be
148
+ # literal-bearing ({Type::Combinator.literal_string_compatible?}) or a `Type::Constant` of any
149
+ # value (Constants are always provably literal). The template arg specifically must be
150
+ # literal-bearing — a Constant<Integer> first arg would not be a valid format template, so the
151
+ # `Type::Constant` allowance applies only to subsequent value args.
183
152
  def fold_format(args)
184
153
  return nil if args.empty?
185
154
  return nil unless Type::Combinator.literal_string_compatible?(args.first)
@@ -188,18 +157,14 @@ module Rigor
188
157
  Type::Combinator.literal_string
189
158
  end
190
159
 
191
- # `"foo %s" % "x"` / `"foo %s" % ["x", "y"]` — receiver
192
- # is the template (already verified literal-bearing by
193
- # the caller); arg is either:
160
+ # `"foo %s" % "x"` / `"foo %s" % ["x", "y"]` — receiver is the template (already verified
161
+ # literal-bearing by the caller); arg is either:
194
162
  #
195
163
  # - a single literal-bearing string / Constant value, or
196
- # - a Tuple whose every element is literal-bearing or a
197
- # Constant.
164
+ # - a Tuple whose every element is literal-bearing or a Constant.
198
165
  #
199
- # Hash-form `%` (e.g. `"%{name}" % {name: "x"}`) is not
200
- # yet folded the analyzer's HashShape carrier could
201
- # support this, but the v0.0.x catalogue declines and
202
- # widens to Nominal[String].
166
+ # Hash-form `%` (e.g. `"%{name}" % {name: "x"}`) is not yet folded — the analyzer's HashShape
167
+ # carrier could support this, but the v0.0.x catalogue declines and widens to Nominal[String].
203
168
  def fold_string_percent(args)
204
169
  return nil unless args.size == 1
205
170
 
@@ -228,11 +193,9 @@ module Rigor
228
193
  end
229
194
  end
230
195
 
231
- # `String#*` raises ArgumentError on a negative multiplier, so a
232
- # `Constant<-1>` argument is not a valid lift target. Decline so
233
- # the call site keeps the existing nil-result behaviour rather
234
- # than promising a `literal-string` value that could never
235
- # exist at runtime.
196
+ # `String#*` raises ArgumentError on a negative multiplier, so a `Constant<-1>` argument is not a
197
+ # valid lift target. Decline so the call site keeps the existing nil-result behaviour rather than
198
+ # promising a `literal-string` value that could never exist at runtime.
236
199
  def known_negative_integer?(type)
237
200
  type.is_a?(Type::Constant) && type.value.is_a?(Integer) && type.value.negative?
238
201
  end
@@ -6,43 +6,34 @@ require_relative "singleton_folding"
6
6
  module Rigor
7
7
  module Inference
8
8
  module MethodDispatcher
9
- # Folds `Math` module-function calls on statically known numeric
10
- # constants.
9
+ # Folds `Math` module-function calls on statically known numeric constants.
11
10
  #
12
- # `Math` is a pure, side-effect-free module whose functions are
13
- # deterministic over their inputs the same number always
14
- # produces the same result. When every relevant argument is a
15
- # `Constant` carrying a `Numeric` value, the analyzer evaluates
16
- # the call at inference time and returns the concrete result.
11
+ # `Math` is a pure, side-effect-free module whose functions are deterministic over their inputs — the
12
+ # same number always produces the same result. When every relevant argument is a `Constant` carrying
13
+ # a `Numeric` value, the analyzer evaluates the call at inference time and returns the concrete
14
+ # result.
17
15
  #
18
16
  # === Supported methods
19
17
  #
20
- # * Single-argument transcendental functions (`sqrt`, `cbrt`,
21
- # `exp`, `log2`, `log10`, `log1p`, `expm1`, `sin`, `cos`,
22
- # `tan`, `asin`, `acos`, `atan`, `sinh`, `cosh`, `tanh`,
23
- # `asinh`, `acosh`, `atanh`, `erf`, `erfc`, `gamma`) — return
24
- # `Constant[Float]`.
18
+ # * Single-argument transcendental functions (`sqrt`, `cbrt`, `exp`, `log2`, `log10`, `log1p`,
19
+ # `expm1`, `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `sinh`, `cosh`, `tanh`, `asinh`, `acosh`,
20
+ # `atanh`, `erf`, `erfc`, `gamma`) return `Constant[Float]`.
25
21
  #
26
- # * Two-argument functions (`atan2`, `hypot`, `ldexp`) — return
27
- # `Constant[Float]`.
22
+ # * Two-argument functions (`atan2`, `hypot`, `ldexp`) — return `Constant[Float]`.
28
23
  #
29
- # * `log(x)` / `log(x, base)` — variadic; folds the 1- and
30
- # 2-argument forms to `Constant[Float]`.
24
+ # * `log(x)` / `log(x, base)` — variadic; folds the 1- and 2-argument forms to `Constant[Float]`.
31
25
  #
32
- # * `frexp(x)` / `lgamma(x)` — return a two-element array, lifted
33
- # to `Tuple[Constant[Float], Constant[Integer]]`.
26
+ # * `frexp(x)` / `lgamma(x)` — return a two-element array, lifted to
27
+ # `Tuple[Constant[Float], Constant[Integer]]`.
34
28
  #
35
29
  # === Non-constant / unsupported cases
36
30
  #
37
- # Any call where the receiver is not `Singleton[Math]`, an
38
- # argument is not a numeric `Constant`, the method is not in the
39
- # supported set, or the Ruby call raises `Math::DomainError` /
40
- # `RangeError` (domain-error inputs like `Math.sqrt(-1)`) returns
41
- # `nil`, deferring to the next dispatcher tier.
31
+ # Any call where the receiver is not `Singleton[Math]`, an argument is not a numeric `Constant`, the
32
+ # method is not in the supported set, or the Ruby call raises `Math::DomainError` / `RangeError`
33
+ # (domain-error inputs like `Math.sqrt(-1)`) returns `nil`, deferring to the next dispatcher tier.
42
34
  #
43
- # An infinite or NaN result (`Math.log(0.0)` → `-Infinity`) is
44
- # still folded `Constant[Float]` carries those values, matching
45
- # `ConstantFolding`'s treatment of `Float / 0`.
35
+ # An infinite or NaN result (`Math.log(0.0)` → `-Infinity`) is still folded — `Constant[Float]`
36
+ # carries those values, matching `ConstantFolding`'s treatment of `Float / 0`.
46
37
  module MathFolding
47
38
  MATH_UNARY = Set[
48
39
  :sqrt, :cbrt, :exp, :log2, :log10, :log1p, :expm1,
@@ -64,8 +55,7 @@ module Rigor
64
55
  args = context.args
65
56
  return nil unless SingletonFolding.receiver?(receiver, "Math")
66
57
 
67
- # `log` is variadic (1 or 2 args), so it cannot live in the
68
- # fixed-arity sets above.
58
+ # `log` is variadic (1 or 2 args), so it cannot live in the fixed-arity sets above.
69
59
  return fold_log(args) if method_name == :log
70
60
  return fold_unary(method_name, args) if MATH_UNARY.include?(method_name)
71
61
  return fold_binary(method_name, args) if MATH_BINARY.include?(method_name)
@@ -74,8 +64,8 @@ module Rigor
74
64
  nil
75
65
  end
76
66
 
77
- # Unwraps a numeric `Constant` argument to its Ruby value.
78
- # Returns nil for any non-`Constant` or non-`Numeric` carrier.
67
+ # Unwraps a numeric `Constant` argument to its Ruby value. Returns nil for any non-`Constant` or
68
+ # non-`Numeric` carrier.
79
69
  def numeric_constant(arg)
80
70
  return nil unless arg.is_a?(Type::Constant)
81
71
 
@@ -106,8 +96,7 @@ module Rigor
106
96
  nil
107
97
  end
108
98
 
109
- # `Math.log(x)` and `Math.log(x, base)` — the only variadic
110
- # `Math` function.
99
+ # `Math.log(x)` and `Math.log(x, base)` — the only variadic `Math` function.
111
100
  def fold_log(args)
112
101
  return nil unless [1, 2].include?(args.size)
113
102
 
@@ -119,8 +108,8 @@ module Rigor
119
108
  nil
120
109
  end
121
110
 
122
- # `Math.frexp` / `Math.lgamma` return a two-element array;
123
- # lift it to `Tuple[Constant[Float], Constant[Integer]]`.
111
+ # `Math.frexp` / `Math.lgamma` return a two-element array; lift it to
112
+ # `Tuple[Constant[Float], Constant[Integer]]`.
124
113
  def fold_tuple_unary(method_name, args)
125
114
  return nil unless args.size == 1
126
115
 
@@ -5,25 +5,20 @@ require_relative "../../type"
5
5
  module Rigor
6
6
  module Inference
7
7
  module MethodDispatcher
8
- # The member-shape projections shared by {DataFolding} and
9
- # {StructFolding}. A `DataInstance` and a `StructInstance` expose the
10
- # same surface an ordered `members` map, `member_names`, and a
11
- # `class_name` so the value projections off that surface
12
- # (`[]` / `to_h` / `deconstruct` / `deconstruct_keys` / `members` /
13
- # `with`) and the reader-redefinition guard are identical between the
14
- # two folders. Only `#with`'s carrier constructor differs
15
- # (`data_instance_of` vs `struct_instance_of`), so it takes a block
16
- # that builds the new instance from the merged member map.
8
+ # The member-shape projections shared by {DataFolding} and {StructFolding}. A `DataInstance` and a
9
+ # `StructInstance` expose the same surface — an ordered `members` map, `member_names`, and a
10
+ # `class_name`so the value projections off that surface (`[]` / `to_h` / `deconstruct` /
11
+ # `deconstruct_keys` / `members` / `with`) and the reader-redefinition guard are identical between the
12
+ # two folders. Only `#with`'s carrier constructor differs (`data_instance_of` vs
13
+ # `struct_instance_of`), so it takes a block that builds the new instance from the merged member map.
17
14
  #
18
- # Both folders `extend` this module so the projections resolve as
19
- # their own module functions (matching their `module_function` style).
15
+ # Both folders `extend` this module so the projections resolve as their own module functions
16
+ # (matching their `module_function` style).
20
17
  module MemberShapeProjection
21
- # A Data/Struct subclass body can redefine a member's synthesised
22
- # reader (`def x`); when it does, `inst.x` runs that `def`, not the
23
- # member, so folding the read would be unsound. A real `def` node
24
- # under the class name is the discriminator (the synthesised reader
25
- # has none), so an entry in the project def-node table gates the
26
- # bare member read off.
18
+ # A Data/Struct subclass body can redefine a member's synthesised reader (`def x`); when it does,
19
+ # `inst.x` runs that `def`, not the member, so folding the read would be unsound. A real `def` node
20
+ # under the class name is the discriminator (the synthesised reader has none), so an entry in the
21
+ # project def-node table gates the bare member read off.
27
22
  def reader_overridden?(instance, method_name, scope)
28
23
  class_name = instance.class_name
29
24
  return false if class_name.nil? || scope.nil?
@@ -56,9 +51,8 @@ module Rigor
56
51
  Type::Combinator.tuple_of(*instance.members.values)
57
52
  end
58
53
 
59
- # `deconstruct_keys(nil)` / `deconstruct_keys([:x])` both yield a
60
- # subset of the member map; the conservative, always-correct answer
61
- # is the full closed member shape.
54
+ # `deconstruct_keys(nil)` / `deconstruct_keys([:x])` both yield a subset of the member map; the
55
+ # conservative, always-correct answer is the full closed member shape.
62
56
  def instance_deconstruct_keys(instance, args)
63
57
  return nil unless args.size <= 1
64
58
 
@@ -69,12 +63,10 @@ module Rigor
69
63
  Type::Combinator.tuple_of(*instance.member_names.map { |name| Type::Combinator.constant_of(name) })
70
64
  end
71
65
 
72
- # `#with(x: 9)` returns a new copy with the named members
73
- # overridden. Only a closed keyword `HashShape` whose keys are a
74
- # subset of the members folds; anything else defers (RBS resolves
75
- # `with` to `self`, returning the unchanged instance type). The
76
- # carrier constructor differs per folder, so the caller supplies it
77
- # as a block taking the merged member map and the class name.
66
+ # `#with(x: 9)` returns a new copy with the named members overridden. Only a closed keyword
67
+ # `HashShape` whose keys are a subset of the members folds; anything else defers (RBS resolves
68
+ # `with` to `self`, returning the unchanged instance type). The carrier constructor differs per
69
+ # folder, so the caller supplies it as a block taking the merged member map and the class name.
78
70
  def instance_with(instance, args)
79
71
  return instance if args.empty?
80
72
  return nil unless args.size == 1
@@ -7,49 +7,32 @@ module Rigor
7
7
  module MethodDispatcher
8
8
  # `Method` (and friends) precision tier.
9
9
  #
10
- # Two folds make a `Method` carrier round-trip with its
11
- # binding visible:
10
+ # Two folds make a `Method` carrier round-trip with its binding visible:
12
11
  #
13
- # 1. **Forward** — `<receiver>.method(:sym)` (or
14
- # `.method("sym")`) lifts to {Type::BoundMethod}
15
- # carrying the receiver type AND the resolved Symbol.
16
- # Calling with a non-literal symbol-shaped argument
17
- # declines so the RBS tier still answers
18
- # `Nominal[Method]`.
19
- # 2. **Backward** `Type::BoundMethod#call(...)` /
20
- # `#()` (Prism lowers `.()` into a CallNode whose
21
- # `name` is `:call`) / `#[](...)` substitutes the
22
- # bound `(receiver_type, method_name)` and recurses
23
- # back into `MethodDispatcher.dispatch`. The
24
- # re-entrant call lets the substituted dispatch
25
- # consume every tier the original call site would
26
- # have — constant folding, shape dispatch, RBS,
27
- # plugin contributions, etc. The original block_type
28
- # / environment / call_node / scope are threaded
29
- # through unchanged so capture-sensitive tiers (the
30
- # block fold) keep working.
12
+ # 1. **Forward** — `<receiver>.method(:sym)` (or `.method("sym")`) lifts to {Type::BoundMethod}
13
+ # carrying the receiver type AND the resolved Symbol. Calling with a non-literal symbol-shaped
14
+ # argument declines so the RBS tier still answers `Nominal[Method]`.
15
+ # 2. **Backward** — `Type::BoundMethod#call(...)` / `#()` (Prism lowers `.()` into a CallNode whose
16
+ # `name` is `:call`) / `#[](...)` substitutes the bound `(receiver_type, method_name)` and
17
+ # recurses back into `MethodDispatcher.dispatch`. The re-entrant call lets the substituted
18
+ # dispatch consume every tier the original call site would have — constant folding, shape
19
+ # dispatch, RBS, plugin contributions, etc. The original block_type / environment / call_node /
20
+ # scope are threaded through unchanged so capture-sensitive tiers (the block fold) keep working.
31
21
  #
32
- # Lives ABOVE the standard precision-tier chain so the
33
- # RBS tier never sees a `BoundMethod` receiver `Method`
34
- # erasure means RBS would otherwise return
35
- # `Method#call: (*untyped) -> untyped`, which is exactly
36
- # the precision loss the carrier exists to avoid.
22
+ # Lives ABOVE the standard precision-tier chain so the RBS tier never sees a `BoundMethod` receiver —
23
+ # `Method` erasure means RBS would otherwise return `Method#call: (*untyped) -> untyped`, which is
24
+ # exactly the precision loss the carrier exists to avoid.
37
25
  module MethodFolding
38
26
  module_function
39
27
 
40
- # Forward fold. Returns a {Type::BoundMethod} when the
41
- # call shape is `<receiver>.method(:name)` /
42
- # `.method("name")` with a precisely-known Symbol /
43
- # String argument. Declines on every other shape so
44
- # the RBS tier still answers `Method` for non-folding
45
- # cases.
28
+ # Forward fold. Returns a {Type::BoundMethod} when the call shape is `<receiver>.method(:name)` /
29
+ # `.method("name")` with a precisely-known Symbol / String argument. Declines on every other shape
30
+ # so the RBS tier still answers `Method` for non-folding cases.
46
31
  #
47
32
  # @param receiver [Rigor::Type] caller's receiver
48
- # @param method_name [Symbol] the method being
49
- # dispatched on `receiver` — only `:method` triggers
33
+ # @param method_name [Symbol] the method being dispatched on `receiver` — only `:method` triggers
50
34
  # the fold.
51
- # @param args [Array<Rigor::Type>] caller's argument
52
- # types in order. Only the single-argument case
35
+ # @param args [Array<Rigor::Type>] caller's argument types in order. Only the single-argument case
53
36
  # matches; other arities decline.
54
37
  def try_dispatch(context)
55
38
  receiver = context.receiver
@@ -64,35 +47,24 @@ module Rigor
64
47
  Type::Combinator.bound_method_of(receiver, bound_name)
65
48
  end
66
49
 
67
- # Backward fold. Recurses into `MethodDispatcher.dispatch`
68
- # with the bound `(receiver_type, method_name)`. The
69
- # `block_type` / `environment` / `call_node` / `scope`
70
- # are forwarded so every downstream tier (constant
71
- # folding, shape dispatch, plugin contributions, …)
72
- # keeps the original call site's context. Returns
73
- # `Dynamic[top]` rather than `nil` when the recursive
74
- # dispatch declines so the call site still ends in a
75
- # well-defined type (the gradual-safety net mirrors
76
- # the engine's "BoundMethod erases to `Method`,
77
- # `Method#call: (*untyped) -> untyped`" RBS fallback).
50
+ # Backward fold. Recurses into `MethodDispatcher.dispatch` with the bound `(receiver_type,
51
+ # method_name)`. The `block_type` / `environment` / `call_node` / `scope` are forwarded so every
52
+ # downstream tier (constant folding, shape dispatch, plugin contributions, …) keeps the original
53
+ # call site's context. Returns `Dynamic[top]` rather than `nil` when the recursive dispatch declines
54
+ # so the call site still ends in a well-defined type (the gradual-safety net mirrors the engine's
55
+ # "BoundMethod erases to `Method`, `Method#call: (*untyped) -> untyped`" RBS fallback).
78
56
  def try_backward(context)
79
57
  receiver = context.receiver
80
58
  method_name = context.method_name
81
59
  return nil unless receiver.is_a?(Type::BoundMethod)
82
60
  return nil unless backward_method?(method_name)
83
61
 
84
- # `Method#curry` is treated as identity on the carrier
85
- # `<bound>.curry` keeps the same
86
- # `(receiver_type, method_name)` so a subsequent
87
- # `<curried>.call` still routes through the recursive
88
- # dispatch below. This is correct for the dominant
89
- # no-arg form (`.curry.call`); partially-applied
90
- # forms (`.curry(n).call(a)`) lose precision and fall
91
- # through to RBS via the trailing
92
- # `Type::Combinator.untyped`. A faithful
93
- # `Type::CurriedBoundMethod(receiver_type,
94
- # method_name, accumulated_args)` carrier is reserved
95
- # for a future slice when concrete user demand
62
+ # `Method#curry` is treated as identity on the carrier — `<bound>.curry` keeps the same
63
+ # `(receiver_type, method_name)` so a subsequent `<curried>.call` still routes through the
64
+ # recursive dispatch below. This is correct for the dominant no-arg form (`.curry.call`);
65
+ # partially-applied forms (`.curry(n).call(a)`) lose precision and fall through to RBS via the
66
+ # trailing `Type::Combinator.untyped`. A faithful `Type::CurriedBoundMethod(receiver_type,
67
+ # method_name, accumulated_args)` carrier is reserved for a future slice when concrete user demand
96
68
  # surfaces.
97
69
  return receiver if method_name == :curry
98
70
 
@@ -106,14 +78,10 @@ module Rigor
106
78
  scope: context.scope
107
79
  ) || Type::Combinator.untyped
108
80
  end
109
- # `Method#call` / `Method#()` and `Method#[]` are the
110
- # invocation entry points on the `Method` API; the
111
- # alias `===` is also `call` semantically but is more
112
- # commonly used as a case-equality predicate, so we
113
- # do NOT fold through it (the case/when narrowing path
114
- # already special-cases `===` for branch typing).
115
- # `Method#curry` rides through as identity (see the
116
- # comment in `try_backward`).
81
+ # `Method#call` / `Method#()` and `Method#[]` are the invocation entry points on the `Method` API;
82
+ # the alias `===` is also `call` semantically but is more commonly used as a case-equality
83
+ # predicate, so we do NOT fold through it (the case/when narrowing path already special-cases `===`
84
+ # for branch typing). `Method#curry` rides through as identity (see the comment in `try_backward`).
117
85
  BACKWARD_METHOD_NAMES = %i[call [] curry].freeze
118
86
  private_constant :BACKWARD_METHOD_NAMES
119
87
 
@@ -121,11 +89,9 @@ module Rigor
121
89
  BACKWARD_METHOD_NAMES.include?(method_name)
122
90
  end
123
91
 
124
- # `Object#method` accepts both Symbol and String at
125
- # runtime (the latter coerced via `to_sym`). The
126
- # `Constant<String>` form is rare in production code
127
- # but cheap to support and matches Ruby's documented
128
- # contract.
92
+ # `Object#method` accepts both Symbol and String at runtime (the latter coerced via `to_sym`). The
93
+ # `Constant<String>` form is rare in production code but cheap to support and matches Ruby's
94
+ # documented contract.
129
95
  def symbol_name_of(arg)
130
96
  return nil unless arg.is_a?(Type::Constant)
131
97