add more comments

This commit is contained in:
Douglas Creager 2025-12-09 20:33:07 -05:00
parent 4f7ad7bbc9
commit b1ede8885b
2 changed files with 30 additions and 0 deletions

View File

@ -556,6 +556,13 @@ impl<'db> GenericContext<'db> {
let partial = PartialSpecialization { let partial = PartialSpecialization {
generic_context: self, generic_context: self,
types: &types, types: &types,
// Don't recursively substitute type[i] in itself. Ideally, we could instead
// check if the result is self-referential after we're done applying the
// partial specialization. But when we apply a paramspec, we don't use the
// callable that it maps to directly; we create a new callable that reuses
// parts of it. That means we can't look for the previous type directly.
// Instead we use this to skip specializing the type in itself in the first
// place.
skip: Some(i), skip: Some(i),
}; };
let updated = types[i].apply_type_mapping( let updated = types[i].apply_type_mapping(
@ -1362,6 +1369,8 @@ impl<'db> Specialization<'db> {
pub struct PartialSpecialization<'a, 'db> { pub struct PartialSpecialization<'a, 'db> {
generic_context: GenericContext<'db>, generic_context: GenericContext<'db>,
types: &'a [Type<'db>], types: &'a [Type<'db>],
/// An optional typevar to _not_ substitute when applying the specialization. We use this to
/// avoid recursively substituting a type inside of itself.
skip: Option<usize>, skip: Option<usize>,
} }
@ -1471,6 +1480,14 @@ impl<'db> SpecializationBuilder<'db> {
} }
} }
/// Finds all of the valid specializations of a constraint set, and adds their type mappings to
/// the specialization that this builder is building up.
///
/// TODO: This is a stopgap! Eventually, the builder will maintain a single constraint set for
/// the main specialization that we are building, and [`build`][Self::build] will build the
/// specialization directly from that constraint set. This method lets us migrate to that brave
/// new world incrementally, by using the new constraint set mechanism piecemeal for certain
/// type comparisons.
fn add_type_mappings_from_constraint_set( fn add_type_mappings_from_constraint_set(
&mut self, &mut self,
constraints: ConstraintSet<'db>, constraints: ConstraintSet<'db>,
@ -1526,6 +1543,15 @@ impl<'db> SpecializationBuilder<'db> {
polarity: TypeVarVariance, polarity: TypeVarVariance,
mut f: &mut dyn FnMut(TypeVarAssignment<'db>) -> Option<Type<'db>>, mut f: &mut dyn FnMut(TypeVarAssignment<'db>) -> Option<Type<'db>>,
) -> Result<(), SpecializationError<'db>> { ) -> Result<(), SpecializationError<'db>> {
// TODO: Eventually, the builder will maintain a constraint set, instead of a hash-map of
// type mappings, to represent the specialization that we are building up. At that point,
// this method will just need to compare `actual ≤ formal`, using constraint set
// assignability, and AND the result into the constraint set we are building.
//
// To make progress on that migration, we use constraint set assignability whenever
// possible when adding any new heuristics here. See the `Callable` clause below for an
// example.
if formal == actual { if formal == actual {
return Ok(()); return Ok(());
} }

View File

@ -443,6 +443,10 @@ impl<'db> CallableSignature<'db> {
let self_is_single_paramspec = Self::signatures_is_single_paramspec(self_signatures); let self_is_single_paramspec = Self::signatures_is_single_paramspec(self_signatures);
let other_is_single_paramspec = Self::signatures_is_single_paramspec(other_signatures); let other_is_single_paramspec = Self::signatures_is_single_paramspec(other_signatures);
// If either callable is a ParamSpec, the constraint set should bind the ParamSpec to
// the other callable's signature. We also need to compare the return types — for
// instance, to verify in `Callable[P, int]` that the return type is assignable to
// `int`, or in `Callable[P, T]` to bind `T` to the return type of the other callable.
match (self_is_single_paramspec, other_is_single_paramspec) { match (self_is_single_paramspec, other_is_single_paramspec) {
( (
Some((self_bound_typevar, self_return_type)), Some((self_bound_typevar, self_return_type)),