add GenericContext.specialize_constrained mdtest method

This commit is contained in:
Douglas Creager 2025-11-12 18:17:10 -05:00
parent ca557a22b9
commit 65d02e05c8
4 changed files with 79 additions and 8 deletions

View file

@ -4433,6 +4433,14 @@ impl<'db> Type<'db> {
))
.into()
}
Type::KnownInstance(KnownInstanceType::GenericContext(tracked))
if name == "specialize_constrained" =>
{
Place::bound(Type::KnownBoundMethod(
KnownBoundMethodType::GenericContextSpecializeConstrained(tracked),
))
.into()
}
Type::ClassLiteral(class)
if name == "__get__" && class.is_known(db, KnownClass::FunctionType) =>
@ -7294,6 +7302,7 @@ impl<'db> Type<'db> {
| KnownBoundMethodType::ConstraintSetImpliesSubtypeOf(_)
| KnownBoundMethodType::ConstraintSetSatisfies(_)
| KnownBoundMethodType::ConstraintSetSatisfiedByAllTypeVars(_)
| KnownBoundMethodType::GenericContextSpecializeConstrained(_)
)
| Type::DataclassDecorator(_)
| Type::DataclassTransformer(_)
@ -7453,7 +7462,8 @@ impl<'db> Type<'db> {
| KnownBoundMethodType::ConstraintSetNever
| KnownBoundMethodType::ConstraintSetImpliesSubtypeOf(_)
| KnownBoundMethodType::ConstraintSetSatisfies(_)
| KnownBoundMethodType::ConstraintSetSatisfiedByAllTypeVars(_),
| KnownBoundMethodType::ConstraintSetSatisfiedByAllTypeVars(_)
| KnownBoundMethodType::GenericContextSpecializeConstrained(_),
)
| Type::DataclassDecorator(_)
| Type::DataclassTransformer(_)
@ -10974,6 +10984,9 @@ pub enum KnownBoundMethodType<'db> {
ConstraintSetImpliesSubtypeOf(TrackedConstraintSet<'db>),
ConstraintSetSatisfies(TrackedConstraintSet<'db>),
ConstraintSetSatisfiedByAllTypeVars(TrackedConstraintSet<'db>),
// GenericContext methods
GenericContextSpecializeConstrained(GenericContext<'db>),
}
pub(super) fn walk_method_wrapper_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
@ -11003,7 +11016,8 @@ pub(super) fn walk_method_wrapper_type<'db, V: visitor::TypeVisitor<'db> + ?Size
| KnownBoundMethodType::ConstraintSetNever
| KnownBoundMethodType::ConstraintSetImpliesSubtypeOf(_)
| KnownBoundMethodType::ConstraintSetSatisfies(_)
| KnownBoundMethodType::ConstraintSetSatisfiedByAllTypeVars(_) => {}
| KnownBoundMethodType::ConstraintSetSatisfiedByAllTypeVars(_)
| KnownBoundMethodType::GenericContextSpecializeConstrained(_) => {}
}
}
@ -11079,6 +11093,10 @@ impl<'db> KnownBoundMethodType<'db> {
| (
KnownBoundMethodType::ConstraintSetSatisfiedByAllTypeVars(_),
KnownBoundMethodType::ConstraintSetSatisfiedByAllTypeVars(_),
)
| (
KnownBoundMethodType::GenericContextSpecializeConstrained(_),
KnownBoundMethodType::GenericContextSpecializeConstrained(_),
) => ConstraintSet::from(true),
(
@ -11093,7 +11111,8 @@ impl<'db> KnownBoundMethodType<'db> {
| KnownBoundMethodType::ConstraintSetNever
| KnownBoundMethodType::ConstraintSetImpliesSubtypeOf(_)
| KnownBoundMethodType::ConstraintSetSatisfies(_)
| KnownBoundMethodType::ConstraintSetSatisfiedByAllTypeVars(_),
| KnownBoundMethodType::ConstraintSetSatisfiedByAllTypeVars(_)
| KnownBoundMethodType::GenericContextSpecializeConstrained(_),
KnownBoundMethodType::FunctionTypeDunderGet(_)
| KnownBoundMethodType::FunctionTypeDunderCall(_)
| KnownBoundMethodType::PropertyDunderGet(_)
@ -11105,7 +11124,8 @@ impl<'db> KnownBoundMethodType<'db> {
| KnownBoundMethodType::ConstraintSetNever
| KnownBoundMethodType::ConstraintSetImpliesSubtypeOf(_)
| KnownBoundMethodType::ConstraintSetSatisfies(_)
| KnownBoundMethodType::ConstraintSetSatisfiedByAllTypeVars(_),
| KnownBoundMethodType::ConstraintSetSatisfiedByAllTypeVars(_)
| KnownBoundMethodType::GenericContextSpecializeConstrained(_),
) => ConstraintSet::from(false),
}
}
@ -11170,6 +11190,11 @@ impl<'db> KnownBoundMethodType<'db> {
.constraints(db)
.iff(db, right_constraints.constraints(db)),
(
KnownBoundMethodType::GenericContextSpecializeConstrained(left_generic_context),
KnownBoundMethodType::GenericContextSpecializeConstrained(right_generic_context),
) => ConstraintSet::from(left_generic_context == right_generic_context),
(
KnownBoundMethodType::FunctionTypeDunderGet(_)
| KnownBoundMethodType::FunctionTypeDunderCall(_)
@ -11182,7 +11207,8 @@ impl<'db> KnownBoundMethodType<'db> {
| KnownBoundMethodType::ConstraintSetNever
| KnownBoundMethodType::ConstraintSetImpliesSubtypeOf(_)
| KnownBoundMethodType::ConstraintSetSatisfies(_)
| KnownBoundMethodType::ConstraintSetSatisfiedByAllTypeVars(_),
| KnownBoundMethodType::ConstraintSetSatisfiedByAllTypeVars(_)
| KnownBoundMethodType::GenericContextSpecializeConstrained(_),
KnownBoundMethodType::FunctionTypeDunderGet(_)
| KnownBoundMethodType::FunctionTypeDunderCall(_)
| KnownBoundMethodType::PropertyDunderGet(_)
@ -11194,7 +11220,8 @@ impl<'db> KnownBoundMethodType<'db> {
| KnownBoundMethodType::ConstraintSetNever
| KnownBoundMethodType::ConstraintSetImpliesSubtypeOf(_)
| KnownBoundMethodType::ConstraintSetSatisfies(_)
| KnownBoundMethodType::ConstraintSetSatisfiedByAllTypeVars(_),
| KnownBoundMethodType::ConstraintSetSatisfiedByAllTypeVars(_)
| KnownBoundMethodType::GenericContextSpecializeConstrained(_),
) => ConstraintSet::from(false),
}
}
@ -11220,7 +11247,8 @@ impl<'db> KnownBoundMethodType<'db> {
| KnownBoundMethodType::ConstraintSetNever
| KnownBoundMethodType::ConstraintSetImpliesSubtypeOf(_)
| KnownBoundMethodType::ConstraintSetSatisfies(_)
| KnownBoundMethodType::ConstraintSetSatisfiedByAllTypeVars(_) => self,
| KnownBoundMethodType::ConstraintSetSatisfiedByAllTypeVars(_)
| KnownBoundMethodType::GenericContextSpecializeConstrained(_) => self,
}
}
@ -11238,7 +11266,8 @@ impl<'db> KnownBoundMethodType<'db> {
| KnownBoundMethodType::ConstraintSetNever
| KnownBoundMethodType::ConstraintSetImpliesSubtypeOf(_)
| KnownBoundMethodType::ConstraintSetSatisfies(_)
| KnownBoundMethodType::ConstraintSetSatisfiedByAllTypeVars(_) => {
| KnownBoundMethodType::ConstraintSetSatisfiedByAllTypeVars(_)
| KnownBoundMethodType::GenericContextSpecializeConstrained(_) => {
KnownClass::ConstraintSet
}
}
@ -11400,6 +11429,19 @@ impl<'db> KnownBoundMethodType<'db> {
Some(KnownClass::Bool.to_instance(db)),
)))
}
KnownBoundMethodType::GenericContextSpecializeConstrained(_) => {
Either::Right(std::iter::once(Signature::new(
Parameters::new([Parameter::positional_only(Some(Name::new_static(
"constraints",
)))
.with_annotated_type(KnownClass::ConstraintSet.to_instance(db))]),
Some(UnionType::from_elements(
db,
[KnownClass::Specialization.to_instance(db), Type::none(db)],
)),
)))
}
}
}
}

View file

@ -1274,6 +1274,26 @@ impl<'db> Bindings<'db> {
overload.set_return_type(Type::BooleanLiteral(result));
}
Type::KnownBoundMethod(
KnownBoundMethodType::GenericContextSpecializeConstrained(generic_context),
) => {
let [Some(constraints)] = overload.parameter_types() else {
continue;
};
let Type::KnownInstance(KnownInstanceType::ConstraintSet(constraints)) =
constraints
else {
continue;
};
if let Ok(specialization) =
generic_context.specialize_constrained(db, constraints.constraints(db))
{
overload.set_return_type(Type::KnownInstance(
KnownInstanceType::Specialization(specialization),
));
}
}
Type::ClassLiteral(class) => match class.known(db) {
Some(KnownClass::Bool) => match overload.parameter_types() {
[Some(arg)] => overload.set_return_type(arg.bool(db).into_type(db)),

View file

@ -541,6 +541,9 @@ impl Display for DisplayRepresentation<'_> {
Type::KnownBoundMethod(KnownBoundMethodType::ConstraintSetSatisfiedByAllTypeVars(
_,
)) => f.write_str("bound method `ConstraintSet.satisfied_by_all_typevars`"),
Type::KnownBoundMethod(KnownBoundMethodType::GenericContextSpecializeConstrained(
_,
)) => f.write_str("bound method `GenericContext.specialize_constrained`"),
Type::WrapperDescriptor(kind) => {
let (method, object) = match kind {
WrapperDescriptorKind::FunctionTypeDunderGet => ("__get__", "function"),

View file

@ -97,6 +97,12 @@ class GenericContext:
alias.
"""
def specialize_constrained(self, constraints: ConstraintSet) -> Specialization | None:
"""
Returns a specialization of this generic context that satisfies the
given constraints, or None if the constraints cannot be satisfied.
"""
class Specialization:
"""A mapping of typevars to specific types"""