pub struct InferenceContext<'a> { /* private fields */ }Expand description
Type inference context for a single function call or expression.
Implementations§
Source§impl<'a> InferenceContext<'a>
impl<'a> InferenceContext<'a>
pub fn new(interner: &'a dyn TypeDatabase) -> Self
pub fn with_resolver( interner: &'a dyn TypeDatabase, resolver: &'a dyn TypeResolver, ) -> Self
Sourcepub fn fresh_var(&mut self) -> InferenceVar
pub fn fresh_var(&mut self) -> InferenceVar
Create a fresh inference variable
Sourcepub fn fresh_type_param(&mut self, name: Atom, is_const: bool) -> InferenceVar
pub fn fresh_type_param(&mut self, name: Atom, is_const: bool) -> InferenceVar
Create an inference variable for a type parameter
Sourcepub fn register_type_param(
&mut self,
name: Atom,
var: InferenceVar,
is_const: bool,
)
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.
Sourcepub fn find_type_param(&self, name: Atom) -> Option<InferenceVar>
pub fn find_type_param(&self, name: Atom) -> Option<InferenceVar>
Look up an inference variable by type parameter name
Sourcepub fn is_var_const(&mut self, var: InferenceVar) -> bool
pub fn is_var_const(&mut self, var: InferenceVar) -> bool
Check if an inference variable is a const type parameter
Sourcepub fn probe(&mut self, var: InferenceVar) -> Option<TypeId>
pub fn probe(&mut self, var: InferenceVar) -> Option<TypeId>
Probe the current value of an inference variable
Sourcepub fn unify_var_type(
&mut self,
var: InferenceVar,
ty: TypeId,
) -> Result<(), InferenceError>
pub fn unify_var_type( &mut self, var: InferenceVar, ty: TypeId, ) -> Result<(), InferenceError>
Unify an inference variable with a concrete type
Sourcepub fn unify_vars(
&mut self,
a: InferenceVar,
b: InferenceVar,
) -> Result<(), InferenceError>
pub fn unify_vars( &mut self, a: InferenceVar, b: InferenceVar, ) -> Result<(), InferenceError>
Unify two inference variables
Sourcepub fn resolve_all(&mut self) -> Result<Vec<(Atom, TypeId)>, InferenceError>
pub fn resolve_all(&mut self) -> Result<Vec<(Atom, TypeId)>, InferenceError>
Resolve all type parameters to concrete types
Sourcepub fn interner(&self) -> &dyn TypeDatabase
pub fn interner(&self) -> &dyn TypeDatabase
Get the interner reference
Sourcepub fn add_lower_bound(&mut self, var: InferenceVar, ty: TypeId)
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.
Sourcepub fn add_candidate(
&mut self,
var: InferenceVar,
ty: TypeId,
priority: InferencePriority,
)
pub fn add_candidate( &mut self, var: InferenceVar, ty: TypeId, priority: InferencePriority, )
Add an inference candidate for a variable.
Sourcepub fn add_property_candidate(
&mut self,
var: InferenceVar,
ty: TypeId,
priority: InferencePriority,
)
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 }).
Sourcepub fn add_property_candidate_with_index(
&mut self,
var: InferenceVar,
ty: TypeId,
priority: InferencePriority,
object_property_index: u32,
object_property_name: Option<Atom>,
)
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.
Sourcepub fn add_upper_bound(&mut self, var: InferenceVar, ty: TypeId)
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.
Sourcepub fn get_constraints(&mut self, var: InferenceVar) -> Option<ConstraintSet>
pub fn get_constraints(&mut self, var: InferenceVar) -> Option<ConstraintSet>
Get the constraints for a variable
Sourcepub fn all_candidates_are_return_type(&mut self, var: InferenceVar) -> bool
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).
Sourcepub fn get_literal_candidates(&mut self, var: InferenceVar) -> Vec<TypeId>
pub fn get_literal_candidates(&mut self, var: InferenceVar) -> Vec<TypeId>
Get the original un-widened literal candidate types for an inference variable.
Sourcepub const fn collect_constraint(&mut self, _source: TypeId, _target: TypeId)
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>
impl<'a> InferenceContext<'a>
Sourcepub fn best_common_type(&self, types: &[TypeId]) -> TypeId
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:
- Filter out duplicates and never types
- Try to find a single candidate that is a supertype of all others
- Try to find a common base class (e.g., Dog + Cat -> Animal)
- If not found, create a union of all candidates
Source§impl<'a> InferenceContext<'a>
impl<'a> InferenceContext<'a>
Sourcepub fn infer_from_types(
&mut self,
source: TypeId,
target: TypeId,
priority: InferencePriority,
) -> Result<(), InferenceError>
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.,stringfromidentity("hello"))target- The type from the parameter (e.g.,Tfromfunction identity<T>(x: T))priority- The inference priority (e.g.,NakedTypeVariablefor direct arguments)
§Type Inference Algorithm
TypeScript uses structural type inference with the following rules:
-
Direct Parameter Match: If target is a type parameter
Twe’re inferring, add source as a lower bound candidate forT. -
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)
-
Variance Handling:
- Covariant positions (properties, arrays, return types):
infer(source, target) - Contravariant positions (function parameters):
infer(target, source)(swapped!)
- Covariant positions (properties, arrays, return types):
§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>
impl<'a> InferenceContext<'a>
Sourcepub fn resolve_with_constraints(
&mut self,
var: InferenceVar,
) -> Result<TypeId, InferenceError>
pub fn resolve_with_constraints( &mut self, var: InferenceVar, ) -> Result<TypeId, InferenceError>
Resolve an inference variable using its collected constraints.
Algorithm:
- If already unified to a concrete type, return that
- Otherwise, compute the best common type from lower bounds
- Validate against upper bounds
- If no lower bounds, use the constraint (upper bound) or default
Sourcepub fn resolve_with_constraints_by<F>(
&mut self,
var: InferenceVar,
is_subtype: F,
) -> Result<TypeId, InferenceError>
pub fn resolve_with_constraints_by<F>( &mut self, var: InferenceVar, is_subtype: F, ) -> Result<TypeId, InferenceError>
Resolve an inference variable using its collected constraints and a custom assignability check for upper-bound validation.
Sourcepub fn resolve_all_with_constraints(
&mut self,
) -> Result<Vec<(Atom, TypeId)>, InferenceError>
pub fn resolve_all_with_constraints( &mut self, ) -> Result<Vec<(Atom, TypeId)>, InferenceError>
Resolve all type parameters using constraints.
Sourcepub fn infer_from_conditional(
&mut self,
var: InferenceVar,
check_type: TypeId,
extends_type: TypeId,
true_type: TypeId,
false_type: TypeId,
)
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.
Sourcepub fn compute_variance(
&self,
ty: TypeId,
target_param: Atom,
) -> (u32, u32, u32, u32)
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)
Sourcepub fn is_invariant_position(&self, ty: TypeId, target_param: Atom) -> bool
pub fn is_invariant_position(&self, ty: TypeId, target_param: Atom) -> bool
Check if a type parameter is invariant at a given position.
Sourcepub fn is_bivariant_position(&self, ty: TypeId, target_param: Atom) -> bool
pub fn is_bivariant_position(&self, ty: TypeId, target_param: Atom) -> bool
Check if a type parameter is bivariant at a given position.
Sourcepub fn get_variance(&self, ty: TypeId, target_param: Atom) -> &'static str
pub fn get_variance(&self, ty: TypeId, target_param: Atom) -> &'static str
Get the variance of a type parameter as a string.
Sourcepub fn infer_from_context(
&mut self,
var: InferenceVar,
context_type: TypeId,
) -> Result<(), InferenceError>
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.
Sourcepub fn strengthen_constraints(&mut self) -> Result<(), InferenceError>
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.
Sourcepub fn validate_variance(&mut self) -> Result<(), InferenceError>
pub fn validate_variance(&mut self) -> Result<(), InferenceError>
Validate that resolved types respect variance constraints.
Sourcepub fn fix_current_variables(&mut self) -> Result<(), InferenceError>
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:
- Finds variables with candidates but no resolved type yet
- Computes their best current type from candidates
- Sets the
resolvedfield to prevent Round 2 from overriding
Variables without candidates are NOT fixed (they might get info from Round 2).
Sourcepub fn get_current_substitution(&mut self) -> TypeSubstitution
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.