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[Top]. 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[Top] instead of falling through to the unbound-local Dynamic[Top] 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



45
46
47
48
49
50
51
52
53
54
# File 'lib/rigor/inference/method_parameter_binder.rb', line 45

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.



40
41
42
43
# File 'lib/rigor/inference/method_parameter_binder.rb', line 40

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