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,21 +5,17 @@ module Rigor
5
5
  FALLBACK_FAMILIES = %i[prism virtual].freeze
6
6
  private_constant :FALLBACK_FAMILIES
7
7
 
8
- # Immutable value object recorded by the typer whenever Scope#type_of
9
- # falls back to Dynamic[Top] for a node it does not yet recognise. The
10
- # contract for emitting these events lives in
8
+ # Immutable value object recorded by the typer whenever Scope#type_of falls back to Dynamic[Top] for a
9
+ # node it does not yet recognise. The contract for emitting these events lives in
11
10
  # docs/internal-spec/inference-engine.md (Fail-Soft Policy).
12
11
  #
13
12
  # Fields:
14
- # - node_class: the Ruby class of the node that triggered the
15
- # fallback (e.g. Prism::CallNode, or a Rigor::AST::Node subclass).
16
- # - location: the Prism source location for real Prism nodes, or
17
- # nil for synthetic nodes.
18
- # - family: :prism for real Prism nodes, :virtual for nodes
19
- # that include Rigor::AST::Node.
20
- # - inner_type: the Rigor::Type returned to the caller (currently
21
- # always Dynamic[Top]; later slices may carry richer fallback
22
- # types).
13
+ # - node_class: the Ruby class of the node that triggered the fallback (e.g. Prism::CallNode, or a
14
+ # Rigor::AST::Node subclass).
15
+ # - location: the Prism source location for real Prism nodes, or nil for synthetic nodes.
16
+ # - family: :prism for real Prism nodes, :virtual for nodes that include Rigor::AST::Node.
17
+ # - inner_type: the Rigor::Type returned to the caller (currently always Dynamic[Top]; later slices may
18
+ # carry richer fallback types).
23
19
  class Fallback < Data.define(:node_class, :location, :family, :inner_type, :origin)
24
20
  def initialize(node_class:, location:, family:, inner_type:, origin: nil)
25
21
  raise ArgumentError, "node_class must be a Class, got #{node_class.class}" unless node_class.is_a?(Class)
@@ -4,16 +4,10 @@ require_relative "fallback"
4
4
 
5
5
  module Rigor
6
6
  module Inference
7
- # Mutable observer that accumulates Rigor::Inference::Fallback events
8
- # emitted by the type-inference engine. Pass an instance to
9
- # Rigor::Scope#type_of(node, tracer: ...) to record every fail-soft
10
- # fallback. The tracer MUST NOT change the return value of type_of;
11
- # see docs/internal-spec/inference-engine.md (Fail-Soft Policy).
12
- #
13
- # Future slices may add additional record_* methods (e.g.
14
- # record_dispatch_miss for Slice 3, record_budget_cutoff for Slice 5);
15
- # the namespaced method names exist so a single tracer can collect
16
- # multiple event families without confusing them.
7
+ # Mutable observer that accumulates Rigor::Inference::Fallback events emitted by the type-inference
8
+ # engine. Pass an instance to Rigor::Scope#type_of(node, tracer: ...) to record every fail-soft fallback.
9
+ # The tracer MUST NOT change the return value of type_of; see docs/internal-spec/inference-engine.md
10
+ # (Fail-Soft Policy).
17
11
  class FallbackTracer
18
12
  def initialize
19
13
  @events = []
@@ -2,21 +2,16 @@
2
2
 
3
3
  module Rigor
4
4
  module Inference
5
- # Thread-local event recorder behind `rigor trace`: while a block runs
6
- # under {record}, the inference engine emits a flat, ordered event
7
- # stream describing HOW it typed the program expression enter/result
8
- # pairs, scope binds, union formation, and method-dispatch outcomes.
9
- # The CLI replays that stream as a terminal animation (or dumps it as
10
- # JSON); the engine itself never reads the events back, so recording
11
- # is purely observational and MUST NOT change any inferred type.
5
+ # Thread-local event recorder behind `rigor trace`: while a block runs under {record}, the inference engine
6
+ # emits a flat, ordered event stream describing HOW it typed the program expression enter/result pairs, scope
7
+ # binds, union formation, and method-dispatch outcomes. The CLI replays that stream as a terminal animation (or
8
+ # dumps it as JSON); the engine itself never reads the events back, so recording is purely observational and
9
+ # MUST NOT change any inferred type.
12
10
  #
13
- # Modelled on {Analysis::DependencyRecorder}: thread-local state, a
14
- # module-level activation count so the disabled fast path ({active?})
15
- # is a plain integer read, and a frozen snapshot for consumers. The
16
- # instrumented hot paths (`ExpressionTyper#type_of`,
17
- # `Scope#with_local`, `Type::Combinator.union`,
18
- # `MethodDispatcher.dispatch`) each guard their emit behind {active?},
19
- # so a normal (non-tracing) run pays one integer comparison.
11
+ # Modelled on {Analysis::DependencyRecorder}: thread-local state, a module-level activation count so the
12
+ # disabled fast path ({active?}) is a plain integer read, and a frozen snapshot for consumers. The instrumented
13
+ # hot paths (`ExpressionTyper#type_of`, `Scope#with_local`, `Type::Combinator.union`, `MethodDispatcher.dispatch`)
14
+ # each guard their emit behind {active?}, so a normal (non-tracing) run pays one integer comparison.
20
15
  module FlowTracer
21
16
  KEY = :__rigor_flow_tracer__
22
17
  private_constant :KEY
@@ -25,18 +20,16 @@ module Rigor
25
20
  #
26
21
  # kind :enter | :result | :bind | :union | :dispatch
27
22
  # depth expression-recursion depth at emit time (0 = statement level)
28
- # location frozen Hash with :start_line/:start_column/:end_line/
29
- # :end_column/:start_offset/:end_offset, or nil. Events
30
- # without a node of their own (:bind, :union) inherit the
31
- # innermost in-flight expression node's location so the
32
- # replayer can still highlight the source being evaluated.
23
+ # location frozen Hash with :start_line/:start_column/:end_line/:end_column/:start_offset/:end_offset, or nil.
24
+ # Events without a node of their own (:bind, :union) inherit the innermost in-flight expression
25
+ # node's location so the replayer can still highlight the source being evaluated.
33
26
  # stack frozen Array of short node-class names, outermost first
34
- # data frozen kind-specific Hash (types pre-rendered as Strings
35
- # via `describe(:short)` so events serialise to JSON as-is)
27
+ # data frozen kind-specific Hash (types pre-rendered as Strings via `describe(:short)` so events
28
+ # serialise to JSON as-is)
36
29
  Event = Data.define(:kind, :depth, :location, :stack, :data)
37
30
 
38
- # Mutable per-thread accumulator; only ever touched by the thread
39
- # that activated it, so no locking is needed on the emit path.
31
+ # Mutable per-thread accumulator; only ever touched by the thread that activated it, so no locking is needed
32
+ # on the emit path.
40
33
  class Recorder
41
34
  attr_reader :events
42
35
 
@@ -45,9 +38,8 @@ module Rigor
45
38
  @stack = []
46
39
  end
47
40
 
48
- # Brackets one `ExpressionTyper#type_of` recursion: emits :enter,
49
- # runs the real inference, emits :result with the inferred type,
50
- # and returns the type unchanged.
41
+ # Brackets one `ExpressionTyper#type_of` recursion: emits :enter, runs the real inference, emits :result
42
+ # with the inferred type, and returns the type unchanged.
51
43
  def node(node)
52
44
  location = location_of(node)
53
45
  name = short_name(node.class)
@@ -100,9 +92,8 @@ module Rigor
100
92
 
101
93
  module_function
102
94
 
103
- # Activates recording on the current thread for the duration of the
104
- # block and returns the frozen event list. Nests safely; restores
105
- # the previous recorder on exit.
95
+ # Activates recording on the current thread for the duration of the block and returns the frozen event list.
96
+ # Nests safely; restores the previous recorder on exit.
106
97
  def record
107
98
  previous = Thread.current[KEY]
108
99
  recorder = Recorder.new
@@ -120,9 +111,8 @@ module Rigor
120
111
  @active_count.positive?
121
112
  end
122
113
 
123
- # Brackets one expression-typing recursion. Falls through to the
124
- # bare block when the current thread is not recording (another
125
- # thread may have flipped {active?}).
114
+ # Brackets one expression-typing recursion. Falls through to the bare block when the current thread is not
115
+ # recording (another thread may have flipped {active?}).
126
116
  def trace_node(node, &)
127
117
  recorder = Thread.current[KEY]
128
118
  return yield unless recorder
@@ -135,8 +125,7 @@ module Rigor
135
125
  Thread.current[KEY]&.emit(:bind, data: { name: name.to_s, type: describe(type) })
136
126
  end
137
127
 
138
- # `Type::Combinator.union` — the moment branch types merge
139
- # (including degenerate collapses like `1 | 1 → 1`).
128
+ # `Type::Combinator.union` — the moment branch types merge (including degenerate collapses like `1 | 1 → 1`).
140
129
  def union(members, result)
141
130
  Thread.current[KEY]&.emit(
142
131
  :union,
@@ -144,8 +133,8 @@ module Rigor
144
133
  )
145
134
  end
146
135
 
147
- # `MethodDispatcher.dispatch` — resolution or the fail-soft `nil`
148
- # ("no rule matched"; the caller will widen to `Dynamic[Top]`).
136
+ # `MethodDispatcher.dispatch` — resolution or the fail-soft `nil` ("no rule matched"; the caller will widen
137
+ # to `Dynamic[Top]`).
149
138
  def dispatch(receiver:, method_name:, args:, result:, location: nil)
150
139
  recorder = Thread.current[KEY]
151
140
  return unless recorder
@@ -2,45 +2,35 @@
2
2
 
3
3
  module Rigor
4
4
  module Inference
5
- # ADR-20 Slice 2a — node types for the parsed body of a
6
- # type-function `Definition`. Each node represents one
7
- # piece of a Rigor-side type expression that the reducer
8
- # ({HktReducer}) walks against a concrete argument list.
5
+ # ADR-20 Slice 2a — node types for the parsed body of a type-function `Definition`. Each node
6
+ # represents one piece of a Rigor-side type expression that the reducer ({HktReducer}) walks
7
+ # against a concrete argument list.
9
8
  #
10
- # Slice 2a ships a programmatic constructor surface; plugin
11
- # and Rigor-bundled overlay authors may build a body tree
12
- # by hand using these node types. The string-grammar parser
13
- # (`HktBodyParser`, Slice 2b, shipped) reads `Definition#body`
14
- # (populated by Slice 1's `HktDirectives.parse_define`) into
15
- # this node tree; `body_tree` is the evaluable form.
9
+ # Slice 2a ships a programmatic constructor surface; plugin and Rigor-bundled overlay authors
10
+ # may build a body tree by hand using these node types. The string-grammar parser
11
+ # (`HktBodyParser`, Slice 2b, shipped) reads `Definition#body` (populated by Slice 1's
12
+ # `HktDirectives.parse_define`) into this node tree; `body_tree` is the evaluable form.
16
13
  #
17
- # The nine node types cover JSON.parse, dry-monads, and the
18
- # ADR-20 § D3 conditional / membership forms (shipped):
14
+ # The nine node types cover JSON.parse, dry-monads, and the ADR-20 § D3 conditional /
15
+ # membership forms (shipped):
19
16
  #
20
- # - {TypeLeaf} — wraps a fully-built `Rigor::Type`
21
- # (use for atoms like `nil`, `Constant<true>`,
22
- # `Nominal[Integer]`).
23
- # - {Param} — reference to a formal parameter
24
- # declared in the enclosing `Definition#params` list
25
- # (e.g. `K` in `json::value[K]`). The reducer
26
- # substitutes from the application's `args`.
27
- # - {AppRef} — abstract HKT application; the reducer
28
- # resolves it via the registry, or returns the `App`
29
- # carrier as-is when the reference is self-recursive
30
- # (lazy "tying-the-knot" handling that lets recursive
31
- # sums like `json::value` reduce without infinite
32
- # expansion).
17
+ # - {TypeLeaf} — wraps a fully-built `Rigor::Type` (use for atoms like `nil`,
18
+ # `Constant<true>`, `Nominal[Integer]`).
19
+ # - {Param} — reference to a formal parameter declared in the enclosing
20
+ # `Definition#params` list (e.g. `K` in `json::value[K]`). The reducer substitutes from the
21
+ # application's `args`.
22
+ # - {AppRef} — abstract HKT application; the reducer resolves it via the registry, or
23
+ # returns the `App` carrier as-is when the reference is self-recursive (lazy
24
+ # "tying-the-knot" handling that lets recursive sums like `json::value` reduce without
25
+ # infinite expansion).
33
26
  # - {Union} — N-ary union of arms.
34
- # - {NominalApp} — parameterised nominal class
35
- # (`Array[X]`, `Hash[K, V]`) whose type args are
27
+ # - {NominalApp} — parameterised nominal class (`Array[X]`, `Hash[K, V]`) whose type args are
36
28
  # themselves body nodes.
37
29
  #
38
- # Every node is a frozen `Data.define` value; structural
39
- # equality is by-field.
30
+ # Every node is a frozen `Data.define` value; structural equality is by-field.
40
31
  module HktBody
41
- # Wraps a pre-built `Rigor::Type` value. Use for atoms
42
- # that need no substitution (e.g. `Nominal[Integer]`,
43
- # `Constant<nil>`).
32
+ # Wraps a pre-built `Rigor::Type` value. Use for atoms that need no substitution
33
+ # (e.g. `Nominal[Integer]`, `Constant<nil>`).
44
34
  TypeLeaf = Data.define(:type) do
45
35
  def initialize(type:)
46
36
  raise ArgumentError, "type must not be nil" if type.nil?
@@ -49,12 +39,10 @@ module Rigor
49
39
  end
50
40
  end
51
41
 
52
- # Reference to a formal parameter the enclosing
53
- # `Definition#params` declared. The reducer substitutes
54
- # this node with the matching positional arg from the
55
- # `App` being reduced; an unknown name raises during
56
- # reduction (the parser, when it ships, MUST reject
57
- # unknown names earlier).
42
+ # Reference to a formal parameter the enclosing `Definition#params` declared. The reducer
43
+ # substitutes this node with the matching positional arg from the `App` being reduced; an
44
+ # unknown name raises during reduction (the parser, when it ships, MUST reject unknown names
45
+ # earlier).
58
46
  Param = Data.define(:name) do
59
47
  def initialize(name:)
60
48
  raise ArgumentError, "name must be a Symbol, got #{name.class}" unless name.is_a?(Symbol)
@@ -63,11 +51,9 @@ module Rigor
63
51
  end
64
52
  end
65
53
 
66
- # Abstract HKT application — the reducer's primary
67
- # recursion point. `uri` is a namespaced Symbol
68
- # matching some `Registration` in the registry; `args`
69
- # is an Array of body nodes (each gets substituted /
70
- # resolved before being used).
54
+ # Abstract HKT application — the reducer's primary recursion point. `uri` is a namespaced
55
+ # Symbol matching some `Registration` in the registry; `args` is an Array of body nodes
56
+ # (each gets substituted / resolved before being used).
71
57
  AppRef = Data.define(:uri, :args) do
72
58
  def initialize(uri:, args:)
73
59
  raise ArgumentError, "uri must be a Symbol, got #{uri.class}" unless uri.is_a?(Symbol)
@@ -79,9 +65,8 @@ module Rigor
79
65
  end
80
66
  end
81
67
 
82
- # N-ary union. The reducer builds the result through
83
- # `Type::Combinator.union(*reduced_arms)` so
84
- # normalization (flattening, dedup, Bot drop) applies.
68
+ # N-ary union. The reducer builds the result through `Type::Combinator.union(*reduced_arms)`
69
+ # so normalization (flattening, dedup, Bot drop) applies.
85
70
  Union = Data.define(:arms) do
86
71
  def initialize(arms:)
87
72
  raise ArgumentError, "arms must be an Array, got #{arms.class}" unless arms.is_a?(Array)
@@ -91,12 +76,9 @@ module Rigor
91
76
  end
92
77
  end
93
78
 
94
- # Parameterised nominal class. `class_name` is the
95
- # Ruby class name (`"Array"`, `"Hash"`); `args` is an
96
- # Array of body nodes for the type arguments. The
97
- # reducer builds the result through
98
- # `Type::Combinator.nominal_of(class_name, type_args:
99
- # reduced_args)`.
79
+ # Parameterised nominal class. `class_name` is the Ruby class name (`"Array"`, `"Hash"`);
80
+ # `args` is an Array of body nodes for the type arguments. The reducer builds the result
81
+ # through `Type::Combinator.nominal_of(class_name, type_args: reduced_args)`.
100
82
  NominalApp = Data.define(:class_name, :args) do
101
83
  def initialize(class_name:, args:)
102
84
  unless class_name.is_a?(String) && !class_name.empty?
@@ -109,17 +91,14 @@ module Rigor
109
91
  end
110
92
  end
111
93
 
112
- # ADR-20 § D3 — conditional type form. `test` is a
113
- # {TestSubtype} / {TestEquality} / {TestMembership}
114
- # value object the reducer evaluates against the
115
- # current bindings; `then_branch` / `else_branch` are
116
- # body nodes. The reducer's trinary handling:
94
+ # ADR-20 § D3 — conditional type form. `test` is a {TestSubtype} / {TestEquality} /
95
+ # {TestMembership} value object the reducer evaluates against the current bindings;
96
+ # `then_branch` / `else_branch` are body nodes. The reducer's trinary handling:
117
97
  #
118
98
  # - test = `yes` → return the reduced `then_branch`.
119
99
  # - test = `no` → return the reduced `else_branch`.
120
- # - test = `maybe` → widen to the union of both
121
- # reduced branches (per ADR-20 WD7 / robustness
122
- # principle).
100
+ # - test = `maybe` → widen to the union of both reduced branches (per ADR-20 WD7 /
101
+ # robustness principle).
123
102
  Conditional = Data.define(:test, :then_branch, :else_branch) do
124
103
  def initialize(test:, then_branch:, else_branch:)
125
104
  raise ArgumentError, "test must not be nil" if test.nil?
@@ -130,8 +109,8 @@ module Rigor
130
109
  end
131
110
  end
132
111
 
133
- # `left <: right` — subtype check. `left` is typically
134
- # a {Param} reference; `right` is any body expression.
112
+ # `left <: right` — subtype check. `left` is typically a {Param} reference; `right` is any
113
+ # body expression.
135
114
  TestSubtype = Data.define(:left, :right) do
136
115
  def initialize(left:, right:)
137
116
  raise ArgumentError, "left/right must not be nil" if left.nil? || right.nil?
@@ -140,9 +119,8 @@ module Rigor
140
119
  end
141
120
  end
142
121
 
143
- # `left == right` — structural equality. Useful for
144
- # discriminating against literal constants
145
- # (`E == :symbol`).
122
+ # `left == right` — structural equality. Useful for discriminating against literal
123
+ # constants (`E == :symbol`).
146
124
  TestEquality = Data.define(:left, :right) do
147
125
  def initialize(left:, right:)
148
126
  raise ArgumentError, "left/right must not be nil" if left.nil? || right.nil?
@@ -151,9 +129,8 @@ module Rigor
151
129
  end
152
130
  end
153
131
 
154
- # `left in [opt1, opt2, ...]` — set membership. Each
155
- # `option` is a body node; the test passes iff `left`
156
- # is structurally equal to any of the options.
132
+ # `left in [opt1, opt2, ...]` — set membership. Each `option` is a body node; the test
133
+ # passes iff `left` is structurally equal to any of the options.
157
134
  TestMembership = Data.define(:left, :options) do
158
135
  def initialize(left:, options:)
159
136
  raise ArgumentError, "left must not be nil" if left.nil?
@@ -5,17 +5,13 @@ require_relative "../type"
5
5
 
6
6
  module Rigor
7
7
  module Inference
8
- # ADR-20 slice 2b — parses the body of an
9
- # `HktRegistry::Definition` (a `String`, as populated by
10
- # Slice 1's `HktDirectives.parse_define` from
11
- # `%a{rigor:v1:hkt_define}` payloads) into the `HktBody`
12
- # node tree the Slice 2a reducer evaluates against.
8
+ # ADR-20 slice 2b — parses the body of an `HktRegistry::Definition` (a `String`, as populated
9
+ # by Slice 1's `HktDirectives.parse_define` from `%a{rigor:v1:hkt_define}` payloads) into the
10
+ # `HktBody` node tree the Slice 2a reducer evaluates against.
13
11
  #
14
- # The grammar implements the full ADR-20 § D3 subset:
15
- # union-of-atoms/parameterised-forms for `JSON.parse`'s
16
- # `json::value` recursive sum, plus the conditional and
17
- # membership forms shipped in subsequent slices. Indexed-access
18
- # forms remain deferred (no concrete demand yet).
12
+ # The grammar implements the full ADR-20 § D3 subset: union-of-atoms/parameterised-forms for
13
+ # `JSON.parse`'s `json::value` recursive sum, plus the conditional and membership forms
14
+ # shipped in subsequent slices. Indexed-access forms remain deferred (no concrete demand yet).
19
15
  #
20
16
  # ## Grammar
21
17
  #
@@ -37,22 +33,17 @@ module Rigor
37
33
  #
38
34
  # ## Disambiguation
39
35
  #
40
- # The same syntactic UCNAME spells both a parameter
41
- # reference (`K` when `params = [:K]`) and a nominal class
42
- # name (`Integer`). The parser resolves by checking the
43
- # `params` set passed to {.parse}; an unknown UCNAME is
44
- # treated as a nominal class name. `App` is reserved at
45
- # the head position of an `App[...]` form; using `App` as
46
- # a class name is therefore not supported.
36
+ # The same syntactic UCNAME spells both a parameter reference (`K` when `params = [:K]`) and
37
+ # a nominal class name (`Integer`). The parser resolves by checking the `params` set passed
38
+ # to {.parse}; an unknown UCNAME is treated as a nominal class name. `App` is reserved at the
39
+ # head position of an `App[...]` form; using `App` as a class name is therefore not
40
+ # supported.
47
41
  #
48
- # Atoms are kept verbatim as `HktBody::TypeLeaf` nodes
49
- # wrapping the appropriate `Rigor::Type::*` carrier:
50
- # `nil` / `true` / `false` produce `Constant` carriers;
51
- # `bool` produces the `Constant<true> | Constant<false>`
52
- # union; `untyped` produces `Combinator.untyped`
53
- # (i.e. `Dynamic[Top]`). Nominal class names produce raw
54
- # `Type::Nominal` carriers (no `name_scope` resolution at
55
- # this slice — the reducer trusts the name verbatim).
42
+ # Atoms are kept verbatim as `HktBody::TypeLeaf` nodes wrapping the appropriate
43
+ # `Rigor::Type::*` carrier: `nil` / `true` / `false` produce `Constant` carriers; `bool`
44
+ # produces the `Constant<true> | Constant<false>` union; `untyped` produces
45
+ # `Combinator.untyped` (i.e. `Dynamic[Top]`). Nominal class names produce raw `Type::Nominal`
46
+ # carriers (no `name_scope` resolution at this slice — the reducer trusts the name verbatim).
56
47
  module HktBodyParser
57
48
  class ParseError < StandardError; end
58
49
 
@@ -159,14 +150,11 @@ module Rigor
159
150
  # conditional := "(" test "?" union ":" union ")"
160
151
  # test := type_expr ("<:" | "==") type_expr
161
152
  #
162
- # Parens delimit a conditional unambiguously — bare
163
- # `(type_expr)` grouping is not supported at this slice
164
- # (no use case yet). Branches can be unions; test sides
165
- # are single arms (wrap in `App[my_union, ...]` if you
166
- # need a union there). `in [opt1, opt2]` membership
167
- # tests are programmatically supported via
168
- # `HktBody::TestMembership` but the parser does not yet
169
- # recognise the `in` keyword (no concrete demand yet).
153
+ # Parens delimit a conditional unambiguously — bare `(type_expr)` grouping is not
154
+ # supported at this slice (no use case yet). Branches can be unions; test sides are
155
+ # single arms (wrap in `App[my_union, ...]` if you need a union there). `in [opt1, opt2]`
156
+ # membership tests are programmatically supported via `HktBody::TestMembership` but the
157
+ # parser does not yet recognise the `in` keyword (no concrete demand yet).
170
158
  def parse_conditional
171
159
  expect!(:lparen)
172
160
  test = parse_test
@@ -196,11 +184,9 @@ module Rigor
196
184
  end
197
185
  end
198
186
 
199
- # `left in [opt1, opt2, ...]` membership test.
200
- # Distinguished from a lowercase atom by the
201
- # subsequent `[` — the only place an identifier
202
- # `in` is permitted at this position is membership
203
- # syntax.
187
+ # `left in [opt1, opt2, ...]` membership test. Distinguished from a lowercase atom by the
188
+ # subsequent `[` the only place an identifier `in` is permitted at this position is
189
+ # membership syntax.
204
190
  def parse_in_membership(left, op_token:)
205
191
  unless op_token.value == "in"
206
192
  raise ParseError,
@@ -243,11 +229,9 @@ module Rigor
243
229
  parse_nominal_or_param_with_args
244
230
  end
245
231
 
246
- # Returns true when the current UCName is followed by
247
- # `::` (qualified class name continuation) or `[`
248
- # (parameterised application). In either case the
249
- # token is a nominal, not a param ref — Slice 2b's
250
- # `Param` nodes are always single bare identifiers.
232
+ # Returns true when the current UCName is followed by `::` (qualified class name
233
+ # continuation) or `[` (parameterised application). In either case the token is a
234
+ # nominal, not a param ref — Slice 2b's `Param` nodes are always single bare identifiers.
251
235
  def class_continuation?
252
236
  next_tok = @tokens[@pos + 1]
253
237
  next_tok && %i[sep lb].include?(next_tok.kind)
@@ -266,8 +250,8 @@ module Rigor
266
250
  end
267
251
 
268
252
  def parse_classname_with_leading_sep
269
- # The leading "::" form (`::Foo::Bar`). Consume the
270
- # separator so the rest threads through parse_class_name.
253
+ # The leading "::" form (`::Foo::Bar`). Consume the separator so the rest threads
254
+ # through parse_class_name.
271
255
  consume
272
256
  tok = peek
273
257
  raise ParseError, "expected class name after `::`" if tok.nil? || tok.kind != :ucname
@@ -307,13 +291,10 @@ module Rigor
307
291
  parts.join("::").to_sym
308
292
  end
309
293
 
310
- # Arg list for `Foo[A, B, C]` and `App[uri, A, B]`
311
- # forms. Each arg is parsed as a union so per-arg
312
- # `A | B` forms work (`Array[K | nil]`); the COMMA
313
- # at the top level still separates args, so
314
- # `Hash[K, V]` reads as two args (each a single-arm
315
- # union that collapses to the arm) rather than one
316
- # union of two.
294
+ # Arg list for `Foo[A, B, C]` and `App[uri, A, B]` forms. Each arg is parsed as a union so
295
+ # per-arg `A | B` forms work (`Array[K | nil]`); the COMMA at the top level still
296
+ # separates args, so `Hash[K, V]` reads as two args (each a single-arm union that
297
+ # collapses to the arm) rather than one union of two.
317
298
  def parse_arg_list
318
299
  args = [parse_union]
319
300
  while peek_kind == :comma