Class: Rigor::Inference::ExpressionTyper

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

Overview

Translates AST nodes into Rigor::Type values, consulting the surrounding Rigor::Scope for local-variable bindings and the environment registry for nominal-type resolution. Pure: never mutates the receiver scope.

Accepts both real Prism nodes and synthetic Rigor::AST::Node instances; the synthetic family lets callers and plugins ask “what would the analyzer infer if a value of type T appeared here?” without building a real Prism expression.

Slice 1 recognises literal expressions, local-variable reads/writes, shallow Array literals, and Rigor::AST::TypeNode. Slice 2 adds Prism::CallNode (routed through Rigor::Inference::MethodDispatcher), Prism::ArgumentsNode (a non-value position whose children are typed individually by the CallNode handler), constant references resolved through Rigor::Environment::ClassRegistry, hash and interpolated string/symbol literals, definition expressions (def/class/module), and explicit handlers for parameter, block, splat, instance/class/ global-variable, and self positions. Many of those handlers return Dynamic silently because they are non-value or out-of-scope positions for Slice 2; later slices refine them in place.

Slice 4 phase 2b types bare-constant references (‘Foo`, `Foo::Bar`) as `Singleton` rather than `Nominal`, so that method dispatch on the constant correctly looks up class methods. The corresponding instance type is reachable through `Foo.new` and the value-lattice projections.

Every other node falls back to Dynamic per the fail-soft policy in docs/internal-spec/inference-engine.md. The optional tracer is a Rigor::Inference::FallbackTracer (or any object answering #record_fallback) that receives a Fallback event for each fallback; the tracer MUST NOT change the return value of type_of. rubocop:disable Metrics/ClassLength

Instance Method Summary collapse

Constructor Details

#initialize(scope:, tracer: nil) ⇒ ExpressionTyper

Returns a new instance of ExpressionTyper.



180
181
182
183
# File 'lib/rigor/inference/expression_typer.rb', line 180

def initialize(scope:, tracer: nil)
  @scope = scope
  @tracer = tracer
end

Instance Method Details

#type_of(node) ⇒ Object



185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/rigor/inference/expression_typer.rb', line 185

def type_of(node)
  # Slice A-declarations. ScopeIndexer pre-fills
  # `scope.declared_types` for declaration-position nodes
  # (`module Foo` / `class Bar` headers) with the qualified
  # `Singleton` type so the header itself does not fall
  # through to `Dynamic[Top]`. The override is consulted
  # before any other dispatch and bypasses fail-soft
  # tracing on a recognised match.
  declared = scope.declared_types[node]
  return declared if declared

  return type_of_virtual(node) if node.is_a?(AST::Node)

  handler = PRISM_DISPATCH[node.class]
  return send(handler, node) if handler

  fallback_for(node, family: :prism)
end