rigortype 0.1.3 → 0.1.4

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 (116) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +125 -31
  3. data/lib/rigor/analysis/check_rules.rb +10 -18
  4. data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +75 -0
  5. data/lib/rigor/analysis/dependency_source_inference/builder.rb +47 -21
  6. data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +1 -1
  7. data/lib/rigor/analysis/dependency_source_inference/index.rb +32 -3
  8. data/lib/rigor/analysis/dependency_source_inference/walker.rb +1 -1
  9. data/lib/rigor/analysis/dependency_source_inference.rb +1 -0
  10. data/lib/rigor/analysis/diagnostic.rb +0 -2
  11. data/lib/rigor/analysis/fact_store.rb +11 -3
  12. data/lib/rigor/analysis/rule_catalog.rb +2 -2
  13. data/lib/rigor/analysis/runner.rb +114 -3
  14. data/lib/rigor/builtins/imported_refinements.rb +360 -55
  15. data/lib/rigor/cache/descriptor.rb +1 -1
  16. data/lib/rigor/cache/store.rb +1 -1
  17. data/lib/rigor/cli/diff_command.rb +1 -1
  18. data/lib/rigor/cli/sig_gen_command.rb +173 -0
  19. data/lib/rigor/cli/type_of_command.rb +1 -1
  20. data/lib/rigor/cli/type_scan_renderer.rb +1 -1
  21. data/lib/rigor/cli/type_scan_report.rb +2 -2
  22. data/lib/rigor/cli.rb +9 -1
  23. data/lib/rigor/configuration/dependencies.rb +2 -2
  24. data/lib/rigor/configuration.rb +2 -2
  25. data/lib/rigor/environment.rb +35 -4
  26. data/lib/rigor/flow_contribution/conflict.rb +2 -2
  27. data/lib/rigor/flow_contribution/element.rb +1 -1
  28. data/lib/rigor/flow_contribution/fact.rb +1 -1
  29. data/lib/rigor/flow_contribution/merge_result.rb +1 -1
  30. data/lib/rigor/flow_contribution/merger.rb +3 -3
  31. data/lib/rigor/flow_contribution.rb +2 -2
  32. data/lib/rigor/inference/block_parameter_binder.rb +0 -2
  33. data/lib/rigor/inference/coverage_scanner.rb +1 -1
  34. data/lib/rigor/inference/expression_typer.rb +67 -11
  35. data/lib/rigor/inference/fallback.rb +1 -1
  36. data/lib/rigor/inference/method_dispatcher/block_folding.rb +3 -5
  37. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +0 -12
  38. data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +1 -3
  39. data/lib/rigor/inference/method_dispatcher/literal_string_folding.rb +1 -1
  40. data/lib/rigor/inference/method_dispatcher/method_folding.rb +118 -0
  41. data/lib/rigor/inference/method_dispatcher/overload_selector.rb +6 -11
  42. data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +27 -11
  43. data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +0 -4
  44. data/lib/rigor/inference/method_dispatcher.rb +146 -2
  45. data/lib/rigor/inference/method_parameter_binder.rb +1 -3
  46. data/lib/rigor/inference/narrowing.rb +2 -4
  47. data/lib/rigor/inference/rbs_type_translator.rb +0 -2
  48. data/lib/rigor/inference/scope_indexer.rb +14 -9
  49. data/lib/rigor/inference/statement_evaluator.rb +7 -7
  50. data/lib/rigor/plugin/io_boundary.rb +0 -2
  51. data/lib/rigor/plugin/loader.rb +2 -2
  52. data/lib/rigor/plugin/manifest.rb +30 -9
  53. data/lib/rigor/plugin/registry.rb +11 -0
  54. data/lib/rigor/plugin/services.rb +1 -1
  55. data/lib/rigor/plugin/type_node_resolver.rb +52 -0
  56. data/lib/rigor/plugin.rb +1 -0
  57. data/lib/rigor/rbs_extended/reporter.rb +91 -0
  58. data/lib/rigor/rbs_extended.rb +131 -32
  59. data/lib/rigor/scope.rb +25 -8
  60. data/lib/rigor/sig_gen/classification.rb +36 -0
  61. data/lib/rigor/sig_gen/generator.rb +1048 -0
  62. data/lib/rigor/sig_gen/layout_index.rb +108 -0
  63. data/lib/rigor/sig_gen/method_candidate.rb +62 -0
  64. data/lib/rigor/sig_gen/observation_collector.rb +391 -0
  65. data/lib/rigor/sig_gen/observed_call.rb +62 -0
  66. data/lib/rigor/sig_gen/path_mapper.rb +116 -0
  67. data/lib/rigor/sig_gen/renderer.rb +157 -0
  68. data/lib/rigor/sig_gen/type_elaborator.rb +92 -0
  69. data/lib/rigor/sig_gen/write_result.rb +48 -0
  70. data/lib/rigor/sig_gen/writer.rb +530 -0
  71. data/lib/rigor/sig_gen.rb +25 -0
  72. data/lib/rigor/type/bound_method.rb +79 -0
  73. data/lib/rigor/type/combinator.rb +195 -2
  74. data/lib/rigor/type/constant.rb +13 -0
  75. data/lib/rigor/type/hash_shape.rb +0 -2
  76. data/lib/rigor/type/union.rb +20 -1
  77. data/lib/rigor/type.rb +1 -0
  78. data/lib/rigor/type_node/generic.rb +62 -0
  79. data/lib/rigor/type_node/identifier.rb +30 -0
  80. data/lib/rigor/type_node/indexed_access.rb +41 -0
  81. data/lib/rigor/type_node/integer_literal.rb +29 -0
  82. data/lib/rigor/type_node/name_scope.rb +52 -0
  83. data/lib/rigor/type_node/resolver_chain.rb +56 -0
  84. data/lib/rigor/type_node/string_literal.rb +29 -0
  85. data/lib/rigor/type_node/symbol_literal.rb +28 -0
  86. data/lib/rigor/type_node/union.rb +42 -0
  87. data/lib/rigor/type_node.rb +29 -0
  88. data/lib/rigor/version.rb +1 -1
  89. data/lib/rigor.rb +2 -0
  90. data/sig/rigor/analysis/check_rules/always_truthy_condition_collector.rbs +10 -0
  91. data/sig/rigor/analysis/check_rules/dead_assignment_collector.rbs +10 -0
  92. data/sig/rigor/analysis/dependency_source_inference/gem_resolver.rbs +25 -0
  93. data/sig/rigor/analysis/dependency_source_inference/index.rbs +9 -0
  94. data/sig/rigor/cli/diff_command.rbs +4 -0
  95. data/sig/rigor/cli/explain_command.rbs +4 -0
  96. data/sig/rigor/cli/sig_gen_command.rbs +4 -0
  97. data/sig/rigor/cli/type_scan_command.rbs +3 -0
  98. data/sig/rigor/environment.rbs +5 -2
  99. data/sig/rigor/inference/builtins/method_catalog.rbs +4 -0
  100. data/sig/rigor/inference/builtins/numeric_catalog.rbs +3 -0
  101. data/sig/rigor/inference/builtins.rbs +2 -0
  102. data/sig/rigor/plugin/access_denied_error.rbs +3 -0
  103. data/sig/rigor/plugin/base.rbs +6 -0
  104. data/sig/rigor/plugin/fact_store.rbs +11 -0
  105. data/sig/rigor/plugin/io_boundary.rbs +4 -0
  106. data/sig/rigor/plugin/load_error.rbs +6 -0
  107. data/sig/rigor/plugin/loader.rbs +20 -0
  108. data/sig/rigor/plugin/manifest.rbs +9 -0
  109. data/sig/rigor/plugin/registry.rbs +3 -0
  110. data/sig/rigor/plugin/services.rbs +3 -0
  111. data/sig/rigor/plugin/trust_policy.rbs +4 -0
  112. data/sig/rigor/plugin/type_node_resolver.rbs +3 -0
  113. data/sig/rigor/plugin.rbs +8 -0
  114. data/sig/rigor/scope.rbs +4 -2
  115. data/sig/rigor/type.rbs +28 -6
  116. metadata +52 -1
@@ -37,7 +37,7 @@ module Rigor
37
37
  # tuple — element-wise block re-evaluation against
38
38
  # `Constant<Array>` receivers (the `map` / `filter_map` /
39
39
  # `flat_map` precision tier) is reserved for a later slice.
40
- module BlockFolding # rubocop:disable Metrics/ModuleLength
40
+ module BlockFolding
41
41
  module_function
42
42
 
43
43
  FILTER_KEEP_ON_TRUTHY = Set[:select, :filter, :take_while].freeze
@@ -69,7 +69,6 @@ module Rigor
69
69
  # the call's block. `nil` means "no block at the call site"
70
70
  # and disqualifies every rule here.
71
71
  # @return [Rigor::Type, nil]
72
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
73
72
  def try_fold(receiver:, method_name:, args:, block_type:)
74
73
  return nil if receiver.nil? || block_type.nil?
75
74
 
@@ -86,7 +85,6 @@ module Rigor
86
85
  fold_count(receiver, truthiness, args)
87
86
  end
88
87
  end
89
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
90
88
 
91
89
  def filter_method?(method_name)
92
90
  FILTER_KEEP_ON_TRUTHY.include?(method_name) ||
@@ -154,7 +152,7 @@ module Rigor
154
152
  end
155
153
 
156
154
  # @return [:always_true, :always_false, :bool, nil]
157
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
155
+ # rubocop:disable Metrics/CyclomaticComplexity
158
156
  def predicate_decision(method_name, truthiness, emptiness)
159
157
  case method_name
160
158
  when :all?
@@ -177,7 +175,7 @@ module Rigor
177
175
  :bool
178
176
  end
179
177
  end
180
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
178
+ # rubocop:enable Metrics/CyclomaticComplexity
181
179
 
182
180
  def bool_union
183
181
  Type::Combinator.union(
@@ -149,7 +149,6 @@ module Rigor
149
149
  # and runs the format. Symbol keys are kept as
150
150
  # Symbols (matching Ruby's `%{key}` resolution).
151
151
  # Anything else declines so the RBS tier widens.
152
- # rubocop:disable Metrics/CyclomaticComplexity
153
152
  def try_fold_string_format(receiver, method_name, args)
154
153
  return nil unless method_name == :%
155
154
  return nil unless args.size == 1
@@ -166,7 +165,6 @@ module Rigor
166
165
  rescue StandardError
167
166
  nil
168
167
  end
169
- # rubocop:enable Metrics/CyclomaticComplexity
170
168
 
171
169
  def format_argument_value(arg)
172
170
  case arg
@@ -275,7 +273,6 @@ module Rigor
275
273
  [result]
276
274
  end
277
275
 
278
- # rubocop:disable Metrics/CyclomaticComplexity
279
276
  def try_fold_unary_set(receiver_values, method_name)
280
277
  range_lift = try_fold_range_constant_unary(receiver_values, method_name)
281
278
  return range_lift if range_lift
@@ -299,8 +296,6 @@ module Rigor
299
296
  end
300
297
  build_constant_type(results, source: receiver_values)
301
298
  end
302
- # rubocop:enable Metrics/CyclomaticComplexity
303
-
304
299
  # v0.0.7 — `Constant<Range>#to_a` and the no-arg
305
300
  # `first` / `last` / `min` / `max` short-circuit through a
306
301
  # Range-specific arm that catalog dispatch cannot reach:
@@ -353,7 +348,6 @@ module Rigor
353
348
  Type::Combinator.constant_of(edge == :first ? values.first : values.last)
354
349
  end
355
350
 
356
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
357
351
  def try_fold_binary_set(receiver_values, method_name, arg_values)
358
352
  string_lift = try_fold_string_array_binary(receiver_values, method_name, arg_values)
359
353
  return string_lift if string_lift
@@ -369,8 +363,6 @@ module Rigor
369
363
  end
370
364
  build_constant_type(results, source: receiver_values + arg_values)
371
365
  end
372
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
373
-
374
366
  # v0.0.7 — `Constant<String>#chars` / `bytes` / `lines` /
375
367
  # `split` (no-arg) return a Ruby Array of foldable
376
368
  # scalars; `foldable_constant_value?` rejects Array
@@ -425,7 +417,6 @@ module Rigor
425
417
  nil
426
418
  end
427
419
 
428
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
429
420
  def try_fold_pathname_binary(receiver_values, method_name, arg_values)
430
421
  return nil unless PATHNAME_PURE_BINARY.include?(method_name)
431
422
  return nil unless receiver_values.size == 1 && arg_values.size == 1
@@ -442,7 +433,6 @@ module Rigor
442
433
  rescue StandardError
443
434
  nil
444
435
  end
445
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
446
436
 
447
437
  def try_fold_string_array_unary(receiver_values, method_name)
448
438
  return nil unless STRING_ARRAY_UNARY_METHODS.include?(method_name)
@@ -459,7 +449,6 @@ module Rigor
459
449
  # `Constant<String>#split(arg)` / `#scan(arg)` — lift the
460
450
  # Array result to a Tuple when both sides are statically
461
451
  # known and the cardinality fits.
462
- # rubocop:disable Metrics/CyclomaticComplexity
463
452
  def try_fold_string_array_binary(receiver_values, method_name, arg_values)
464
453
  return nil unless STRING_ARRAY_BINARY_METHODS.include?(method_name)
465
454
  return nil unless receiver_values.size == 1 && arg_values.size == 1
@@ -473,7 +462,6 @@ module Rigor
473
462
  rescue StandardError
474
463
  nil
475
464
  end
476
- # rubocop:enable Metrics/CyclomaticComplexity
477
465
 
478
466
  def lift_array_result(result)
479
467
  return nil unless result.is_a?(Array)
@@ -27,12 +27,11 @@ module Rigor
27
27
  # - `a.downto(b) { |i| … }` yields the same domain `[b, a]`,
28
28
  # just iterated in reverse. Lower bound from the
29
29
  # argument, upper bound from the receiver.
30
- module IteratorDispatch # rubocop:disable Metrics/ModuleLength
30
+ module IteratorDispatch
31
31
  module_function
32
32
 
33
33
  # @return [Array<Rigor::Type>, nil] block-param types, or
34
34
  # nil to fall through to the next tier.
35
- # rubocop:disable Metrics/CyclomaticComplexity
36
35
  def block_param_types(receiver:, method_name:, args:)
37
36
  case method_name
38
37
  when :times then times_block_params(receiver)
@@ -45,7 +44,6 @@ module Rigor
45
44
  when :each_slice, :each_cons then slice_block_params(receiver)
46
45
  end
47
46
  end
48
- # rubocop:enable Metrics/CyclomaticComplexity
49
47
 
50
48
  def times_block_params(receiver)
51
49
  return nil unless integer_rooted?(receiver)
@@ -74,7 +74,7 @@ module Rigor
74
74
  private_constant :CONCAT_METHODS, :FORMAT_METHODS,
75
75
  :LITERAL_PRESERVING_METHODS, :WIDTH_PADDING_METHODS
76
76
 
77
- def try_dispatch(receiver:, method_name:, args:, **) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
77
+ def try_dispatch(receiver:, method_name:, args:, **)
78
78
  return fold_array_join(receiver, args) if method_name == :join
79
79
  return fold_format(args) if FORMAT_METHODS.include?(method_name)
80
80
 
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../type"
4
+
5
+ module Rigor
6
+ module Inference
7
+ module MethodDispatcher
8
+ # `Method` (and friends) precision tier.
9
+ #
10
+ # Two folds make a `Method` carrier round-trip with its
11
+ # binding visible:
12
+ #
13
+ # 1. **Forward** — `<receiver>.method(:sym)` (or
14
+ # `.method("sym")`) lifts to {Type::BoundMethod}
15
+ # carrying the receiver type AND the resolved Symbol.
16
+ # Calling with a non-literal symbol-shaped argument
17
+ # declines so the RBS tier still answers
18
+ # `Nominal[Method]`.
19
+ # 2. **Backward** — `Type::BoundMethod#call(...)` /
20
+ # `#()` (Prism lowers `.()` into a CallNode whose
21
+ # `name` is `:call`) / `#[](...)` substitutes the
22
+ # bound `(receiver_type, method_name)` and recurses
23
+ # back into `MethodDispatcher.dispatch`. The
24
+ # re-entrant call lets the substituted dispatch
25
+ # consume every tier the original call site would
26
+ # have — constant folding, shape dispatch, RBS,
27
+ # plugin contributions, etc. The original block_type
28
+ # / environment / call_node / scope are threaded
29
+ # through unchanged so capture-sensitive tiers (the
30
+ # block fold) keep working.
31
+ #
32
+ # Lives ABOVE the standard precision-tier chain so the
33
+ # RBS tier never sees a `BoundMethod` receiver — `Method`
34
+ # erasure means RBS would otherwise return
35
+ # `Method#call: (*untyped) -> untyped`, which is exactly
36
+ # the precision loss the carrier exists to avoid.
37
+ module MethodFolding
38
+ module_function
39
+
40
+ # Forward fold. Returns a {Type::BoundMethod} when the
41
+ # call shape is `<receiver>.method(:name)` /
42
+ # `.method("name")` with a precisely-known Symbol /
43
+ # String argument. Declines on every other shape so
44
+ # the RBS tier still answers `Method` for non-folding
45
+ # cases.
46
+ #
47
+ # @param receiver [Rigor::Type] caller's receiver
48
+ # @param method_name [Symbol] the method being
49
+ # dispatched on `receiver` — only `:method` triggers
50
+ # the fold.
51
+ # @param args [Array<Rigor::Type>] caller's argument
52
+ # types in order. Only the single-argument case
53
+ # matches; other arities decline.
54
+ def try_forward(receiver:, method_name:, args:)
55
+ return nil unless method_name == :method
56
+ return nil if args.size != 1
57
+
58
+ bound_name = symbol_name_of(args.first)
59
+ return nil if bound_name.nil?
60
+
61
+ Type::Combinator.bound_method_of(receiver, bound_name)
62
+ end
63
+
64
+ # Backward fold. Recurses into `MethodDispatcher.dispatch`
65
+ # with the bound `(receiver_type, method_name)`. The
66
+ # `block_type` / `environment` / `call_node` / `scope`
67
+ # are forwarded so every downstream tier (constant
68
+ # folding, shape dispatch, plugin contributions, …)
69
+ # keeps the original call site's context. Returns
70
+ # `Dynamic[top]` rather than `nil` when the recursive
71
+ # dispatch declines so the call site still ends in a
72
+ # well-defined type (the gradual-safety net mirrors
73
+ # the engine's "BoundMethod erases to `Method`,
74
+ # `Method#call: (*untyped) -> untyped`" RBS fallback).
75
+ def try_backward(receiver:, method_name:, args:, block_type:, environment:, call_node:, scope:)
76
+ return nil unless receiver.is_a?(Type::BoundMethod)
77
+ return nil unless backward_method?(method_name)
78
+
79
+ MethodDispatcher.dispatch(
80
+ receiver_type: receiver.receiver_type,
81
+ method_name: receiver.method_name,
82
+ arg_types: args,
83
+ block_type: block_type,
84
+ environment: environment,
85
+ call_node: call_node,
86
+ scope: scope
87
+ ) || Type::Combinator.untyped
88
+ end
89
+ # `Method#call` / `Method#()` and `Method#[]` are the
90
+ # invocation entry points on the `Method` API; the
91
+ # alias `===` is also `call` semantically but is more
92
+ # commonly used as a case-equality predicate, so we
93
+ # do NOT fold through it (the case/when narrowing path
94
+ # already special-cases `===` for branch typing).
95
+ BACKWARD_METHOD_NAMES = %i[call []].freeze
96
+ private_constant :BACKWARD_METHOD_NAMES
97
+
98
+ def backward_method?(method_name)
99
+ BACKWARD_METHOD_NAMES.include?(method_name)
100
+ end
101
+
102
+ # `Object#method` accepts both Symbol and String at
103
+ # runtime (the latter coerced via `to_sym`). The
104
+ # `Constant<String>` form is rare in production code
105
+ # but cheap to support and matches Ruby's documented
106
+ # contract.
107
+ def symbol_name_of(arg)
108
+ return nil unless arg.is_a?(Type::Constant)
109
+
110
+ case arg.value
111
+ when Symbol then arg.value
112
+ when String then arg.value.to_sym
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -41,7 +41,7 @@ module Rigor
41
41
  # (instance vs singleton). Both kinds share the same arity and
42
42
  # acceptance shape; the difference is only in which `Definition`
43
43
  # the caller fetched.
44
- module OverloadSelector # rubocop:disable Metrics/ModuleLength
44
+ module OverloadSelector
45
45
  module_function
46
46
 
47
47
  # @param method_definition [RBS::Definition::Method]
@@ -64,8 +64,8 @@ module Rigor
64
64
  # back to the first declaration.
65
65
  # @return [RBS::MethodType, nil] the chosen overload, or nil
66
66
  # when the definition has no method types at all.
67
- # rubocop:disable Metrics/ParameterLists
68
- def select(method_definition, arg_types:, self_type:, instance_type:, type_vars: {}, block_required: false)
67
+ def select(method_definition, arg_types:, self_type:, instance_type:, type_vars: {}, block_required: false,
68
+ environment: nil)
69
69
  overloads = method_definition.method_types
70
70
  return nil if overloads.empty?
71
71
 
@@ -75,7 +75,7 @@ module Rigor
75
75
  # `accepts_param?` so overload selection sees the
76
76
  # tighter type when filtering candidates by argument
77
77
  # compatibility.
78
- param_overrides = RbsExtended.param_type_override_map(method_definition)
78
+ param_overrides = RbsExtended.param_type_override_map(method_definition, environment: environment)
79
79
 
80
80
  # Pass 1: prefer overloads whose param types stay strict —
81
81
  # no translator-induced `Dynamic[Top]` from Alias /
@@ -113,7 +113,6 @@ module Rigor
113
113
 
114
114
  overloads.first
115
115
  end
116
- # rubocop:enable Metrics/ParameterLists
117
116
 
118
117
  def overload_has_block?(method_type)
119
118
  method_type.respond_to?(:block) && method_type.block
@@ -122,7 +121,7 @@ module Rigor
122
121
  class << self
123
122
  private
124
123
 
125
- # rubocop:disable Metrics/ParameterLists, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
124
+ # rubocop:disable Metrics/ParameterLists
126
125
  def find_matching_overload(overloads, arg_types:, self_type:, instance_type:, type_vars:, block_required:,
127
126
  param_overrides:, strict:)
128
127
  return nil if strict && arg_types.any? { |t| untyped_arg?(t) }
@@ -141,7 +140,7 @@ module Rigor
141
140
  )
142
141
  end
143
142
  end
144
- # rubocop:enable Metrics/ParameterLists, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
143
+ # rubocop:enable Metrics/ParameterLists
145
144
 
146
145
  # Treats the literal `untyped` carrier (`Dynamic[Top]`)
147
146
  # as too imprecise to drive a strict-pass match. Other
@@ -194,7 +193,6 @@ module Rigor
194
193
  end
195
194
  end
196
195
 
197
- # rubocop:disable Metrics/ParameterLists
198
196
  def matches?(method_type, arg_types, self_type:, instance_type:, type_vars:, param_overrides:)
199
197
  return false if method_type.respond_to?(:type_params) && rejects_keyword_required?(method_type)
200
198
 
@@ -213,7 +211,6 @@ module Rigor
213
211
  )
214
212
  end
215
213
  end
216
- # rubocop:enable Metrics/ParameterLists
217
214
 
218
215
  # Slice 4 phase 2c does not pass keyword arguments through the
219
216
  # call site (caller passes only positional `arg_types`). An
@@ -258,7 +255,6 @@ module Rigor
258
255
  head
259
256
  end
260
257
 
261
- # rubocop:disable Metrics/ParameterLists
262
258
  def accepts_param?(param, arg, self_type:, instance_type:, type_vars:, param_overrides:)
263
259
  param_type = param_overrides[param.name] || RbsTypeTranslator.translate(
264
260
  param.type,
@@ -269,7 +265,6 @@ module Rigor
269
265
  result = param_type.accepts(arg, mode: :gradual)
270
266
  result.yes? || result.maybe?
271
267
  end
272
- # rubocop:enable Metrics/ParameterLists
273
268
  end
274
269
  end
275
270
  end
@@ -162,7 +162,8 @@ module Rigor
162
162
  kind: kind,
163
163
  args: args,
164
164
  type_vars: type_vars,
165
- block_type: block_type
165
+ block_type: block_type,
166
+ environment: environment
166
167
  )
167
168
  rescue StandardError
168
169
  # Defensive: if RBS' definition builder raises on a broken
@@ -194,6 +195,18 @@ module Rigor
194
195
  ["Array", :instance, tuple_type_args(receiver)]
195
196
  when Type::HashShape
196
197
  ["Hash", :instance, hash_shape_type_args(receiver)]
198
+ when Type::BoundMethod
199
+ # `BoundMethod` is a precision-bearing alias for
200
+ # `Nominal[Method]`: it carries the
201
+ # `(receiver, method_name)` binding that
202
+ # `MethodFolding.try_backward` consumes at
203
+ # `.call` / `.()` / `[]`, but every other call
204
+ # site (`.owner` / `.name` / `.arity` / …) must
205
+ # still resolve through Method's RBS contract.
206
+ # Routing here keeps reflective Method methods
207
+ # working without forcing the carrier to
208
+ # collapse to a plain Nominal at construction.
209
+ ["Method", :instance, []]
197
210
  when Type::Dynamic
198
211
  receiver_descriptor(receiver.static_facet)
199
212
  end
@@ -241,15 +254,15 @@ module Rigor
241
254
  param_names.zip(receiver_args).to_h
242
255
  end
243
256
 
244
- # rubocop:disable Metrics/ParameterLists
245
- def translate_return_type(method_definition, class_name:, kind:, args:, type_vars:, block_type:)
257
+ def translate_return_type(method_definition, class_name:, kind:, args:, type_vars:, block_type:,
258
+ environment: nil)
246
259
  # Slice 4b-3 (ADR-7 § "Slice 4-A/4-B") — read the
247
260
  # return-type override through the merger so future
248
261
  # plugin / `:rbs_extended` bundles that also assert a
249
262
  # `return_type` slot at this call site compose with
250
263
  # the RBS::Extended directive instead of silently
251
264
  # racing it.
252
- override = merged_return_type(method_definition)
265
+ override = merged_return_type(method_definition, environment: environment)
253
266
  return override if override
254
267
 
255
268
  instance_type = Type::Combinator.nominal_of(class_name)
@@ -265,7 +278,8 @@ module Rigor
265
278
  self_type: self_type,
266
279
  instance_type: instance_type,
267
280
  type_vars: type_vars,
268
- block_required: !block_type.nil?
281
+ block_required: !block_type.nil?,
282
+ environment: environment
269
283
  )
270
284
  return nil unless method_type
271
285
 
@@ -278,7 +292,6 @@ module Rigor
278
292
  type_vars: full_type_vars
279
293
  )
280
294
  end
281
- # rubocop:enable Metrics/ParameterLists
282
295
 
283
296
  # ADR-7 § "Slice 4-A/4-B" — folds the
284
297
  # `RBS::Extended` `return:` directive (and any
@@ -287,8 +300,8 @@ module Rigor
287
300
  # before consuming. Returns the merged return type
288
301
  # or nil when no contribution overrides the
289
302
  # RBS-declared return.
290
- def merged_return_type(method_definition)
291
- contribution = RbsExtended.read_flow_contribution(method_definition)
303
+ def merged_return_type(method_definition, environment: nil)
304
+ contribution = RbsExtended.read_flow_contribution(method_definition, environment: environment)
292
305
  return nil if contribution.nil?
293
306
 
294
307
  Rigor::FlowContribution::Merger.merge([contribution]).return_type
@@ -377,13 +390,15 @@ module Rigor
377
390
  class_name: class_name,
378
391
  kind: kind,
379
392
  args: args,
380
- type_vars: type_vars
393
+ type_vars: type_vars,
394
+ environment: environment
381
395
  )
382
396
  rescue StandardError
383
397
  []
384
398
  end
385
399
 
386
- def extract_block_param_types(method_definition, class_name:, kind:, args:, type_vars:)
400
+ def extract_block_param_types(method_definition, class_name:, kind:, args:, type_vars:,
401
+ environment: nil)
387
402
  instance_type = Type::Combinator.nominal_of(class_name)
388
403
  self_type =
389
404
  case kind
@@ -397,7 +412,8 @@ module Rigor
397
412
  self_type: self_type,
398
413
  instance_type: instance_type,
399
414
  type_vars: type_vars,
400
- block_required: true
415
+ block_required: true,
416
+ environment: environment
401
417
  )
402
418
  return [] unless method_type
403
419
 
@@ -626,7 +626,6 @@ module Rigor
626
626
  # (so it can serve as a Hash key). Produces a closed
627
627
  # `HashShape` whose entries mirror the per-position
628
628
  # pairs. Empty Tuples fold to the empty HashShape.
629
- # rubocop:disable Metrics/CyclomaticComplexity
630
629
  def tuple_to_h(tuple, _method_name, args)
631
630
  return nil unless args.empty?
632
631
  return Type::Combinator.hash_shape_of({}) if tuple.elements.empty?
@@ -637,7 +636,6 @@ module Rigor
637
636
 
638
637
  Type::Combinator.hash_shape_of(pairs.to_h)
639
638
  end
640
- # rubocop:enable Metrics/CyclomaticComplexity
641
639
 
642
640
  def tuple_to_h_pair(element)
643
641
  return nil unless element.is_a?(Type::Tuple)
@@ -865,7 +863,6 @@ module Rigor
865
863
  # `HashShape` accepts as keys). Duplicate values would
866
864
  # alias under inversion, so Rigor declines on
867
865
  # collisions rather than silently dropping entries.
868
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
869
866
  def hash_invert(shape, _method_name, args)
870
867
  return nil unless args.empty?
871
868
  return nil unless shape.closed?
@@ -880,7 +877,6 @@ module Rigor
880
877
  end
881
878
  Type::Combinator.hash_shape_of(inverted)
882
879
  end
883
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
884
880
 
885
881
  # `shape.first` — returns the first `[k, v]` pair as a
886
882
  # 2-Tuple, or `Constant[nil]` when the shape is empty.