diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index e61ed88a35..bdbb30e23f 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -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)], + )), + ))) + } } } } diff --git a/crates/ty_python_semantic/src/types/call/bind.rs b/crates/ty_python_semantic/src/types/call/bind.rs index d71922b7eb..ab110be2f5 100644 --- a/crates/ty_python_semantic/src/types/call/bind.rs +++ b/crates/ty_python_semantic/src/types/call/bind.rs @@ -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)), diff --git a/crates/ty_python_semantic/src/types/display.rs b/crates/ty_python_semantic/src/types/display.rs index 9e0bf34a3d..27a373c279 100644 --- a/crates/ty_python_semantic/src/types/display.rs +++ b/crates/ty_python_semantic/src/types/display.rs @@ -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"), diff --git a/crates/ty_vendored/ty_extensions/ty_extensions.pyi b/crates/ty_vendored/ty_extensions/ty_extensions.pyi index 6d14869f3d..ad822aa33f 100644 --- a/crates/ty_vendored/ty_extensions/ty_extensions.pyi +++ b/crates/ty_vendored/ty_extensions/ty_extensions.pyi @@ -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"""