Module: Rigor::Inference::MultiTargetBinder

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

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`, `Dynamic`, `Top`, `Bot`, …) collapse to `Dynamic` 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

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:



68
69
70
71
72
# File 'lib/rigor/inference/multi_target_binder.rb', line 68

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