Class: Rigor::Inference::BlockParameterBinder
- Inherits:
-
Object
- Object
- Rigor::Inference::BlockParameterBinder
- Defined in:
- lib/rigor/inference/block_parameter_binder.rb,
sig/rigor/inference.rbs
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[Top]. 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[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).
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.
The it implicit parameter (Ruby 3.4+) is bound from Prism::ItParametersNode. It is the
single-argument cousin of _1: the binder produces { it: expected_param_types[0] } so the body's
Prism::ItLocalVariableReadNode lookup sees the same type as the explicit |x| form would.
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.
Instance Method Summary collapse
-
#bind(block_node) ⇒ Hash{Symbol => Rigor::Type}
Ordered map from parameter name to bound type.
- #bind_block_parameters(params_root) ⇒ Hash[Symbol, Type::t]
-
#bind_numbered_parameters(numbered_node) ⇒ Hash[Symbol, Type::t]
|_1, _2|numbered-parameter form. -
#initialize(expected_param_types: []) ⇒ BlockParameterBinder
constructor
A new instance of BlockParameterBinder.
- #positional_type_at(index) ⇒ Type::t
Constructor Details
#initialize(expected_param_types: []) ⇒ BlockParameterBinder
Returns a new instance of BlockParameterBinder.
40 41 42 |
# File 'lib/rigor/inference/block_parameter_binder.rb', line 40 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.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/rigor/inference/block_parameter_binder.rb', line 49 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::ItParametersNode bind_it_parameter when Prism::BlockParametersNode bind_block_parameters(params_root) else {} end end |
#bind_block_parameters(params_root) ⇒ Hash[Symbol, Type::t]
85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/rigor/inference/block_parameter_binder.rb', line 85 def bind_block_parameters(params_root) params_node = params_root.parameters return {} if params_node.nil? apply_auto_splat(params_node) bindings = {} bind_positionals(params_node, bindings, 0) bind_rest(params_node, bindings) bind_keywords(params_node, bindings) bind_keyword_rest(params_node, bindings) bind_block_param(params_node, bindings) bindings end |
#bind_numbered_parameters(numbered_node) ⇒ Hash[Symbol, Type::t]
|_1, _2| numbered-parameter form. Prism exposes the implicit count through
NumberedParametersNode#maximum (the highest _N referenced in the body); we materialise bindings
for :_1 through :_maximum so the block body's LocalVariableReadNode lookups see the same types
as the equivalent explicit |x, y| form would.
71 72 73 74 75 76 77 |
# File 'lib/rigor/inference/block_parameter_binder.rb', line 71 def bind_numbered_parameters(numbered_node) bindings = {} numbered_node.maximum.times do |i| bindings[:"_#{i + 1}"] = positional_type_at(i) end bindings end |
#positional_type_at(index) ⇒ Type::t
209 210 211 |
# File 'lib/rigor/inference/block_parameter_binder.rb', line 209 def positional_type_at(index) @expected_param_types[index] || Type::Combinator.untyped end |