Module: Rigor::Inference::Destructure

Defined in:
lib/rigor/inference/method_parameter_binder.rb

Overview

Builds the entry scope of a method body by translating the method’s parameter list into a ‘name -> Rigor::Type` map.

Parameter types come from the surrounding class’s RBS signature when one is available; otherwise every parameter defaults to ‘Dynamic`. The default is the Slice 1 fail-soft answer for unknown values, so a method whose RBS signature is missing or whose parameters cannot be matched still binds every name into the scope (a method body whose `Local x` reads return `Dynamic` instead of falling through to the unbound-local `Dynamic` event is the same observable type, but the binding presence is what later slices need to attach narrowing facts to).

The class context (‘class_path:`) and `singleton:` flag are supplied by the caller (the StatementEvaluator) which threads them as the lexical class scope. The binder makes no assumption about how that context was computed; it only uses it to build the `(class_name, method_name)` lookup key for `Rigor::Environment::RbsLoader#instance_method` / `#singleton_method`.

See docs/internal-spec/inference-engine.md for the binding contract. Leaf-name extraction for a destructured positional parameter (‘Prism::MultiTargetNode`). Stateless; lifted out of MethodParameterBinder so the binder’s class length stays in budget.

Class Method Summary collapse

Class Method Details

.names_for_entry(entry) ⇒ Object



52
53
54
55
56
57
58
59
60
61
# File 'lib/rigor/inference/method_parameter_binder.rb', line 52

def names_for_entry(entry)
  # A splat sub-target (`*rest` inside the destructure) wraps its
  # real target in a `SplatNode#expression`; unwrap it.
  entry = entry.expression if entry.is_a?(Prism::SplatNode) && entry.expression
  return [] if entry.nil?
  return target_names(entry) if entry.is_a?(Prism::MultiTargetNode)
  return [entry.name] if entry.respond_to?(:name) && entry.name

  []
end

.target_names(multi_target) ⇒ Object

Collect every leaf local name a ‘MultiTargetNode` binds, recursing through nested destructures (`((a, b), c)`) and the splat slot (`(a, *rest)`). Targets without a `#name` (an index/call write target, vanishingly rare in a parameter position) are skipped — there is no local to bind.



47
48
49
50
# File 'lib/rigor/inference/method_parameter_binder.rb', line 47

def target_names(multi_target)
  entries = multi_target.lefts + [multi_target.rest, *multi_target.rights].compact
  entries.flat_map { |entry| names_for_entry(entry) }
end