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,48 +5,37 @@ require_relative "../inference/rbs_type_translator"
5
5
 
6
6
  module Rigor
7
7
  module RbsExtended
8
- # Verifies every `rigor:v1:conforms-to <Interface>` class- /
9
- # module-level directive in the loaded RBS environment (spec:
10
- # `docs/type-specification/rbs-extended.md` § "Explicit
11
- # conformance directive"). For each annotated class, the
12
- # directive asserts the class satisfies the named structural
13
- # interface as a *checked design assertion* — independent of
14
- # whether any current call site exercises that requirement.
15
- # Multiple directives on one class combine as an intersection:
16
- # each interface is checked independently.
8
+ # Verifies every `rigor:v1:conforms-to <Interface>` class- / module-level directive in the loaded RBS
9
+ # environment (spec: `docs/type-specification/rbs-extended.md` § "Explicit conformance directive"). For each
10
+ # annotated class, the directive asserts the class satisfies the named structural interface as a *checked
11
+ # design assertion* independent of whether any current call site exercises that requirement. Multiple
12
+ # directives on one class combine as an intersection: each interface is checked independently.
17
13
  #
18
14
  # ## Two checked tiers
19
15
  #
20
- # 1. **Presence** (FP-free): an interface method the class provably does
21
- # NOT provide anywhere in its RBS-resolved method set (own, inherited,
22
- # included) is a definitive non-conformance.
23
- # 2. **Signature compatibility** (covariant return / contravariant
24
- # params): for a method the class DOES provide, the provided RBS
25
- # signature must be a behavioural subtype of the interface's required
26
- # one. Both sides are *authored* RBS (the class in `signature_paths:`
27
- # RBS, the interface in a loaded `sig`/library), so this is the same
28
- # FP-safe both-sides-authored construction as the
29
- # [ADR-35](../../../docs/adr/35-override-signature-compatibility.md)
30
- # `def.override-*` rules — not the inferred-signature comparison whose
31
- # FP risk justified deferring it. Conservative: single-method-type
32
- # (non-overloaded) signatures only, `Dynamic[Top]` positions skipped,
33
- # fires only on a proven `accepts(...).no?` violation.
16
+ # 1. **Presence** (FP-free): an interface method the class provably does NOT provide anywhere in its
17
+ # RBS-resolved method set (own, inherited, included) is a definitive non-conformance.
18
+ # 2. **Signature compatibility** (covariant return / contravariant params): for a method the class DOES
19
+ # provide, the provided RBS signature must be a behavioural subtype of the interface's required one. Both
20
+ # sides are *authored* RBS (the class in `signature_paths:` RBS, the interface in a loaded `sig`/library),
21
+ # so this is the same FP-safe both-sides-authored construction as the
22
+ # [ADR-35](../../../docs/adr/35-override-signature-compatibility.md) `def.override-*` rules not the
23
+ # inferred-signature comparison whose FP risk justified deferring it. Conservative: single-method-type
24
+ # (non-overloaded) signatures only, `Dynamic[Top]` positions skipped, fires only on a proven
25
+ # `accepts(...).no?` violation.
34
26
  #
35
27
  # ## Output records (all drained by {Rigor::Analysis::Runner})
36
28
  #
37
- # - `Unsatisfied` — the class is missing one or more required interface
38
- # methods. Surfaces as `rbs_extended.unsatisfied-conformance`.
39
- # - `IncompatibleSignature` — a provided method's signature violates the
40
- # interface contract (return widened, or a parameter narrowed). Same
41
- # rule, signature-specific message.
42
- # - `UnresolvedInterface` the named interface is not loaded (a typo, or
43
- # the defining library / `sig` set is not on the RBS load path).
44
- # Surfaces as `dynamic.rbs-extended.unresolved` `:info`, the fail-soft
45
- # channel the other directive parsers use, so a bad name never silently
46
- # disables the author's assertion.
29
+ # - `Unsatisfied` — the class is missing one or more required interface methods. Surfaces as
30
+ # `rbs_extended.unsatisfied-conformance`.
31
+ # - `IncompatibleSignature` — a provided method's signature violates the interface contract (return widened,
32
+ # or a parameter narrowed). Same rule, signature-specific message.
33
+ # - `UnresolvedInterface` — the named interface is not loaded (a typo, or the defining library / `sig` set is
34
+ # not on the RBS load path). Surfaces as `dynamic.rbs-extended.unresolved` `:info`, the fail-soft channel
35
+ # the other directive parsers use, so a bad name never silently disables the author's assertion.
47
36
  #
48
- # Fail-soft throughout: a class whose own definition cannot be built (RBS
49
- # error) is skipped rather than reported.
37
+ # Fail-soft throughout: a class whose own definition cannot be built (RBS error) is skipped rather than
38
+ # reported.
50
39
  module ConformanceChecker
51
40
  Unsatisfied = Data.define(:class_name, :interface_name, :missing_methods, :location)
52
41
  IncompatibleSignature = Data.define(:class_name, :interface_name, :method_name, :detail, :location)
@@ -113,14 +102,11 @@ module Rigor
113
102
  end
114
103
  end
115
104
 
116
- # Returns a human-readable mismatch detail when `provided` is NOT a
117
- # behavioural subtype of the `required` (interface) signature, else
118
- # nil. Mirrors the ADR-35 override checks: covariant return,
119
- # contravariant params, single method type only, `Dynamic[Top]`
120
- # positions skipped (fires only on a proven `accepts(...).no?`).
121
- # Also checks arity divergence and keyword-requiredness divergence
122
- # (positional-type comparison only was the initial scope; these
123
- # extend it to the cases that cause runtime ArgumentError).
105
+ # Returns a human-readable mismatch detail when `provided` is NOT a behavioural subtype of the `required`
106
+ # (interface) signature, else nil. Mirrors the ADR-35 override checks: covariant return, contravariant
107
+ # params, single method type only, `Dynamic[Top]` positions skipped (fires only on a proven
108
+ # `accepts(...).no?`). Also checks arity divergence and keyword-requiredness divergence (positional-type
109
+ # comparison only was the initial scope; these extend it to the cases that cause runtime ArgumentError).
124
110
  def signature_mismatch(required_method, provided_method)
125
111
  return nil unless required_method.method_types.size == 1
126
112
  return nil unless provided_method.method_types.size == 1
@@ -158,14 +144,13 @@ module Rigor
158
144
  nil
159
145
  end
160
146
 
161
- # Checks positional-count divergence — cases that would cause a
162
- # runtime `ArgumentError` even when every declared type matches.
163
- # Skipped when either side has a rest parameter (`*args`) since
164
- # that makes the arity range unbounded. Two violation shapes:
165
- # (a) provided requires MORE positionals than the interface allows
166
- # (caller passes interface total provided raises);
167
- # (b) provided accepts FEWER positionals than the interface requires
168
- # (caller passes ≥ interface required → provided raises).
147
+ # Checks positional-count divergence — cases that would cause a runtime `ArgumentError` even when every
148
+ # declared type matches. Skipped when either side has a rest parameter (`*args`) since that makes the
149
+ # arity range unbounded. Two violation shapes:
150
+ # (a) provided requires MORE positionals than the interface allows (caller passes interface total →
151
+ # provided raises);
152
+ # (b) provided accepts FEWER positionals than the interface requires (caller passes interface required
153
+ # provided raises).
169
154
  def arity_detail(required_method, provided_method)
170
155
  req_func = required_method.method_types.first.type
171
156
  prov_func = provided_method.method_types.first.type
@@ -193,11 +178,10 @@ module Rigor
193
178
  end
194
179
 
195
180
  # Checks keyword-requiredness divergence.
196
- # (a) A keyword the interface requires that the provided method does
197
- # not accept at all → callers will pass it, provided will raise.
198
- # (b) A keyword the provided method requires that the interface does
199
- # not mention → callers following the interface won't pass it,
200
- # provided will raise.
181
+ # (a) A keyword the interface requires that the provided method does not accept at all → callers will pass
182
+ # it, provided will raise.
183
+ # (b) A keyword the provided method requires that the interface does not mention → callers following the
184
+ # interface won't pass it, provided will raise.
201
185
  # Skipped when either side has a keyword rest (`**kwargs`).
202
186
  def keyword_detail(required_method, provided_method)
203
187
  req_func, prov_func = keyword_funcs(required_method, provided_method)
@@ -245,13 +229,11 @@ module Rigor
245
229
  (func.required_positionals + func.optional_positionals).map { |param| translate(param.type) }
246
230
  end
247
231
 
248
- # Resolves the (possibly namespace-relative) `interface_name` against
249
- # the declaring class's namespace chain, mirroring Ruby constant
250
- # lookup: `conforms-to _Foo` inside `Bar::Baz` tries `Bar::Baz::_Foo`,
251
- # `Bar::_Foo`, then top-level `_Foo` (longest prefix first). Returns
252
- # the first interface definition that resolves, or nil. (A leading
253
- # `::` is already stripped by the parser, so an intended-absolute name
254
- # still resolves via the trailing top-level candidate.)
232
+ # Resolves the (possibly namespace-relative) `interface_name` against the declaring class's namespace
233
+ # chain, mirroring Ruby constant lookup: `conforms-to _Foo` inside `Bar::Baz` tries `Bar::Baz::_Foo`,
234
+ # `Bar::_Foo`, then top-level `_Foo` (longest prefix first). Returns the first interface definition that
235
+ # resolves, or nil. (A leading `::` is already stripped by the parser, so an intended-absolute name still
236
+ # resolves via the trailing top-level candidate.)
255
237
  def resolve_interface(rbs_loader, class_name, interface_name)
256
238
  candidate_interface_names(class_name, interface_name).each do |candidate|
257
239
  defn = rbs_loader.interface_definition(candidate)
@@ -265,11 +247,9 @@ module Rigor
265
247
  prefixes.map { |prefix| "#{prefix}::#{interface_name}" } + [interface_name]
266
248
  end
267
249
 
268
- # Namespace prefixes of a qualified name, longest first:
269
- # `"Bar::Baz"` `["Bar::Baz", "Bar"]`. Covers both the
270
- # `class Bar::Baz` and the `module Bar; class Baz` nesting shapes
271
- # (a superset of `Module.nesting`, which the directive's resolved
272
- # class name does not record).
250
+ # Namespace prefixes of a qualified name, longest first: `"Bar::Baz"` → `["Bar::Baz", "Bar"]`. Covers both
251
+ # the `class Bar::Baz` and the `module Bar; class Baz` nesting shapes (a superset of `Module.nesting`,
252
+ # which the directive's resolved class name does not record).
273
253
  def namespace_prefixes(class_name)
274
254
  parts = normalize(class_name).split("::")
275
255
  (1..parts.size).to_a.reverse.map { |count| parts.first(count).join("::") }
@@ -5,35 +5,25 @@ require_relative "../inference/hkt_body_parser"
5
5
 
6
6
  module Rigor
7
7
  module RbsExtended
8
- # ADR-20 § "Decision D6" parser for the two new HKT
9
- # directives that live in `.rbs` files at module / class
8
+ # ADR-20 § "Decision D6" parser for the two new HKT directives that live in `.rbs` files at module / class
10
9
  # scope:
11
10
  #
12
- # - `%a{rigor:v1:hkt_register: uri=<uri> arity=<int>
13
- # variance=<v1>,<v2>,... bound=<class_name_or_untyped>}` —
14
- # registers a defunctionalised type-constructor URI
15
- # together with its arity, per-position variance, and
11
+ # - `%a{rigor:v1:hkt_register: uri=<uri> arity=<int> variance=<v1>,<v2>,... bound=<class_name_or_untyped>}` —
12
+ # registers a defunctionalised type-constructor URI together with its arity, per-position variance, and
16
13
  # erasure bound.
17
- # - `%a{rigor:v1:hkt_define: uri=<uri> params=<P1>,<P2>,...
18
- # body=<body_text>}` binds the URI to a type-function
19
- # body that {HktBodyParser} parses into an
20
- # {HktBody::Union} tree.
14
+ # - `%a{rigor:v1:hkt_define: uri=<uri> params=<P1>,<P2>,... body=<body_text>}` — binds the URI to a
15
+ # type-function body that {HktBodyParser} parses into an {HktBody::Union} tree.
21
16
  #
22
17
  # ## Payload format
23
18
  #
24
- # **Space-separated `key=value` pairs.** The format is
25
- # constrained by RBS's `%a{...}` annotation grammar, which
26
- # does NOT accept arbitrary nested punctuation (a JSON
27
- # payload with quotes / nested braces will fail RBS
28
- # parsing). Each value is a bare token: no quoting, no
29
- # escaping. Values that contain spaces or `=` signs MUST
30
- # be encoded via the `body=` key, which is special-cased
31
- # to gobble everything from `body=` to the end of the
19
+ # **Space-separated `key=value` pairs.** The format is constrained by RBS's `%a{...}` annotation grammar,
20
+ # which does NOT accept arbitrary nested punctuation (a JSON payload with quotes / nested braces will fail RBS
21
+ # parsing). Each value is a bare token: no quoting, no escaping. Values that contain spaces or `=` signs MUST
22
+ # be encoded via the `body=` key, which is special-cased to gobble everything from `body=` to the end of the
32
23
  # payload — see `parse_define`.
33
24
  #
34
- # Example annotations (write inside a class / module
35
- # declaration so the annotation attaches to the decl
36
- # RBS parses):
25
+ # Example annotations (write inside a class / module declaration so the annotation attaches to the decl RBS
26
+ # parses):
37
27
  #
38
28
  # %a{rigor:v1:hkt_register: uri=json::value arity=1
39
29
  # variance=out bound=untyped}
@@ -46,18 +36,13 @@ module Rigor
46
36
  #
47
37
  # ## Bound vocabulary
48
38
  #
49
- # - `untyped` resolves to `Rigor::Type::Combinator.untyped`
50
- # (i.e. `Dynamic[Top]`, the ADR-20 WD2 default).
51
- # - A bare class name (`String`, `Integer`, …) resolves
52
- # through `name_scope.nominal_for_name(...)` when
53
- # supplied, falling back to a raw `Rigor::Type::Nominal`
54
- # otherwise.
55
- # - Anything else falls back to `untyped` and emits an
56
- # `:info` diagnostic via the supplied reporter (fail-soft
39
+ # - `untyped` resolves to `Rigor::Type::Combinator.untyped` (i.e. `Dynamic[Top]`, the ADR-20 WD2 default).
40
+ # - A bare class name (`String`, `Integer`, …) resolves through `name_scope.nominal_for_name(...)` when
41
+ # supplied, falling back to a raw `Rigor::Type::Nominal` otherwise.
42
+ # - Anything else falls back to `untyped` and emits an `:info` diagnostic via the supplied reporter (fail-soft
57
43
  # so an unrecognised bound never crashes the loader).
58
44
  #
59
- # Richer bound forms (parameterised generics, unions,
60
- # refinements) wait for a follow-up slice's expression
45
+ # Richer bound forms (parameterised generics, unions, refinements) wait for a follow-up slice's expression
61
46
  # parser.
62
47
  module HktDirectives
63
48
  module_function
@@ -68,10 +53,8 @@ module Rigor
68
53
  DEFAULT_VARIANCE = :inv
69
54
  DEFAULT_BOUND_LITERAL = "untyped"
70
55
 
71
- # Parses one `%a{rigor:v1:hkt_register: ...}` payload
72
- # string and returns a `Registration`, or `nil` when the
73
- # string is not an hkt_register directive (so callers can
74
- # walk a list of annotations without each having to
56
+ # Parses one `%a{rigor:v1:hkt_register: ...}` payload string and returns a `Registration`, or `nil` when the
57
+ # string is not an hkt_register directive (so callers can walk a list of annotations without each having to
75
58
  # pre-filter).
76
59
  def parse_register(string, name_scope: nil, reporter: nil, source_location: nil)
77
60
  payload = extract_payload(string, REGISTER_DIRECTIVE)
@@ -106,8 +89,7 @@ module Rigor
106
89
  nil
107
90
  end
108
91
 
109
- # Parses one `%a{rigor:v1:hkt_define: ...}` payload
110
- # string and returns a `Definition`, or `nil` when the
92
+ # Parses one `%a{rigor:v1:hkt_define: ...}` payload string and returns a `Definition`, or `nil` when the
111
93
  # string is not an hkt_define directive.
112
94
  def parse_define(string, reporter: nil, source_location: nil)
113
95
  payload = extract_payload(string, DEFINE_DIRECTIVE)
@@ -149,8 +131,7 @@ module Rigor
149
131
  return nil if idx.nil?
150
132
 
151
133
  payload = string[(idx + directive.size)..].to_s.strip
152
- # Strip trailing `}` of the wrapping `%a{...}` form if
153
- # the caller passed the raw annotation string. The
134
+ # Strip trailing `}` of the wrapping `%a{...}` form if the caller passed the raw annotation string. The
154
135
  # parser also accepts a pre-extracted payload.
155
136
  payload = payload.sub(/\}\z/, "") if payload.end_with?("}") && !balanced_braces?(payload)
156
137
  payload.empty? ? nil : payload
@@ -169,19 +150,15 @@ module Rigor
169
150
  depth.zero?
170
151
  end
171
152
 
172
- # Parses a space-separated `key=value [key=value ...]`
173
- # payload into a Hash. When `body_key` is supplied AND
174
- # that key appears, everything from `<body_key>=` to
175
- # the end of the payload becomes the value (body
176
- # contents typically include spaces, `|`, `[]` etc.
177
- # that the simple tokenizer cannot otherwise carry).
153
+ # Parses a space-separated `key=value [key=value ...]` payload into a Hash. When `body_key` is supplied AND
154
+ # that key appears, everything from `<body_key>=` to the end of the payload becomes the value (body
155
+ # contents typically include spaces, `|`, `[]` etc. that the simple tokenizer cannot otherwise carry).
178
156
  KV_KEY_PATTERN = /(?<![\w.])([a-z_]\w*)=/
179
157
  private_constant :KV_KEY_PATTERN
180
158
 
181
159
  def parse_kv_payload(payload, body_key:)
182
160
  result = {}
183
- # Find every `<key>=` boundary; each value runs to
184
- # the next boundary or end of string.
161
+ # Find every `<key>=` boundary; each value runs to the next boundary or end of string.
185
162
  markers = []
186
163
  payload.scan(KV_KEY_PATTERN) { markers << [::Regexp.last_match[1], ::Regexp.last_match.end(0)] }
187
164
  markers.each_with_index do |(key, value_start), i|
@@ -196,13 +173,10 @@ module Rigor
196
173
  result
197
174
  end
198
175
 
199
- # ADR-20 slice 2b — parse the body String into an
200
- # `HktBody::*` tree via {Inference::HktBodyParser.parse}.
201
- # On parse failure: emit a fail-soft `:info` reporter
202
- # entry and return `nil` so the resulting Definition
203
- # keeps its `body` String slot but `body_tree` stays
204
- # absent (the reducer falls back to `app.bound` at call
205
- # time per ADR-20 D5).
176
+ # ADR-20 slice 2b — parse the body String into an `HktBody::*` tree via {Inference::HktBodyParser.parse}. On
177
+ # parse failure: emit a fail-soft `:info` reporter entry and return `nil` so the resulting Definition keeps
178
+ # its `body` String slot but `body_tree` stays absent (the reducer falls back to `app.bound` at call time
179
+ # per ADR-20 D5).
206
180
  def parse_body_tree(body, params, reporter:, source_location:)
207
181
  return nil if body.nil? || body.empty?
208
182
 
@@ -2,35 +2,26 @@
2
2
 
3
3
  module Rigor
4
4
  module RbsExtended
5
- # ADR-13 slice 3b — per-run accumulator for `RBS::Extended`
6
- # diagnostic events that the parser / resolver cannot surface
7
- # at the point of failure (the parsers are fail-soft, returning
8
- # `nil` so call sites fall back to the RBS-declared type).
5
+ # ADR-13 slice 3b — per-run accumulator for `RBS::Extended` diagnostic events that the parser / resolver
6
+ # cannot surface at the point of failure (the parsers are fail-soft, returning `nil` so call sites fall back
7
+ # to the RBS-declared type).
9
8
  #
10
9
  # Owns two event streams:
11
10
  #
12
- # - `#unresolved_payloads` — `rigor:v1:*` directive payloads
13
- # the resolver could not turn into a {Rigor::Type}. Surface
14
- # as `dynamic.rbs-extended.unresolved` `:info` diagnostics.
15
- # - `#lossy_projections` shape-projection type functions
16
- # (`pick_of` / `omit_of` / `partial_of` / `required_of` /
17
- # `readonly_of`) applied to a carrier that does not preserve
18
- # shape information (anything other than `Type::HashShape`
19
- # / `Type::Tuple`). Surface as
20
- # `dynamic.shape.lossy-projection` `:info` diagnostics.
11
+ # - `#unresolved_payloads` — `rigor:v1:*` directive payloads the resolver could not turn into a
12
+ # {Rigor::Type}. Surface as `dynamic.rbs-extended.unresolved` `:info` diagnostics.
13
+ # - `#lossy_projections` — shape-projection type functions (`pick_of` / `omit_of` / `partial_of` /
14
+ # `required_of` / `readonly_of`) applied to a carrier that does not preserve shape information (anything
15
+ # other than `Type::HashShape` / `Type::Tuple`). Surface as `dynamic.shape.lossy-projection` `:info`
16
+ # diagnostics.
21
17
  #
22
- # Mutable through the run; consumed once by
23
- # {Rigor::Analysis::Runner} at end-of-run. Each event is
24
- # deduplicated by `(payload, source_location)` for unresolved
25
- # and `(head, source_location)` for lossy-projection so a
26
- # single annotation read from many call sites yields one
27
- # diagnostic.
18
+ # Mutable through the run; consumed once by {Rigor::Analysis::Runner} at end-of-run. Each event is
19
+ # deduplicated by `(payload, source_location)` for unresolved and `(head, source_location)` for
20
+ # lossy-projection so a single annotation read from many call sites yields one diagnostic.
28
21
  #
29
- # The reporter is intentionally thread-safe via a coarse
30
- # `Mutex` because the inference engine may read the same
31
- # method definition from multiple files in parallel; the
32
- # critical sections are short (Array#include? + Array#<<) so
33
- # the lock contention is negligible.
22
+ # The reporter is intentionally thread-safe via a coarse `Mutex` because the inference engine may read the
23
+ # same method definition from multiple files in parallel; the critical sections are short (Array#include? +
24
+ # Array#<<) so the lock contention is negligible.
34
25
  class Reporter
35
26
  UnresolvedEntry = Data.define(:payload, :source_location)
36
27
  LossyProjectionEntry = Data.define(:head, :source_location)
@@ -41,23 +32,19 @@ module Rigor
41
32
  @mutex = Mutex.new
42
33
  end
43
34
 
44
- # @return [Array<UnresolvedEntry>] frozen snapshot of the
45
- # accumulated unresolved-payload events.
35
+ # @return [Array<UnresolvedEntry>] frozen snapshot of the accumulated unresolved-payload events.
46
36
  def unresolved_payloads
47
37
  @mutex.synchronize { @unresolved_payloads.dup.freeze }
48
38
  end
49
39
 
50
- # @return [Array<LossyProjectionEntry>] frozen snapshot of
51
- # the accumulated lossy-projection events.
40
+ # @return [Array<LossyProjectionEntry>] frozen snapshot of the accumulated lossy-projection events.
52
41
  def lossy_projections
53
42
  @mutex.synchronize { @lossy_projections.dup.freeze }
54
43
  end
55
44
 
56
- # Records a `dynamic.rbs-extended.unresolved` event. The
57
- # `source_location` argument is the {RBS::Location} attached
58
- # to the source annotation (or `nil` when the caller doesn't
59
- # have one — the diagnostic falls back to a generic
60
- # location in that case).
45
+ # Records a `dynamic.rbs-extended.unresolved` event. The `source_location` argument is the {RBS::Location}
46
+ # attached to the source annotation (or `nil` when the caller doesn't have one — the diagnostic falls back
47
+ # to a generic location in that case).
61
48
  def record_unresolved(payload:, source_location: nil)
62
49
  entry = UnresolvedEntry.new(payload: payload.to_s, source_location: source_location)
63
50
  @mutex.synchronize do
@@ -67,10 +54,8 @@ module Rigor
67
54
  end
68
55
  end
69
56
 
70
- # Records a `dynamic.shape.lossy-projection` event for one
71
- # of the five shape-projection heads. `head` MUST be a
72
- # String (`"pick_of"`, `"omit_of"`, …); the diagnostic
73
- # message identifies which projection degraded.
57
+ # Records a `dynamic.shape.lossy-projection` event for one of the five shape-projection heads. `head` MUST
58
+ # be a String (`"pick_of"`, `"omit_of"`, …); the diagnostic message identifies which projection degraded.
74
59
  def record_lossy_projection(head:, source_location: nil)
75
60
  entry = LossyProjectionEntry.new(head: head.to_s, source_location: source_location)
76
61
  @mutex.synchronize do
@@ -80,9 +65,8 @@ module Rigor
80
65
  end
81
66
  end
82
67
 
83
- # True when no events have accumulated. Used by callers
84
- # that want to skip the diagnostic-emission pass entirely
85
- # on the common no-event path.
68
+ # True when no events have accumulated. Used by callers that want to skip the diagnostic-emission pass
69
+ # entirely on the common no-event path.
86
70
  def empty?
87
71
  @mutex.synchronize { @unresolved_payloads.empty? && @lossy_projections.empty? }
88
72
  end