Skip to main content

InferenceContext

Struct InferenceContext 

Source
pub struct InferenceContext<'a> { /* private fields */ }
Expand description

Type inference context for a single function call or expression.

Implementations§

Source§

impl<'a> InferenceContext<'a>

Source

pub fn new(interner: &'a dyn TypeDatabase) -> Self

Source

pub fn with_resolver( interner: &'a dyn TypeDatabase, resolver: &'a dyn TypeResolver, ) -> Self

Source

pub fn fresh_var(&mut self) -> InferenceVar

Create a fresh inference variable

Source

pub fn fresh_type_param(&mut self, name: Atom, is_const: bool) -> InferenceVar

Create an inference variable for a type parameter

Source

pub fn register_type_param( &mut self, name: Atom, var: InferenceVar, is_const: bool, )

Register an existing inference variable as representing a type parameter.

This is useful when the caller needs to compute a unique placeholder name (and corresponding placeholder TypeId) after allocating the inference variable.

Source

pub fn find_type_param(&self, name: Atom) -> Option<InferenceVar>

Look up an inference variable by type parameter name

Source

pub fn is_var_const(&mut self, var: InferenceVar) -> bool

Check if an inference variable is a const type parameter

Source

pub fn probe(&mut self, var: InferenceVar) -> Option<TypeId>

Probe the current value of an inference variable

Source

pub fn unify_var_type( &mut self, var: InferenceVar, ty: TypeId, ) -> Result<(), InferenceError>

Unify an inference variable with a concrete type

Source

pub fn unify_vars( &mut self, a: InferenceVar, b: InferenceVar, ) -> Result<(), InferenceError>

Unify two inference variables

Source

pub fn resolve_all(&mut self) -> Result<Vec<(Atom, TypeId)>, InferenceError>

Resolve all type parameters to concrete types

Source

pub fn interner(&self) -> &dyn TypeDatabase

Get the interner reference

Source

pub fn add_lower_bound(&mut self, var: InferenceVar, ty: TypeId)

Add a lower bound constraint: ty <: var This is used when an argument type flows into a type parameter. Updated to use NakedTypeVariable (highest priority) for direct argument inference.

Source

pub fn add_candidate( &mut self, var: InferenceVar, ty: TypeId, priority: InferencePriority, )

Add an inference candidate for a variable.

Source

pub fn add_property_candidate( &mut self, var: InferenceVar, ty: TypeId, priority: InferencePriority, )

Add an inference candidate for a variable that originates from object property inference. Object-property candidates are tracked so the resolver can apply tighter union handling for repeated property positions (e.g. { bar: T; baz: T }).

Source

pub fn add_property_candidate_with_index( &mut self, var: InferenceVar, ty: TypeId, priority: InferencePriority, object_property_index: u32, object_property_name: Option<Atom>, )

Add an inference candidate for a variable that originates from an object property. object_property_index captures the source property order and enables deterministic tie-breaking when repeated property candidates collapse to a union.

Source

pub fn add_upper_bound(&mut self, var: InferenceVar, ty: TypeId)

Add an upper bound constraint: var <: ty This is used for extends constraints on type parameters.

Source

pub fn get_constraints(&mut self, var: InferenceVar) -> Option<ConstraintSet>

Get the constraints for a variable

Source

pub fn all_candidates_are_return_type(&mut self, var: InferenceVar) -> bool

Check if all inference candidates for a variable have ReturnType priority. This indicates the type was inferred from callback return types (Round 2), not from direct arguments (Round 1).

Source

pub fn get_literal_candidates(&mut self, var: InferenceVar) -> Vec<TypeId>

Get the original un-widened literal candidate types for an inference variable.

Source

pub const fn collect_constraint(&mut self, _source: TypeId, _target: TypeId)

Collect a constraint from an assignment: source flows into target If target is an inference variable, source becomes a lower bound. If source is an inference variable, target becomes an upper bound.

Source§

impl<'a> InferenceContext<'a>

Source

pub fn best_common_type(&self, types: &[TypeId]) -> TypeId

Calculate the best common type from a set of types. This implements Rule #32: Best Common Type (BCT) Inference.

Algorithm:

  1. Filter out duplicates and never types
  2. Try to find a single candidate that is a supertype of all others
  3. Try to find a common base class (e.g., Dog + Cat -> Animal)
  4. If not found, create a union of all candidates
Source§

impl<'a> InferenceContext<'a>

Source

pub fn infer_from_types( &mut self, source: TypeId, target: TypeId, priority: InferencePriority, ) -> Result<(), InferenceError>

Perform structural type inference from a source type to a target type.

This is the core algorithm for inferring type parameters from function arguments. It walks the structure of both types, collecting constraints for type parameters.

§Arguments
  • source - The type from the value argument (e.g., string from identity("hello"))
  • target - The type from the parameter (e.g., T from function identity<T>(x: T))
  • priority - The inference priority (e.g., NakedTypeVariable for direct arguments)
§Type Inference Algorithm

TypeScript uses structural type inference with the following rules:

  1. Direct Parameter Match: If target is a type parameter T we’re inferring, add source as a lower bound candidate for T.

  2. Structural Recursion: For complex types, recurse into the structure:

    • Objects: Match properties recursively
    • Arrays: Match element types
    • Functions: Match parameters (contravariant) and return types (covariant)
  3. Variance Handling:

    • Covariant positions (properties, arrays, return types): infer(source, target)
    • Contravariant positions (function parameters): infer(target, source) (swapped!)
§Example
let mut ctx = InferenceContext::new(&interner);
let t_var = ctx.fresh_type_param(interner.intern_string("T"), false);

// Inference: identity("hello") should infer T = string
ctx.infer_from_types(string_type, t_type, InferencePriority::NakedTypeVariable)?;
Source§

impl<'a> InferenceContext<'a>

Source

pub fn resolve_with_constraints( &mut self, var: InferenceVar, ) -> Result<TypeId, InferenceError>

Resolve an inference variable using its collected constraints.

Algorithm:

  1. If already unified to a concrete type, return that
  2. Otherwise, compute the best common type from lower bounds
  3. Validate against upper bounds
  4. If no lower bounds, use the constraint (upper bound) or default
Source

pub fn resolve_with_constraints_by<F>( &mut self, var: InferenceVar, is_subtype: F, ) -> Result<TypeId, InferenceError>
where F: FnMut(TypeId, TypeId) -> bool,

Resolve an inference variable using its collected constraints and a custom assignability check for upper-bound validation.

Source

pub fn resolve_all_with_constraints( &mut self, ) -> Result<Vec<(Atom, TypeId)>, InferenceError>

Resolve all type parameters using constraints.

Source

pub fn infer_from_conditional( &mut self, var: InferenceVar, check_type: TypeId, extends_type: TypeId, true_type: TypeId, false_type: TypeId, )

Infer type parameters from a conditional type. When a type parameter appears in a conditional type, we can sometimes infer its value from the check and extends clauses.

Source

pub fn compute_variance( &self, ty: TypeId, target_param: Atom, ) -> (u32, u32, u32, u32)

Compute the variance of a type parameter within a type. Returns (covariant_count, contravariant_count, invariant_count, bivariant_count)

Source

pub fn is_invariant_position(&self, ty: TypeId, target_param: Atom) -> bool

Check if a type parameter is invariant at a given position.

Source

pub fn is_bivariant_position(&self, ty: TypeId, target_param: Atom) -> bool

Check if a type parameter is bivariant at a given position.

Source

pub fn get_variance(&self, ty: TypeId, target_param: Atom) -> &'static str

Get the variance of a type parameter as a string.

Source

pub fn infer_from_context( &mut self, var: InferenceVar, context_type: TypeId, ) -> Result<(), InferenceError>

Try to infer a type parameter from its usage context. This implements bidirectional type inference where the context (e.g., return type, variable declaration) provides constraints.

Source

pub fn strengthen_constraints(&mut self) -> Result<(), InferenceError>

Strengthen constraints by analyzing relationships between type parameters. For example, if T <: U and we know T = string, then U must be at least string.

Source

pub fn validate_variance(&mut self) -> Result<(), InferenceError>

Validate that resolved types respect variance constraints.

Source

pub fn fix_current_variables(&mut self) -> Result<(), InferenceError>

Fix (resolve) inference variables that have candidates from Round 1.

This is called after processing non-contextual arguments to “fix” type variables that have enough information, before processing contextual arguments (like lambdas) in Round 2.

The fixing process:

  1. Finds variables with candidates but no resolved type yet
  2. Computes their best current type from candidates
  3. Sets the resolved field to prevent Round 2 from overriding

Variables without candidates are NOT fixed (they might get info from Round 2).

Source

pub fn get_current_substitution(&mut self) -> TypeSubstitution

Get the current best substitution for all type parameters.

This returns a TypeSubstitution mapping each type parameter to its current best type (either resolved or the best candidate so far). Used in Round 2 to provide contextual types to lambda arguments.

Auto Trait Implementations§

§

impl<'a> !Freeze for InferenceContext<'a>

§

impl<'a> !RefUnwindSafe for InferenceContext<'a>

§

impl<'a> !Send for InferenceContext<'a>

§

impl<'a> !Sync for InferenceContext<'a>

§

impl<'a> Unpin for InferenceContext<'a>

§

impl<'a> UnsafeUnpin for InferenceContext<'a>

§

impl<'a> !UnwindSafe for InferenceContext<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<S, T> Upcast<T> for S
where T: UpcastFrom<S> + ?Sized, S: ?Sized,

Source§

fn upcast(&self) -> &T
where Self: ErasableGeneric, T: ErasableGeneric<Repr = Self::Repr>,

Perform a zero-cost type-safe upcast to a wider ref type within the Wasm bindgen generics type system. Read more
Source§

fn upcast_into(self) -> T
where Self: Sized + ErasableGeneric, T: ErasableGeneric<Repr = Self::Repr>,

Perform a zero-cost type-safe upcast to a wider type within the Wasm bindgen generics type system. Read more
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more