Class: Rigor::Inference::BlockParameterBinder

Inherits:
Object
  • Object
show all
Defined in:
lib/rigor/inference/block_parameter_binder.rb

Overview

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

The binder is the symmetric counterpart of MethodParameterBinder for ‘Prism::BlockNode`. The expected parameter types come from the receiving method’s RBS signature (MethodDispatcher.expected_block_param_types); parameters that the signature does not cover (or that the binder cannot match by position) default to ‘Dynamic`. The default is the Slice 1 fail-soft answer for unknown values, so a block whose receiving method has no signature still binds every name into the scope (a block 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).

MultiTargetNode parameters (‘|(a, b), c|`) are bound by delegating each destructuring slot to MultiTargetBinder, so a Tuple-shaped expected element type projects element-wise into the inner locals (Slice 6 phase C sub-phase 2). Numbered parameters (`_1`, `_2`, …) are bound from `Prism::NumberedParametersNode` using the same per-position `expected_param_types:` array, so `[1, 2, 3].each { _1 + _2 }` sees `_1`/`_2` typed identically to their explicit `|x, y|` counterparts.

Block-local declarations after ‘;` (e.g., `|x; y, z|`) are still skipped — they are explicitly block-local, so the outer scope MUST NOT observe them and the binder leaves them unbound.

See docs/internal-spec/inference-engine.md for the binding contract. rubocop:disable Metrics/ClassLength

Instance Method Summary collapse

Constructor Details

#initialize(expected_param_types: []) ⇒ BlockParameterBinder

Returns a new instance of BlockParameterBinder.

Parameters:

  • expected_param_types (Array<Rigor::Type>) (defaults to: [])

    positional block parameter types in order. Indices the binder cannot fill from this array (because the array is shorter than the parameter list, or because the slot is a kind we do not pull from the array) default to ‘Dynamic`.



49
50
51
# File 'lib/rigor/inference/block_parameter_binder.rb', line 49

def initialize(expected_param_types: [])
  @expected_param_types = expected_param_types
end

Instance Method Details

#bind(block_node) ⇒ Hash{Symbol => Rigor::Type}

Returns ordered map from parameter name to bound type. Anonymous parameters are skipped; MultiTargetNode destructuring slots delegate to MultiTargetBinder and contribute every named local in declaration order. Numbered-parameter forms (‘_1`, `_2`, …) bind `:_1`, `:_2`, … up to the maximum the block body refers to.

Parameters:

  • block_node (Prism::BlockNode)

Returns:

  • (Hash{Symbol => Rigor::Type})

    ordered map from parameter name to bound type. Anonymous parameters are skipped; MultiTargetNode destructuring slots delegate to MultiTargetBinder and contribute every named local in declaration order. Numbered-parameter forms (‘_1`, `_2`, …) bind `:_1`, `:_2`, … up to the maximum the block body refers to.



61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/rigor/inference/block_parameter_binder.rb', line 61

def bind(block_node)
  params_root = block_node.parameters
  return {} if params_root.nil?

  case params_root
  when Prism::NumberedParametersNode
    bind_numbered_parameters(params_root)
  when Prism::BlockParametersNode
    bind_block_parameters(params_root)
  else
    {}
  end
end