Module: Rigor::Inference::Acceptance
- Defined in:
- lib/rigor/inference/acceptance.rb,
sig/rigor/inference.rbs
Overview
Shared dispatch table for Rigor::Type#accepts(other, mode:).
The acceptance query answers "is other passable to self at a method-parameter or assignment
boundary?". It uses gradual-typing rules from docs/type-specification/value-lattice.md and the
acceptance contract in docs/internal-spec/internal-type-api.md.
Each concrete type's accepts method delegates here so the case-analysis stays in one place. Type
instances remain thin value objects; routing logic lives in the inference layer.
Slice 4 phase 2c implements the :gradual mode in full and reserves :strict for later slices (the
entry point raises ArgumentError on strict for now). The table covers the leaf and combinator types
added through phase 2b: Top, Bot, Dynamic, Nominal, Singleton, Constant, and Union.
Slice 5 registers the shape carriers Tuple and HashShape. Tuple/HashShape acceptance compares
per-position element types (covariant) and per-key entry types (depth covariant), including HashShape
required/optional/closed-extra-key policy. When the receiver side is a generic Nominal[Array, [E]] or
Nominal[Hash, [K, V]] the shape is projected to its underlying nominal so the existing
generic-acceptance pipeline continues to apply; the converse direction (a Tuple receiver accepting a
generic Array) stays conservative because the analyzer cannot verify arity from a raw nominal alone.
rubocop:disable Metrics/ModuleLength
Class Method Summary collapse
Instance Method Summary collapse
Class Method Details
.accepts(self_type, other_type, mode: :gradual) ⇒ Rigor::Type::AcceptsResult
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/rigor/inference/acceptance.rb', line 34 def accepts(self_type, other_type, mode: :gradual) raise ArgumentError, "Acceptance mode #{mode.inspect} is not implemented yet" unless mode == :gradual return Type::AcceptsResult.yes(mode: mode, reasons: "Bot is the empty type") if other_type.is_a?(Type::Bot) if other_type.is_a?(Type::Dynamic) return Type::AcceptsResult.yes(mode: mode, reasons: "gradual: Dynamic[T] passes any boundary") end # Structural equality short-circuit. Two identical carriers describe the same value set, so they always # accept each other. This is sound for any mode and covers cases where neither side has a per-class rule # for the other's exact carrier kind (the canonical example is `Intersection.accepts(Intersection)`, # where the disjunction rule below would otherwise reject equal-but-narrow LHSes). return Type::AcceptsResult.yes(mode: mode, reasons: "structural equality") if self_type == other_type return accepts_union_other(self_type, other_type, mode) if other_type.is_a?(Type::Union) return accepts_intersection_other(self_type, other_type, mode) if other_type.is_a?(Type::Intersection) accepts_one(self_type, other_type, mode) end |
Instance Method Details
#self?.accepts ⇒ Type::AcceptsResult
132 |
# File 'sig/rigor/inference.rbs', line 132
def self?.accepts: (Type::t self_type, Type::t other_type, ?mode: Type::accepts_mode) -> Type::AcceptsResult
|