Class: Rigor::Inference::MethodParameterBinder

Inherits:
Object
  • Object
show all
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`. 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` 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).

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.

Instance Method Summary collapse

Constructor Details

#initialize(environment:, class_path:, singleton:, source_path: nil) ⇒ MethodParameterBinder

Returns a new instance of MethodParameterBinder.

Parameters:

  • environment (Rigor::Environment)
  • class_path (String, nil)

    the qualified name of the class the method is defined in (e.g., ‘“Foo::Bar”`), or `nil` for a top-level `def` outside any class. When `nil` (or when the class is unknown to RBS), every parameter falls back to `Dynamic`.

  • singleton (Boolean)

    ‘true` when the def is a singleton method (either `def self.foo` or a `def foo` inside `class << self`); routes the lookup through `RbsLoader#singleton_method`.

  • source_path (String, nil) (defaults to: nil)

    the project-relative path of the file the method is defined in. Used to match ADR-28 path-scoped protocol contracts; ‘nil` (the default for synthetic / probe scopes) disables the contract tier.



50
51
52
53
54
55
# File 'lib/rigor/inference/method_parameter_binder.rb', line 50

def initialize(environment:, class_path:, singleton:, source_path: nil)
  @environment = environment
  @class_path = class_path
  @singleton = singleton
  @source_path = source_path
end

Instance Method Details

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

Returns ordered map from parameter name to bound type. Anonymous parameters (‘*` and `**` without a name) are skipped.

Parameters:

  • def_node (Prism::DefNode)

Returns:

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

    ordered map from parameter name to bound type. Anonymous parameters (‘*` and `**` without a name) are skipped.



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/rigor/inference/method_parameter_binder.rb', line 61

def bind(def_node)
  slots = collect_slots(def_node.parameters)
  types = default_types_for(slots)

  rbs_method = lookup_rbs_method(def_node)
  if rbs_method
    apply_rbs_overloads(types, slots, rbs_method.method_types) unless rbs_method.method_types.empty?
    # `rigor:v1:param: <name> <refinement>` annotations
    # tighten the bound type for matching slots. Applied
    # after the RBS-overload pass so the override is the
    # authoritative answer regardless of what the RBS
    # signature declared.
    apply_param_overrides(types, slots, rbs_method)
  end
  # ADR-28 — a path-scoped protocol contract supplies the
  # parameter type for a matching `def`. Applied last (most
  # authoritative) and regardless of RBS presence: the
  # methods a contract targets — controller actions and the
  # like — typically have no RBS signature at all, so this
  # tier must run even when `rbs_method` is nil.
  apply_protocol_contract(types, slots, def_node)
  types
end