rigortype 0.1.19 → 0.2.1

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 (197) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +41 -6
  3. data/data/core_overlay/numeric.rbs +33 -0
  4. data/data/core_overlay/pathname.rbs +25 -0
  5. data/data/core_overlay/string_scanner.rbs +28 -0
  6. data/data/gem_overlay/activesupport/core_ext.rbs +473 -0
  7. data/data/vendored_gem_sigs/ast/ast.rbs +130 -0
  8. data/data/vendored_gem_sigs/bcrypt/bcrypt.rbs +47 -0
  9. data/data/vendored_gem_sigs/bundler/bundler.rbs +238 -0
  10. data/data/vendored_gem_sigs/cgi/cgi_extras.rbs +34 -0
  11. data/data/vendored_gem_sigs/did_you_mean/did_you_mean_extras.rbs +34 -0
  12. data/data/vendored_gem_sigs/idn-ruby/idn.rbs +54 -0
  13. data/data/vendored_gem_sigs/mysql2/client.rbs +55 -0
  14. data/data/vendored_gem_sigs/mysql2/error.rbs +5 -0
  15. data/data/vendored_gem_sigs/mysql2/result.rbs +31 -0
  16. data/data/vendored_gem_sigs/mysql2/statement.rbs +5 -0
  17. data/data/vendored_gem_sigs/nokogiri/nokogiri.rbs +2332 -0
  18. data/data/vendored_gem_sigs/nokogiri/nokogiri_html5.rbs +47 -0
  19. data/data/vendored_gem_sigs/pg/pg.rbs +212 -0
  20. data/data/vendored_gem_sigs/prism/prism_supplement.rbs +44 -0
  21. data/data/vendored_gem_sigs/redis/errors.rbs +50 -0
  22. data/data/vendored_gem_sigs/redis/future.rbs +5 -0
  23. data/data/vendored_gem_sigs/redis/redis.rbs +348 -0
  24. data/data/vendored_gem_sigs/redis/redis_extras.rbs +130 -0
  25. data/data/vendored_gem_sigs/rubygems/rubygems_extras.rbs +226 -0
  26. data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +3 -23
  27. data/lib/rigor/analysis/check_rules/rule_walk.rb +3 -21
  28. data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +24 -15
  29. data/lib/rigor/analysis/check_rules.rb +492 -71
  30. data/lib/rigor/analysis/dependency_source_inference/index.rb +4 -7
  31. data/lib/rigor/analysis/dependency_source_inference/walker.rb +2 -18
  32. data/lib/rigor/analysis/dependency_source_inference.rb +3 -12
  33. data/lib/rigor/analysis/fact_store.rb +5 -4
  34. data/lib/rigor/analysis/rule_catalog.rb +153 -6
  35. data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +17 -17
  36. data/lib/rigor/analysis/runner/project_pre_passes.rb +9 -8
  37. data/lib/rigor/analysis/runner.rb +17 -6
  38. data/lib/rigor/analysis/self_call_resolution_recorder.rb +3 -4
  39. data/lib/rigor/analysis/worker_session.rb +10 -14
  40. data/lib/rigor/builtins/predefined_constant_refinements.rb +151 -0
  41. data/lib/rigor/cache/store.rb +5 -3
  42. data/lib/rigor/cli/annotate_command.rb +28 -7
  43. data/lib/rigor/cli/baseline_command.rb +4 -3
  44. data/lib/rigor/cli/check_command.rb +138 -16
  45. data/lib/rigor/cli/coverage_command.rb +138 -31
  46. data/lib/rigor/cli/coverage_mutation.rb +149 -0
  47. data/lib/rigor/cli/coverage_scan.rb +57 -0
  48. data/lib/rigor/cli/explain_command.rb +2 -0
  49. data/lib/rigor/cli/fused_protection_renderer.rb +67 -0
  50. data/lib/rigor/cli/fused_protection_report.rb +76 -0
  51. data/lib/rigor/cli/lsp_command.rb +3 -7
  52. data/lib/rigor/cli/mutation_protection_renderer.rb +63 -0
  53. data/lib/rigor/cli/mutation_protection_report.rb +73 -0
  54. data/lib/rigor/cli/options.rb +9 -0
  55. data/lib/rigor/cli/plugins_command.rb +2 -1
  56. data/lib/rigor/cli/protection_renderer.rb +63 -0
  57. data/lib/rigor/cli/protection_report.rb +68 -0
  58. data/lib/rigor/cli/sig_gen_command.rb +2 -1
  59. data/lib/rigor/cli/trace_command.rb +2 -1
  60. data/lib/rigor/cli/triage_command.rb +2 -1
  61. data/lib/rigor/cli/type_of_command.rb +1 -1
  62. data/lib/rigor/cli/type_scan_command.rb +2 -1
  63. data/lib/rigor/cli.rb +3 -2
  64. data/lib/rigor/config_audit.rb +152 -0
  65. data/lib/rigor/configuration/dependencies.rb +2 -4
  66. data/lib/rigor/configuration.rb +57 -7
  67. data/lib/rigor/environment/bundle_sig_discovery.rb +61 -13
  68. data/lib/rigor/environment/class_registry.rb +4 -3
  69. data/lib/rigor/environment/constant_type_cache_holder.rb +43 -0
  70. data/lib/rigor/environment/lockfile_resolver.rb +1 -1
  71. data/lib/rigor/environment/rbs_collection_discovery.rb +1 -2
  72. data/lib/rigor/environment/rbs_coverage_report.rb +2 -1
  73. data/lib/rigor/environment/rbs_loader.rb +76 -5
  74. data/lib/rigor/environment.rb +66 -8
  75. data/lib/rigor/flow_contribution/fact.rb +1 -1
  76. data/lib/rigor/flow_contribution.rb +3 -5
  77. data/lib/rigor/inference/acceptance.rb +17 -9
  78. data/lib/rigor/inference/block_parameter_binder.rb +2 -3
  79. data/lib/rigor/inference/builtins/comparable_catalog.rb +2 -2
  80. data/lib/rigor/inference/builtins/enumerable_catalog.rb +2 -2
  81. data/lib/rigor/inference/builtins/method_catalog.rb +19 -0
  82. data/lib/rigor/inference/builtins/string_catalog.rb +9 -1
  83. data/lib/rigor/inference/expression_typer.rb +20 -28
  84. data/lib/rigor/inference/hkt_body.rb +8 -11
  85. data/lib/rigor/inference/hkt_body_parser.rb +10 -12
  86. data/lib/rigor/inference/hkt_registry.rb +10 -11
  87. data/lib/rigor/inference/method_dispatcher/call_context.rb +1 -4
  88. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +169 -24
  89. data/lib/rigor/inference/method_dispatcher/data_folding.rb +9 -73
  90. data/lib/rigor/inference/method_dispatcher/file_folding.rb +6 -7
  91. data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +10 -16
  92. data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +25 -13
  93. data/lib/rigor/inference/method_dispatcher/member_shape_projection.rb +93 -0
  94. data/lib/rigor/inference/method_dispatcher/overload_selector.rb +1 -3
  95. data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +24 -22
  96. data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +90 -15
  97. data/lib/rigor/inference/method_dispatcher/struct_folding.rb +303 -0
  98. data/lib/rigor/inference/method_dispatcher.rb +40 -48
  99. data/lib/rigor/inference/mutation_widening.rb +5 -11
  100. data/lib/rigor/inference/narrowing.rb +14 -16
  101. data/lib/rigor/inference/parameter_inference_collector.rb +367 -0
  102. data/lib/rigor/inference/project_patched_methods.rb +4 -7
  103. data/lib/rigor/inference/project_patched_scanner.rb +2 -13
  104. data/lib/rigor/inference/protection_scanner.rb +86 -0
  105. data/lib/rigor/inference/scope_indexer.rb +129 -55
  106. data/lib/rigor/inference/statement_evaluator.rb +271 -114
  107. data/lib/rigor/inference/struct_fold_safety.rb +181 -0
  108. data/lib/rigor/inference/synthetic_method.rb +7 -7
  109. data/lib/rigor/language_server/completion_provider.rb +6 -12
  110. data/lib/rigor/language_server/diagnostic_publisher.rb +4 -4
  111. data/lib/rigor/language_server/document_symbol_provider.rb +3 -3
  112. data/lib/rigor/language_server/hover_provider.rb +2 -3
  113. data/lib/rigor/language_server/hover_renderer.rb +2 -11
  114. data/lib/rigor/language_server/server.rb +9 -17
  115. data/lib/rigor/language_server.rb +4 -5
  116. data/lib/rigor/plugin/base.rb +10 -8
  117. data/lib/rigor/plugin/macro/block_as_method.rb +3 -4
  118. data/lib/rigor/plugin/macro/heredoc_template.rb +4 -7
  119. data/lib/rigor/plugin/macro/trait_registry.rb +3 -6
  120. data/lib/rigor/plugin/macro.rb +4 -5
  121. data/lib/rigor/plugin/manifest.rb +45 -66
  122. data/lib/rigor/plugin/registry.rb +6 -7
  123. data/lib/rigor/plugin/type_node_resolver.rb +6 -8
  124. data/lib/rigor/protection/diagnostic_oracle.rb +51 -0
  125. data/lib/rigor/protection/mutation_scanner.rb +180 -0
  126. data/lib/rigor/protection/mutator.rb +267 -0
  127. data/lib/rigor/protection/test_suite_oracle.rb +68 -0
  128. data/lib/rigor/rbs_extended.rb +24 -36
  129. data/lib/rigor/reflection.rb +4 -7
  130. data/lib/rigor/scope/discovery_index.rb +14 -2
  131. data/lib/rigor/scope.rb +54 -11
  132. data/lib/rigor/sig_gen/observed_call.rb +3 -3
  133. data/lib/rigor/sig_gen/writer.rb +40 -2
  134. data/lib/rigor/signature_path_audit.rb +92 -0
  135. data/lib/rigor/source/constant_path.rb +62 -0
  136. data/lib/rigor/source.rb +1 -0
  137. data/lib/rigor/type/bound_method.rb +2 -11
  138. data/lib/rigor/type/combinator.rb +16 -3
  139. data/lib/rigor/type/constant.rb +2 -11
  140. data/lib/rigor/type/data_class.rb +2 -11
  141. data/lib/rigor/type/data_instance.rb +2 -11
  142. data/lib/rigor/type/hash_shape.rb +2 -11
  143. data/lib/rigor/type/integer_range.rb +2 -11
  144. data/lib/rigor/type/intersection.rb +2 -11
  145. data/lib/rigor/type/nominal.rb +2 -11
  146. data/lib/rigor/type/plain_lattice.rb +37 -0
  147. data/lib/rigor/type/refined.rb +72 -13
  148. data/lib/rigor/type/singleton.rb +2 -11
  149. data/lib/rigor/type/struct_class.rb +75 -0
  150. data/lib/rigor/type/struct_instance.rb +93 -0
  151. data/lib/rigor/type/tuple.rb +5 -15
  152. data/lib/rigor/type.rb +2 -0
  153. data/lib/rigor/version.rb +1 -1
  154. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +1 -1
  155. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +3 -3
  156. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +3 -3
  157. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +5 -13
  158. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +11 -17
  159. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +7 -10
  160. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +3 -2
  161. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +4 -4
  162. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +6 -8
  163. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +5 -7
  164. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +1 -2
  165. data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +9 -11
  166. data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +8 -9
  167. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +13 -12
  168. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +3 -4
  169. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +8 -8
  170. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +9 -11
  171. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +7 -8
  172. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +7 -9
  173. data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +12 -13
  174. data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +15 -23
  175. data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +3 -3
  176. data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +3 -3
  177. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +2 -4
  178. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +27 -11
  179. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +1 -1
  180. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +4 -6
  181. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +12 -18
  182. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +5 -5
  183. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +3 -4
  184. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +1 -1
  185. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +1 -1
  186. data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +19 -14
  187. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +0 -1
  188. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +5 -4
  189. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +2 -3
  190. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb +7 -11
  191. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +4 -5
  192. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +6 -9
  193. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +5 -15
  194. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +28 -41
  195. data/sig/rigor/scope.rbs +9 -1
  196. data/sig/rigor/type.rbs +36 -1
  197. metadata +49 -1
@@ -17,15 +17,12 @@ module Rigor
17
17
  # default) when no sigil is present, matching how Sorbet
18
18
  # treats sigil-less files.
19
19
  #
20
- # Slice 5 of ADR-11 uses this purely at catalog-harvest
21
- # time: `# typed: ignore` files are skipped entirely (the
22
- # plugin records no sigs from them). The other levels are
23
- # detected for forward compatibility but treated
24
- # identically per-call-site sigil honouring (e.g. only
25
- # firing `T.let` recognition in `# typed: true`+ files)
26
- # requires threading the file path through
27
- # the per-call recognition path, which lives behind a
28
- # future plugin-contract widening slice.
20
+ # ADR-11 slice 5 uses this at catalog-harvest time:
21
+ # `# typed: ignore` files are skipped entirely; other
22
+ # levels gate both sig contributions (`:true`/`:strict`/
23
+ # `:strong` only) and per-call assertion recognition
24
+ # (`T.let` / `T.cast` / `T.must` / etc.) via
25
+ # `Sorbet#assertion_enforced_here?`.
29
26
  module SigilDetector
30
27
  # Sorbet's strictness-level names. Stored as symbols to
31
28
  # match the analyzer's existing convention for level
@@ -9,14 +9,6 @@ module Rigor
9
9
  # block's `params(...)` and `returns(...)` clauses) into
10
10
  # Rigor's internal type carriers.
11
11
  #
12
- # Slice 1 covered the minimum vocabulary that lets a
13
- # typical `sig { params(x: Integer).returns(String) }`
14
- # round-trip; slice 3 widens it to cover the dense middle
15
- # of Sorbet's surface — generic class applications
16
- # (`T::Array[E]`, `T::Hash[K, V]`, etc.), class-object
17
- # types (`T.class_of(C)`, `T::Class[T]`), tuples, and
18
- # shapes:
19
- #
20
12
  # | Sorbet form | Rigor carrier |
21
13
  # | ------------------------ | ---------------------------------------- |
22
14
  # | `Integer` etc. | `Nominal["Integer"]` |
@@ -42,10 +34,9 @@ module Rigor
42
34
  #
43
35
  # Anything else (`T.proc`, `T.attached_class`,
44
36
  # `T.self_type`, `T.type_parameter`, `T::Struct` / `T::Enum`
45
- # subclasses, …) degrades to `Dynamic[top]`. The degraded
46
- # path stays silent for now per ADR-11's slice plan; a
47
- # later slice surfaces the gap as a `dynamic.sorbet.unsupported`
48
- # diagnostic.
37
+ # subclasses, …) degrades silently to `Dynamic[top]`. The
38
+ # `dynamic.sorbet.unsupported` diagnostic for degraded
39
+ # forms is deferred.
49
40
  module TypeTranslator
50
41
  BOOLEAN_NAME = "Boolean"
51
42
 
@@ -235,9 +226,8 @@ module Rigor
235
226
  # analogue (Singleton names a specific class); the
236
227
  # closest faithful translation is `Singleton[name]`
237
228
  # when `T` is a constant, or `Singleton[Object]` for
238
- # broader applications. Lossy translation; emitted as
239
- # `dynamic.sorbet.degraded` once slice 3's diagnostic
240
- # surface lands.
229
+ # broader applications. Lossy the `dynamic.sorbet.degraded`
230
+ # diagnostic for this case is deferred.
241
231
  def translate_t_class_subscript(args)
242
232
  inner = args.first
243
233
  return Rigor::Type::Combinator.singleton_of("Class") if inner.nil?
@@ -29,11 +29,10 @@ module Rigor
29
29
  # nesting; `def self.foo` is recognised as a singleton
30
30
  # method.
31
31
  #
32
- # Slice 1 vocabulary is the bare minimum to round-trip the
33
- # most common sig shapes; the {TypeTranslator} table
34
- # documents what's covered. Anything else (T.proc / T::Array
35
- # / T.class_of / T::Struct) degrades silently to
36
- # `Dynamic[top]` for now — slice 3 widens the translator.
32
+ # The {TypeTranslator} table documents coverage. Most of
33
+ # Sorbet's vocabulary translates; remaining gaps (`T.proc`,
34
+ # `T::Struct` subclasses, `T.attached_class`, etc.) degrade
35
+ # silently to `Dynamic[top]`.
37
36
  #
38
37
  # Architecture: per-run `Catalog` is built lazily on first
39
38
  # access by walking every configured `paths:` entry's `.rb`
@@ -99,20 +98,15 @@ module Rigor
99
98
  # `false` to record every file's sigs regardless of
100
99
  # sigil (current behaviour pre-this-config).
101
100
  @enforce_sigil = config.fetch("enforce_sigil")
102
- # ADR-11 deferred follow-up — per-call-site assertion
103
- # gating. Catalog harvest's `@sigil_by_path` cache is
104
- # consulted at every per-call recognition so
105
- # `T.let` / `T.cast` / `T.must` / `T.bind` /
106
- # `T.assert_type!` only fire in files Sorbet itself
107
- # would enforce (`# typed: true` / `:strict` /
108
- # `:strong`). When `@enforce_sigil` is off (the user
109
- # opted out at harvest time), the gate also opens at
110
- # every call site — current behaviour. Files whose
111
- # sigil hasn't been observed yet (e.g. the catalog
112
- # hasn't run, or the call site is in a fixture /
113
- # synthetic path the harvest didn't see) treat
114
- # missing-info as enforced — failing-open is friendlier
115
- # for spec ergonomics than failing-closed.
101
+ # Per-call-site assertion gating: `@sigil_by_path` (built
102
+ # during catalog harvest) is consulted so `T.let` /
103
+ # `T.cast` / `T.must` / `T.bind` / `T.assert_type!` only
104
+ # fire in files Sorbet itself would enforce (`:true` /
105
+ # `:strict` / `:strong`). With `enforce_sigil: false` the
106
+ # gate is open everywhere. Missing-sigil paths (synthetic
107
+ # fixtures, out-of-tree call sites) default to enforced —
108
+ # failing-open suits spec ergonomics better than
109
+ # failing-closed. See `assertion_enforced_here?`.
116
110
  @sigil_by_path = {}
117
111
  @catalog = nil
118
112
  @parse_errors_by_path = {}
@@ -160,8 +154,7 @@ module Rigor
160
154
  diagnostics
161
155
  end
162
156
 
163
- # ADR-52 slice 4 — the per-call return-type path, migrated off
164
- # the legacy `flow_contribution_for` hook onto the
157
+ # ADR-52 slice 4 — per-call return-type path via the
165
158
  # method-name-gated `dynamic_return` DSL. The recognised name
166
159
  # set is only known at run time (the catalog's `def` names come
167
160
  # from the lazy catalog build), so it is declared as a
@@ -170,17 +163,15 @@ module Rigor
170
163
  # resolved Symbol Set. The gate is a safe over-approximation —
171
164
  # a project method merely *named* `cast` or `find` passes it
172
165
  # and is declined by the block's own `T.`-receiver / catalog
173
- # checks, exactly as the ungated hook used to decline.
166
+ # checks.
174
167
  dynamic_return methods: -> { recognised_method_names } do |call_node, scope|
175
168
  contribution_return_type(call_node, scope)
176
169
  end
177
170
 
178
171
  # ADR-52 slice 4 — `T.bind(self, T)`'s self-narrowing fact,
179
- # migrated off the legacy hook's `post_return_facts` slot onto
180
- # the method-gated `type_specifier` DSL (once
181
- # `flow_contribution_for` is gone, the statement evaluator
182
- # consults only this path for narrowing facts). The
183
- # return-type half (`Constant[nil]`) flows through the
172
+ # contributed via the method-gated `type_specifier` DSL. The
173
+ # statement evaluator consults this path for narrowing facts.
174
+ # The return-type half (`Constant[nil]`) flows through the
184
175
  # `dynamic_return` rule above; the block re-checks the `T.`
185
176
  # receiver via the recogniser, so an unrelated `bind` call
186
177
  # contributes nothing.
@@ -190,8 +181,8 @@ module Rigor
190
181
 
191
182
  private
192
183
 
193
- # ADR-52 slice 4 — the run-time method-name gate for the
194
- # `dynamic_return` rule: the static assertion vocabulary
184
+ # Run-time method-name gate for the `dynamic_return` rule
185
+ # (ADR-52 slice 4): the static assertion vocabulary
195
186
  # (`T.let` / `T.cast` / …), `T.absurd`, and every method name
196
187
  # the catalog carries a sig for.
197
188
  def recognised_method_names
@@ -202,20 +193,17 @@ module Rigor
202
193
  names
203
194
  end
204
195
 
205
- # The migrated body of the legacy `flow_contribution_for`
206
- # same recognition order, but returns the bare `Rigor::Type`
207
- # the `dynamic_return` contract expects. Resolves the receiver
208
- # in two passes:
196
+ # Main contribution body for the `dynamic_return` rule.
197
+ # Returns the bare `Rigor::Type` the contract expects.
198
+ # Resolves the receiver in three passes:
209
199
  #
210
200
  # 1. Constant receiver (`User.find(...)`) → singleton-side
211
201
  # catalog lookup.
212
202
  # 2. Nominal receiver-type (`user.name` where `user`'s
213
203
  # inferred type is `Nominal["User"]`) → instance-side
214
204
  # catalog lookup.
215
- #
216
- # Implicit-self calls (no receiver, current-class method)
217
- # are deferred to slice 2 — slice 1 covers the common case
218
- # where the sig is on the called method's own class.
205
+ # 3. Implicit-self (receiver-less inside a method body) →
206
+ # current-class lookup via `implicit_self_lookup`.
219
207
  def contribution_return_type(call_node, scope)
220
208
  return nil unless call_node.is_a?(Prism::CallNode)
221
209
 
@@ -286,9 +274,8 @@ module Rigor
286
274
  contribution&.post_return_facts
287
275
  end
288
276
 
289
- # ADR-11 deferred follow-up — per-call-site assertion
290
- # gating. With `enforce_sigil: false`, the gate is fully
291
- # open (matches the pre-feature behaviour). With
277
+ # Per-call-site assertion gating (ADR-11). With
278
+ # `enforce_sigil: false` the gate is fully open. With
292
279
  # `enforce_sigil: true` (default), the caller file's
293
280
  # sigil must reach `:true` / `:strict` / `:strong` for
294
281
  # assertions to fire. Three honest fallbacks:
@@ -334,7 +321,7 @@ module Rigor
334
321
  end
335
322
  end
336
323
 
337
- # ADR-11 slice 2 (deferred from slice 1) — implicit-self calls.
324
+ # ADR-11 slice 2 — implicit-self calls.
338
325
  # A receiver-less call inside a method body resolves against the
339
326
  # engine's own `scope.self_type`: `Nominal[Foo]` inside an
340
327
  # instance method (instance-side lookup), `Singleton[Foo]` inside
data/sig/rigor/scope.rbs CHANGED
@@ -11,6 +11,7 @@ module Rigor
11
11
  attr_reader indexed_narrowings: Hash[IndexedKey, Type::t]
12
12
  attr_reader method_chain_narrowings: Hash[ChainKey, Type::t]
13
13
  attr_reader source_path: String?
14
+ attr_reader struct_fold_safe_locals: Set[Symbol]
14
15
 
15
16
  # ADR-53 Track A — the seed-time discovery tables live on the
16
17
  # DiscoveryIndex; Scope keeps per-table readers as delegates.
@@ -29,6 +30,8 @@ module Rigor
29
30
  def discovered_includes: () -> Hash[String, Array[String]]
30
31
  def discovered_class_sources: () -> Hash[String, Set[String]]
31
32
  def data_member_layouts: () -> Hash[String, Array[Symbol]]
33
+ def struct_member_layouts: () -> Hash[String, { members: Array[Symbol], keyword_init: bool }]
34
+ def param_inferred_types: () -> Hash[[String, Symbol, Symbol], Hash[Symbol, Type::t]]
32
35
 
33
36
  class DiscoveryIndex
34
37
  attr_reader declared_types: Hash[untyped, Type::t]
@@ -46,10 +49,12 @@ module Rigor
46
49
  attr_reader discovered_includes: Hash[String, Array[String]]
47
50
  attr_reader discovered_class_sources: Hash[String, Set[String]]
48
51
  attr_reader data_member_layouts: Hash[String, Array[Symbol]]
52
+ attr_reader struct_member_layouts: Hash[String, { members: Array[Symbol], keyword_init: bool }]
53
+ attr_reader param_inferred_types: Hash[[String, Symbol, Symbol], Hash[Symbol, Type::t]]
49
54
 
50
55
  EMPTY: DiscoveryIndex
51
56
 
52
- def with: (?declared_types: Hash[untyped, Type::t], ?class_ivars: Hash[String, Hash[Symbol, Type::t]], ?class_cvars: Hash[String, Hash[Symbol, Type::t]], ?program_globals: Hash[Symbol, Type::t], ?discovered_classes: Hash[String, Type::Singleton], ?in_source_constants: Hash[String, Type::t], ?discovered_methods: Hash[String, Hash[Symbol, Symbol]], ?discovered_def_nodes: Hash[String, Hash[Symbol, untyped]], ?discovered_singleton_def_nodes: Hash[String, Hash[Symbol, untyped]], ?discovered_def_sources: Hash[String, Hash[Symbol, String]], ?discovered_method_visibilities: Hash[String, Hash[Symbol, Symbol]], ?discovered_superclasses: Hash[String, String], ?discovered_includes: Hash[String, Array[String]], ?discovered_class_sources: Hash[String, Set[String]], ?data_member_layouts: Hash[String, Array[Symbol]]) -> DiscoveryIndex
57
+ def with: (?declared_types: Hash[untyped, Type::t], ?class_ivars: Hash[String, Hash[Symbol, Type::t]], ?class_cvars: Hash[String, Hash[Symbol, Type::t]], ?program_globals: Hash[Symbol, Type::t], ?discovered_classes: Hash[String, Type::Singleton], ?in_source_constants: Hash[String, Type::t], ?discovered_methods: Hash[String, Hash[Symbol, Symbol]], ?discovered_def_nodes: Hash[String, Hash[Symbol, untyped]], ?discovered_singleton_def_nodes: Hash[String, Hash[Symbol, untyped]], ?discovered_def_sources: Hash[String, Hash[Symbol, String]], ?discovered_method_visibilities: Hash[String, Hash[Symbol, Symbol]], ?discovered_superclasses: Hash[String, String], ?discovered_includes: Hash[String, Array[String]], ?discovered_class_sources: Hash[String, Set[String]], ?data_member_layouts: Hash[String, Array[Symbol]], ?struct_member_layouts: Hash[String, { members: Array[Symbol], keyword_init: bool }], ?param_inferred_types: Hash[[String, Symbol, Symbol], Hash[Symbol, Type::t]]) -> DiscoveryIndex
53
58
  end
54
59
 
55
60
  class IndexedKey
@@ -68,6 +73,8 @@ module Rigor
68
73
 
69
74
  def initialize: (environment: Environment, locals: Hash[Symbol, Type::t], ?fact_store: Analysis::FactStore, ?self_type: Type::t?, ?ivars: Hash[Symbol, Type::t], ?cvars: Hash[Symbol, Type::t], ?globals: Hash[Symbol, Type::t], ?discovery: DiscoveryIndex, ?source_path: String?) -> void
70
75
  def with_source_path: (String? path) -> Scope
76
+ def with_struct_fold_safe: (Set[Symbol] locals) -> Scope
77
+ def struct_fold_safe?: (String | Symbol name) -> bool
71
78
  def with_discovery: (DiscoveryIndex index) -> Scope
72
79
  def local: (String | Symbol name) -> Type::t?
73
80
  def ivar: (String | Symbol name) -> Type::t?
@@ -94,6 +101,7 @@ module Rigor
94
101
  def discovered_method_visibility: (String | Symbol class_name, String | Symbol method_name) -> Symbol?
95
102
  def superclass_of: (String | Symbol class_name) -> String?
96
103
  def data_member_layout: (String | Symbol class_name) -> Array[Symbol]?
104
+ def struct_member_layout: (String | Symbol class_name) -> { members: Array[Symbol], keyword_init: bool }?
97
105
  def includes_of: (String | Symbol class_name) -> Array[String]
98
106
  def indexed_narrowing: (Symbol receiver_kind, String | Symbol receiver_name, untyped key) -> Type::t?
99
107
  def with_indexed_narrowing: (Symbol receiver_kind, String | Symbol receiver_name, untyped key, Type::t type) -> Scope
data/sig/rigor/type.rbs CHANGED
@@ -1,6 +1,6 @@
1
1
  module Rigor
2
2
  module Type
3
- type t = Top | Bot | Dynamic | Constant | IntegerRange | Nominal | Singleton | Union | Difference | Tuple | HashShape | DataClass | DataInstance
3
+ type t = Top | Bot | Dynamic | Constant | IntegerRange | Nominal | Singleton | Union | Difference | Tuple | HashShape | DataClass | DataInstance | StructClass | StructInstance
4
4
 
5
5
  type accepts_mode = :strict | :gradual | :loose
6
6
 
@@ -277,6 +277,39 @@ module Rigor
277
277
  def inspect: () -> String
278
278
  end
279
279
 
280
+ class StructClass
281
+ attr_reader members: Array[Symbol]
282
+ attr_reader class_name: String?
283
+ attr_reader keyword_init: bool
284
+ def initialize: (Array[Symbol] members, ?String? class_name, ?keyword_init: bool) -> void
285
+ def describe: (?Symbol verbosity) -> String
286
+ def erase_to_rbs: () -> String
287
+ def top: () -> Trinary
288
+ def bot: () -> Trinary
289
+ def dynamic: () -> Trinary
290
+ def accepts: (Type::t other, ?mode: accepts_mode) -> AcceptsResult
291
+ def ==: (untyped other) -> bool
292
+ def hash: () -> Integer
293
+ def inspect: () -> String
294
+ end
295
+
296
+ class StructInstance
297
+ attr_reader members: Hash[Symbol, Type::t]
298
+ attr_reader class_name: String?
299
+ def initialize: (Hash[Symbol, Type::t] members, ?String? class_name) -> void
300
+ def member_names: () -> Array[Symbol]
301
+ def member_type: (Symbol name) -> Type::t?
302
+ def describe: (?Symbol verbosity) -> String
303
+ def erase_to_rbs: () -> String
304
+ def top: () -> Trinary
305
+ def bot: () -> Trinary
306
+ def dynamic: () -> Trinary
307
+ def accepts: (Type::t other, ?mode: accepts_mode) -> AcceptsResult
308
+ def ==: (untyped other) -> bool
309
+ def hash: () -> Integer
310
+ def inspect: () -> String
311
+ end
312
+
280
313
  class AcceptsResult
281
314
  attr_reader trinary: Trinary
282
315
  attr_reader mode: accepts_mode
@@ -339,6 +372,8 @@ module Rigor
339
372
  def self?.hash_shape_of: (?Hash[untyped, Type::t]? pairs, **untyped options) -> HashShape
340
373
  def self?.data_class_of: (members: Array[Symbol], ?class_name: String?) -> DataClass
341
374
  def self?.data_instance_of: (members: Hash[Symbol, Type::t], ?class_name: String?) -> DataInstance
375
+ def self?.struct_class_of: (members: Array[Symbol], ?class_name: String?, ?keyword_init: bool) -> StructClass
376
+ def self?.struct_instance_of: (members: Hash[Symbol, Type::t], ?class_name: String?) -> StructInstance
342
377
  def self?.union: (*Type::t types) -> Type::t
343
378
  def self?.key_of: (Type::t type) -> Type::t
344
379
  def self?.value_of: (Type::t type) -> Type::t
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rigortype
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.19
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rigor contributors
@@ -281,6 +281,29 @@ files:
281
281
  - data/builtins/ruby_core/string.yml
282
282
  - data/builtins/ruby_core/struct.yml
283
283
  - data/builtins/ruby_core/time.yml
284
+ - data/core_overlay/numeric.rbs
285
+ - data/core_overlay/pathname.rbs
286
+ - data/core_overlay/string_scanner.rbs
287
+ - data/gem_overlay/activesupport/core_ext.rbs
288
+ - data/vendored_gem_sigs/ast/ast.rbs
289
+ - data/vendored_gem_sigs/bcrypt/bcrypt.rbs
290
+ - data/vendored_gem_sigs/bundler/bundler.rbs
291
+ - data/vendored_gem_sigs/cgi/cgi_extras.rbs
292
+ - data/vendored_gem_sigs/did_you_mean/did_you_mean_extras.rbs
293
+ - data/vendored_gem_sigs/idn-ruby/idn.rbs
294
+ - data/vendored_gem_sigs/mysql2/client.rbs
295
+ - data/vendored_gem_sigs/mysql2/error.rbs
296
+ - data/vendored_gem_sigs/mysql2/result.rbs
297
+ - data/vendored_gem_sigs/mysql2/statement.rbs
298
+ - data/vendored_gem_sigs/nokogiri/nokogiri.rbs
299
+ - data/vendored_gem_sigs/nokogiri/nokogiri_html5.rbs
300
+ - data/vendored_gem_sigs/pg/pg.rbs
301
+ - data/vendored_gem_sigs/prism/prism_supplement.rbs
302
+ - data/vendored_gem_sigs/redis/errors.rbs
303
+ - data/vendored_gem_sigs/redis/future.rbs
304
+ - data/vendored_gem_sigs/redis/redis.rbs
305
+ - data/vendored_gem_sigs/redis/redis_extras.rbs
306
+ - data/vendored_gem_sigs/rubygems/rubygems_extras.rbs
284
307
  - exe/rigor
285
308
  - lib/rigor.rb
286
309
  - lib/rigor/analysis/baseline.rb
@@ -322,6 +345,7 @@ files:
322
345
  - lib/rigor/bleeding_edge.rb
323
346
  - lib/rigor/builtins/hkt_builtins.rb
324
347
  - lib/rigor/builtins/imported_refinements.rb
348
+ - lib/rigor/builtins/predefined_constant_refinements.rb
325
349
  - lib/rigor/builtins/regex_refinement.rb
326
350
  - lib/rigor/builtins/static_return_refinements.rb
327
351
  - lib/rigor/cache/descriptor.rb
@@ -342,18 +366,26 @@ files:
342
366
  - lib/rigor/cli/ci_detector.rb
343
367
  - lib/rigor/cli/command.rb
344
368
  - lib/rigor/cli/coverage_command.rb
369
+ - lib/rigor/cli/coverage_mutation.rb
345
370
  - lib/rigor/cli/coverage_renderer.rb
346
371
  - lib/rigor/cli/coverage_report.rb
372
+ - lib/rigor/cli/coverage_scan.rb
347
373
  - lib/rigor/cli/diagnostic_formats.rb
348
374
  - lib/rigor/cli/diff_command.rb
349
375
  - lib/rigor/cli/explain_command.rb
376
+ - lib/rigor/cli/fused_protection_renderer.rb
377
+ - lib/rigor/cli/fused_protection_report.rb
350
378
  - lib/rigor/cli/lsp_command.rb
351
379
  - lib/rigor/cli/mcp_command.rb
380
+ - lib/rigor/cli/mutation_protection_renderer.rb
381
+ - lib/rigor/cli/mutation_protection_report.rb
352
382
  - lib/rigor/cli/options.rb
353
383
  - lib/rigor/cli/plugin_command.rb
354
384
  - lib/rigor/cli/plugins_command.rb
355
385
  - lib/rigor/cli/plugins_renderer.rb
356
386
  - lib/rigor/cli/prism_colorizer.rb
387
+ - lib/rigor/cli/protection_renderer.rb
388
+ - lib/rigor/cli/protection_report.rb
357
389
  - lib/rigor/cli/renderable.rb
358
390
  - lib/rigor/cli/show_bleedingedge_command.rb
359
391
  - lib/rigor/cli/sig_gen_command.rb
@@ -367,12 +399,14 @@ files:
367
399
  - lib/rigor/cli/type_scan_command.rb
368
400
  - lib/rigor/cli/type_scan_renderer.rb
369
401
  - lib/rigor/cli/type_scan_report.rb
402
+ - lib/rigor/config_audit.rb
370
403
  - lib/rigor/configuration.rb
371
404
  - lib/rigor/configuration/dependencies.rb
372
405
  - lib/rigor/configuration/severity_profile.rb
373
406
  - lib/rigor/environment.rb
374
407
  - lib/rigor/environment/bundle_sig_discovery.rb
375
408
  - lib/rigor/environment/class_registry.rb
409
+ - lib/rigor/environment/constant_type_cache_holder.rb
376
410
  - lib/rigor/environment/hkt_registry_holder.rb
377
411
  - lib/rigor/environment/lockfile_resolver.rb
378
412
  - lib/rigor/environment/rbs_collection_discovery.rb
@@ -436,6 +470,7 @@ files:
436
470
  - lib/rigor/inference/method_dispatcher/kernel_dispatch.rb
437
471
  - lib/rigor/inference/method_dispatcher/literal_string_folding.rb
438
472
  - lib/rigor/inference/method_dispatcher/math_folding.rb
473
+ - lib/rigor/inference/method_dispatcher/member_shape_projection.rb
439
474
  - lib/rigor/inference/method_dispatcher/method_folding.rb
440
475
  - lib/rigor/inference/method_dispatcher/overload_selector.rb
441
476
  - lib/rigor/inference/method_dispatcher/rbs_dispatch.rb
@@ -446,18 +481,22 @@ files:
446
481
  - lib/rigor/inference/method_dispatcher/shape_dispatch.rb
447
482
  - lib/rigor/inference/method_dispatcher/shellwords_folding.rb
448
483
  - lib/rigor/inference/method_dispatcher/singleton_folding.rb
484
+ - lib/rigor/inference/method_dispatcher/struct_folding.rb
449
485
  - lib/rigor/inference/method_dispatcher/time_folding.rb
450
486
  - lib/rigor/inference/method_dispatcher/uri_folding.rb
451
487
  - lib/rigor/inference/method_parameter_binder.rb
452
488
  - lib/rigor/inference/multi_target_binder.rb
453
489
  - lib/rigor/inference/mutation_widening.rb
454
490
  - lib/rigor/inference/narrowing.rb
491
+ - lib/rigor/inference/parameter_inference_collector.rb
455
492
  - lib/rigor/inference/precision_scanner.rb
456
493
  - lib/rigor/inference/project_patched_methods.rb
457
494
  - lib/rigor/inference/project_patched_scanner.rb
495
+ - lib/rigor/inference/protection_scanner.rb
458
496
  - lib/rigor/inference/rbs_type_translator.rb
459
497
  - lib/rigor/inference/scope_indexer.rb
460
498
  - lib/rigor/inference/statement_evaluator.rb
499
+ - lib/rigor/inference/struct_fold_safety.rb
461
500
  - lib/rigor/inference/synthetic_method.rb
462
501
  - lib/rigor/inference/synthetic_method_index.rb
463
502
  - lib/rigor/inference/synthetic_method_scanner.rb
@@ -507,6 +546,10 @@ files:
507
546
  - lib/rigor/plugin/source_rbs_synthesis_reporter.rb
508
547
  - lib/rigor/plugin/trust_policy.rb
509
548
  - lib/rigor/plugin/type_node_resolver.rb
549
+ - lib/rigor/protection/diagnostic_oracle.rb
550
+ - lib/rigor/protection/mutation_scanner.rb
551
+ - lib/rigor/protection/mutator.rb
552
+ - lib/rigor/protection/test_suite_oracle.rb
510
553
  - lib/rigor/rbs_extended.rb
511
554
  - lib/rigor/rbs_extended/conformance_checker.rb
512
555
  - lib/rigor/rbs_extended/hkt_directives.rb
@@ -526,7 +569,9 @@ files:
526
569
  - lib/rigor/sig_gen/type_elaborator.rb
527
570
  - lib/rigor/sig_gen/write_result.rb
528
571
  - lib/rigor/sig_gen/writer.rb
572
+ - lib/rigor/signature_path_audit.rb
529
573
  - lib/rigor/source.rb
574
+ - lib/rigor/source/constant_path.rb
530
575
  - lib/rigor/source/literals.rb
531
576
  - lib/rigor/source/node_locator.rb
532
577
  - lib/rigor/source/node_walker.rb
@@ -551,8 +596,11 @@ files:
551
596
  - lib/rigor/type/integer_range.rb
552
597
  - lib/rigor/type/intersection.rb
553
598
  - lib/rigor/type/nominal.rb
599
+ - lib/rigor/type/plain_lattice.rb
554
600
  - lib/rigor/type/refined.rb
555
601
  - lib/rigor/type/singleton.rb
602
+ - lib/rigor/type/struct_class.rb
603
+ - lib/rigor/type/struct_instance.rb
556
604
  - lib/rigor/type/top.rb
557
605
  - lib/rigor/type/tuple.rb
558
606
  - lib/rigor/type/union.rb