Module: Rigor::Inference::MultiTargetBinder

Defined in:
lib/rigor/inference/multi_target_binder.rb,
sig/rigor/inference.rbs

Overview

Slice 5 phase 2 sub-phase 2 destructuring binder.

Rigor::Inference::MultiTargetBinder decomposes a tuple-shaped right-hand side type against a Prism multi-target tree and produces a name -> Rigor::Type binding map. The binder is shared between two surfaces:

  1. Rigor::Inference::StatementEvaluator#eval_multi_write for the statement-level a, b = rhs form (Prism::MultiWriteNode).
  2. Rigor::Inference::BlockParameterBinder for nested destructuring inside block parameter lists (Prism::MultiTargetNode under BlockParametersNode#requireds).

Both Prism nodes share the same lefts / rest (a Prism::SplatNode) / rights triple, so the binder treats them uniformly. The binder is pure: it MUST NOT mutate its inputs and MUST return a fresh Hash on every call.

The binder threads Type::Tuple decompositions when the right-hand side carrier is a known-arity tuple. Other carriers (Nominal[Array], Dynamic[Top], Top, Bot, ...) collapse to Dynamic[Top] per slot — Slice 5 phase 2 sub-phase 2 stays conservative on dynamic-arity right-hand sides until the narrower receiver-shape lattice lands.

Targets the binder recognises:

  • Prism::LocalVariableTargetNode — used by the statement-level a, b = rhs form. Binds target.name to its slice of the right-hand side.
  • Prism::RequiredParameterNode — used by block-parameter destructuring (|(a, b), c|). Prism encodes the inner names of a block-side MultiTargetNode as parameter nodes rather than target nodes; the binder treats them uniformly with their LocalVariableTargetNode cousins because they carry the same name: field and the same observable semantics (binding a fresh local in the block-entry scope).
  • Prism::MultiTargetNode — recurses with the slot's type as the new right-hand side.
  • Prism::SplatNode (used for rest) — its expression MUST be a Prism::LocalVariableTargetNode or a Prism::RequiredParameterNode to be observable; an anonymous * splat or a non-local target is skipped.

Other target kinds (InstanceVariableTargetNode, ConstantTargetNode, IndexTargetNode, CallTargetNode, ConstantPathTargetNode, ImplicitRestNode, ...) MUST be silently skipped: they have no observable contribution to the local-variable scope the StatementEvaluator threads.

See docs/internal-spec/inference-engine.md for the binding contract and docs/adr/4-type-inference-engine.md for the slice rationale.

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.bind(target_node, rhs_type) ⇒ Hash{Symbol => Rigor::Type}

Parameters:

  • target_node (Prism::MultiWriteNode, Prism::MultiTargetNode)
  • rhs_type (Rigor::Type)

    type of the right-hand side

Returns:



56
57
58
59
60
# File 'lib/rigor/inference/multi_target_binder.rb', line 56

def bind(target_node, rhs_type)
  bindings = {}
  visit(target_node, rhs_type, bindings)
  bindings
end

Instance Method Details

#self?.bindHash[Symbol, Type::t]

Parameters:

  • target_node (Object)
  • rhs_type (Type::t)

Returns:

  • (Hash[Symbol, Type::t])


98
# File 'sig/rigor/inference.rbs', line 98

def self?.bind: (untyped target_node, Type::t rhs_type) -> Hash[Symbol, Type::t]