mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-28 18:53:25 +00:00
[ty] Don't track inferability via different Type variants (#20677)
We have to track whether a typevar appears in a position where it's inferable or not. In a non-inferable position (in the body of the generic class or function that binds it), assignability must hold for every possible specialization of the typevar. In an inferable position, it only needs to hold for _some_ specialization. https://github.com/astral-sh/ruff/pull/20093 is working on using constraint sets to model assignability of typevars, and the constraint sets that we produce will be the same for inferable vs non-inferable typevars; what changes is what we _compare_ that constraint set to. (For a non-inferable typevar, the constraint set must equal the set of valid specializations; for an inferable typevar, it must not be `never`.) When I first added support for tracking inferable vs non-inferable typevars, it seemed like it would be easiest to have separate `Type` variants for each. The alternative (which lines up with the Δ set in [POPL15](https://doi.org/10.1145/2676726.2676991)) would be to explicitly plumb through a list of inferable typevars through our type property methods. That seemed cumbersome. In retrospect, that was the wrong decision. We've had to jump through hoops to translate types between the inferable and non-inferable variants, which has been quite brittle. Combined with the original point above, that much of the assignability logic will become more identical between inferable and non-inferable, there is less justification for the two `Type` variants. And plumbing an extra `inferable` parameter through all of these methods turns out to not be as bad as I anticipated. --------- Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
parent
25023cc0ea
commit
b0e10a9777
17 changed files with 312 additions and 373 deletions
|
|
@ -131,7 +131,7 @@ impl<'db> Completion<'db> {
|
||||||
| Type::BytesLiteral(_) => CompletionKind::Value,
|
| Type::BytesLiteral(_) => CompletionKind::Value,
|
||||||
Type::EnumLiteral(_) => CompletionKind::Enum,
|
Type::EnumLiteral(_) => CompletionKind::Enum,
|
||||||
Type::ProtocolInstance(_) => CompletionKind::Interface,
|
Type::ProtocolInstance(_) => CompletionKind::Interface,
|
||||||
Type::NonInferableTypeVar(_) | Type::TypeVar(_) => CompletionKind::TypeParameter,
|
Type::TypeVar(_) => CompletionKind::TypeParameter,
|
||||||
Type::Union(union) => union
|
Type::Union(union) => union
|
||||||
.elements(db)
|
.elements(db)
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
||||||
|
|
@ -336,9 +336,7 @@ impl<'db> SemanticTokenVisitor<'db> {
|
||||||
|
|
||||||
match ty {
|
match ty {
|
||||||
Type::ClassLiteral(_) => (SemanticTokenType::Class, modifiers),
|
Type::ClassLiteral(_) => (SemanticTokenType::Class, modifiers),
|
||||||
Type::NonInferableTypeVar(_) | Type::TypeVar(_) => {
|
Type::TypeVar(_) => (SemanticTokenType::TypeParameter, modifiers),
|
||||||
(SemanticTokenType::TypeParameter, modifiers)
|
|
||||||
}
|
|
||||||
Type::FunctionLiteral(_) => {
|
Type::FunctionLiteral(_) => {
|
||||||
// Check if this is a method based on current scope
|
// Check if this is a method based on current scope
|
||||||
if self.in_class_scope {
|
if self.in_class_scope {
|
||||||
|
|
|
||||||
|
|
@ -800,15 +800,9 @@ pub enum Type<'db> {
|
||||||
LiteralString,
|
LiteralString,
|
||||||
/// A bytes literal
|
/// A bytes literal
|
||||||
BytesLiteral(BytesLiteralType<'db>),
|
BytesLiteral(BytesLiteralType<'db>),
|
||||||
/// An instance of a typevar in a context where we can infer a specialization for it. (This is
|
/// An instance of a typevar. When the generic class or function binding this typevar is
|
||||||
/// typically the signature of a generic function, or of a constructor of a generic class.)
|
/// specialized, we will replace the typevar with its specialization.
|
||||||
/// When the generic class or function binding this typevar is specialized, we will replace the
|
|
||||||
/// typevar with its specialization.
|
|
||||||
TypeVar(BoundTypeVarInstance<'db>),
|
TypeVar(BoundTypeVarInstance<'db>),
|
||||||
/// An instance of a typevar where we cannot infer a specialization for it. (This is typically
|
|
||||||
/// the body of the generic function or class that binds the typevar.) In these positions,
|
|
||||||
/// properties like assignability must hold for all possible specializations.
|
|
||||||
NonInferableTypeVar(BoundTypeVarInstance<'db>),
|
|
||||||
/// A bound super object like `super()` or `super(A, A())`
|
/// A bound super object like `super()` or `super(A, A())`
|
||||||
/// This type doesn't handle an unbound super object like `super(A)`; for that we just use
|
/// This type doesn't handle an unbound super object like `super(A)`; for that we just use
|
||||||
/// a `Type::NominalInstance` of `builtins.super`.
|
/// a `Type::NominalInstance` of `builtins.super`.
|
||||||
|
|
@ -1374,9 +1368,6 @@ impl<'db> Type<'db> {
|
||||||
Type::TypeVar(bound_typevar) => visitor.visit(self, || {
|
Type::TypeVar(bound_typevar) => visitor.visit(self, || {
|
||||||
Type::TypeVar(bound_typevar.normalized_impl(db, visitor))
|
Type::TypeVar(bound_typevar.normalized_impl(db, visitor))
|
||||||
}),
|
}),
|
||||||
Type::NonInferableTypeVar(bound_typevar) => visitor.visit(self, || {
|
|
||||||
Type::NonInferableTypeVar(bound_typevar.normalized_impl(db, visitor))
|
|
||||||
}),
|
|
||||||
Type::KnownInstance(known_instance) => visitor.visit(self, || {
|
Type::KnownInstance(known_instance) => visitor.visit(self, || {
|
||||||
Type::KnownInstance(known_instance.normalized_impl(db, visitor))
|
Type::KnownInstance(known_instance.normalized_impl(db, visitor))
|
||||||
}),
|
}),
|
||||||
|
|
@ -1453,7 +1444,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::Union(_)
|
| Type::Union(_)
|
||||||
| Type::Intersection(_)
|
| Type::Intersection(_)
|
||||||
| Type::Callable(_)
|
| Type::Callable(_)
|
||||||
| Type::NonInferableTypeVar(_)
|
|
||||||
| Type::TypeVar(_)
|
| Type::TypeVar(_)
|
||||||
| Type::BoundSuper(_)
|
| Type::BoundSuper(_)
|
||||||
| Type::TypeIs(_)
|
| Type::TypeIs(_)
|
||||||
|
|
@ -1544,7 +1534,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::KnownInstance(_)
|
| Type::KnownInstance(_)
|
||||||
| Type::PropertyInstance(_)
|
| Type::PropertyInstance(_)
|
||||||
| Type::Intersection(_)
|
| Type::Intersection(_)
|
||||||
| Type::NonInferableTypeVar(_)
|
|
||||||
| Type::TypeVar(_)
|
| Type::TypeVar(_)
|
||||||
| Type::BoundSuper(_) => None,
|
| Type::BoundSuper(_) => None,
|
||||||
}
|
}
|
||||||
|
|
@ -1729,18 +1718,21 @@ impl<'db> Type<'db> {
|
||||||
// However, there is one exception to this general rule: for any given typevar `T`,
|
// However, there is one exception to this general rule: for any given typevar `T`,
|
||||||
// `T` will always be a subtype of any union containing `T`.
|
// `T` will always be a subtype of any union containing `T`.
|
||||||
// A similar rule applies in reverse to intersection types.
|
// A similar rule applies in reverse to intersection types.
|
||||||
(Type::NonInferableTypeVar(_), Type::Union(union))
|
(Type::TypeVar(bound_typevar), Type::Union(union))
|
||||||
if union.elements(db).contains(&self) =>
|
if !bound_typevar.is_inferable(db, inferable)
|
||||||
|
&& union.elements(db).contains(&self) =>
|
||||||
{
|
{
|
||||||
ConstraintSet::from(true)
|
ConstraintSet::from(true)
|
||||||
}
|
}
|
||||||
(Type::Intersection(intersection), Type::NonInferableTypeVar(_))
|
(Type::Intersection(intersection), Type::TypeVar(bound_typevar))
|
||||||
if intersection.positive(db).contains(&target) =>
|
if !bound_typevar.is_inferable(db, inferable)
|
||||||
|
&& intersection.positive(db).contains(&target) =>
|
||||||
{
|
{
|
||||||
ConstraintSet::from(true)
|
ConstraintSet::from(true)
|
||||||
}
|
}
|
||||||
(Type::Intersection(intersection), Type::NonInferableTypeVar(_))
|
(Type::Intersection(intersection), Type::TypeVar(bound_typevar))
|
||||||
if intersection.negative(db).contains(&target) =>
|
if !bound_typevar.is_inferable(db, inferable)
|
||||||
|
&& intersection.negative(db).contains(&target) =>
|
||||||
{
|
{
|
||||||
ConstraintSet::from(false)
|
ConstraintSet::from(false)
|
||||||
}
|
}
|
||||||
|
|
@ -1750,18 +1742,19 @@ impl<'db> Type<'db> {
|
||||||
//
|
//
|
||||||
// Note that this is not handled by the early return at the beginning of this method,
|
// Note that this is not handled by the early return at the beginning of this method,
|
||||||
// since subtyping between a TypeVar and an arbitrary other type cannot be guaranteed to be reflexive.
|
// since subtyping between a TypeVar and an arbitrary other type cannot be guaranteed to be reflexive.
|
||||||
(
|
(Type::TypeVar(lhs_bound_typevar), Type::TypeVar(rhs_bound_typevar))
|
||||||
Type::NonInferableTypeVar(lhs_bound_typevar),
|
if !lhs_bound_typevar.is_inferable(db, inferable)
|
||||||
Type::NonInferableTypeVar(rhs_bound_typevar),
|
&& lhs_bound_typevar.identity(db) == rhs_bound_typevar.identity(db) =>
|
||||||
) if lhs_bound_typevar.identity(db) == rhs_bound_typevar.identity(db) => {
|
{
|
||||||
ConstraintSet::from(true)
|
ConstraintSet::from(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// A fully static typevar is a subtype of its upper bound, and to something similar to
|
// A fully static typevar is a subtype of its upper bound, and to something similar to
|
||||||
// the union of its constraints. An unbound, unconstrained, fully static typevar has an
|
// the union of its constraints. An unbound, unconstrained, fully static typevar has an
|
||||||
// implicit upper bound of `object` (which is handled above).
|
// implicit upper bound of `object` (which is handled above).
|
||||||
(Type::NonInferableTypeVar(bound_typevar), _)
|
(Type::TypeVar(bound_typevar), _)
|
||||||
if bound_typevar.typevar(db).bound_or_constraints(db).is_some() =>
|
if !bound_typevar.is_inferable(db, inferable)
|
||||||
|
&& bound_typevar.typevar(db).bound_or_constraints(db).is_some() =>
|
||||||
{
|
{
|
||||||
match bound_typevar.typevar(db).bound_or_constraints(db) {
|
match bound_typevar.typevar(db).bound_or_constraints(db) {
|
||||||
None => unreachable!(),
|
None => unreachable!(),
|
||||||
|
|
@ -1792,8 +1785,9 @@ impl<'db> Type<'db> {
|
||||||
// If the typevar is constrained, there must be multiple constraints, and the typevar
|
// If the typevar is constrained, there must be multiple constraints, and the typevar
|
||||||
// might be specialized to any one of them. However, the constraints do not have to be
|
// might be specialized to any one of them. However, the constraints do not have to be
|
||||||
// disjoint, which means an lhs type might be a subtype of all of the constraints.
|
// disjoint, which means an lhs type might be a subtype of all of the constraints.
|
||||||
(_, Type::NonInferableTypeVar(bound_typevar))
|
(_, Type::TypeVar(bound_typevar))
|
||||||
if !bound_typevar
|
if !bound_typevar.is_inferable(db, inferable)
|
||||||
|
&& !bound_typevar
|
||||||
.typevar(db)
|
.typevar(db)
|
||||||
.constraints(db)
|
.constraints(db)
|
||||||
.when_some_and(|constraints| {
|
.when_some_and(|constraints| {
|
||||||
|
|
@ -1831,7 +1825,9 @@ impl<'db> Type<'db> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
(Type::TypeVar(_), _) if relation.is_assignability() => {
|
(Type::TypeVar(bound_typevar), _)
|
||||||
|
if bound_typevar.is_inferable(db, inferable) && relation.is_assignability() =>
|
||||||
|
{
|
||||||
// The implicit lower bound of a typevar is `Never`, which means
|
// The implicit lower bound of a typevar is `Never`, which means
|
||||||
// that it is always assignable to any other type.
|
// that it is always assignable to any other type.
|
||||||
|
|
||||||
|
|
@ -1932,10 +1928,13 @@ impl<'db> Type<'db> {
|
||||||
// (If the typevar is bounded, it might be specialized to a smaller type than the
|
// (If the typevar is bounded, it might be specialized to a smaller type than the
|
||||||
// bound. This is true even if the bound is a final class, since the typevar can still
|
// bound. This is true even if the bound is a final class, since the typevar can still
|
||||||
// be specialized to `Never`.)
|
// be specialized to `Never`.)
|
||||||
(_, Type::NonInferableTypeVar(_)) => ConstraintSet::from(false),
|
(_, Type::TypeVar(bound_typevar)) if !bound_typevar.is_inferable(db, inferable) => {
|
||||||
|
ConstraintSet::from(false)
|
||||||
|
}
|
||||||
|
|
||||||
(_, Type::TypeVar(typevar))
|
(_, Type::TypeVar(typevar))
|
||||||
if relation.is_assignability()
|
if typevar.is_inferable(db, inferable)
|
||||||
|
&& relation.is_assignability()
|
||||||
&& typevar.typevar(db).upper_bound(db).is_none_or(|bound| {
|
&& typevar.typevar(db).upper_bound(db).is_none_or(|bound| {
|
||||||
!self
|
!self
|
||||||
.has_relation_to_impl(
|
.has_relation_to_impl(
|
||||||
|
|
@ -1964,7 +1963,11 @@ impl<'db> Type<'db> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Infer specializations here
|
// TODO: Infer specializations here
|
||||||
(Type::TypeVar(_), _) | (_, Type::TypeVar(_)) => ConstraintSet::from(false),
|
(Type::TypeVar(bound_typevar), _) | (_, Type::TypeVar(bound_typevar))
|
||||||
|
if bound_typevar.is_inferable(db, inferable) =>
|
||||||
|
{
|
||||||
|
ConstraintSet::from(false)
|
||||||
|
}
|
||||||
|
|
||||||
(Type::TypedDict(_), _) | (_, Type::TypedDict(_)) => {
|
(Type::TypedDict(_), _) | (_, Type::TypedDict(_)) => {
|
||||||
// TODO: Implement assignability and subtyping for TypedDict
|
// TODO: Implement assignability and subtyping for TypedDict
|
||||||
|
|
@ -2399,9 +2402,12 @@ impl<'db> Type<'db> {
|
||||||
|
|
||||||
// Other than the special cases enumerated above, `Instance` types and typevars are
|
// Other than the special cases enumerated above, `Instance` types and typevars are
|
||||||
// never subtypes of any other variants
|
// never subtypes of any other variants
|
||||||
(Type::NominalInstance(_) | Type::NonInferableTypeVar(_), _) => {
|
(Type::TypeVar(bound_typevar), _) => {
|
||||||
|
// All inferable cases should have been handled above
|
||||||
|
assert!(!bound_typevar.is_inferable(db, inferable));
|
||||||
ConstraintSet::from(false)
|
ConstraintSet::from(false)
|
||||||
}
|
}
|
||||||
|
(Type::NominalInstance(_), _) => ConstraintSet::from(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2633,16 +2639,17 @@ impl<'db> Type<'db> {
|
||||||
// be specialized to the same type. (This is an important difference between typevars
|
// be specialized to the same type. (This is an important difference between typevars
|
||||||
// and `Any`!) Different typevars might be disjoint, depending on their bounds and
|
// and `Any`!) Different typevars might be disjoint, depending on their bounds and
|
||||||
// constraints, which are handled below.
|
// constraints, which are handled below.
|
||||||
(
|
(Type::TypeVar(self_bound_typevar), Type::TypeVar(other_bound_typevar))
|
||||||
Type::NonInferableTypeVar(self_bound_typevar),
|
if !self_bound_typevar.is_inferable(db, inferable)
|
||||||
Type::NonInferableTypeVar(other_bound_typevar),
|
&& self_bound_typevar.identity(db) == other_bound_typevar.identity(db) =>
|
||||||
) if self_bound_typevar.identity(db) == other_bound_typevar.identity(db) => {
|
{
|
||||||
ConstraintSet::from(false)
|
ConstraintSet::from(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
(tvar @ Type::NonInferableTypeVar(_), Type::Intersection(intersection))
|
(tvar @ Type::TypeVar(bound_typevar), Type::Intersection(intersection))
|
||||||
| (Type::Intersection(intersection), tvar @ Type::NonInferableTypeVar(_))
|
| (Type::Intersection(intersection), tvar @ Type::TypeVar(bound_typevar))
|
||||||
if intersection.negative(db).contains(&tvar) =>
|
if !bound_typevar.is_inferable(db, inferable)
|
||||||
|
&& intersection.negative(db).contains(&tvar) =>
|
||||||
{
|
{
|
||||||
ConstraintSet::from(true)
|
ConstraintSet::from(true)
|
||||||
}
|
}
|
||||||
|
|
@ -2651,8 +2658,9 @@ impl<'db> Type<'db> {
|
||||||
// specialized to any type. A bounded typevar is not disjoint from its bound, and is
|
// specialized to any type. A bounded typevar is not disjoint from its bound, and is
|
||||||
// only disjoint from other types if its bound is. A constrained typevar is disjoint
|
// only disjoint from other types if its bound is. A constrained typevar is disjoint
|
||||||
// from a type if all of its constraints are.
|
// from a type if all of its constraints are.
|
||||||
(Type::NonInferableTypeVar(bound_typevar), other)
|
(Type::TypeVar(bound_typevar), other) | (other, Type::TypeVar(bound_typevar))
|
||||||
| (other, Type::NonInferableTypeVar(bound_typevar)) => {
|
if !bound_typevar.is_inferable(db, inferable) =>
|
||||||
|
{
|
||||||
match bound_typevar.typevar(db).bound_or_constraints(db) {
|
match bound_typevar.typevar(db).bound_or_constraints(db) {
|
||||||
None => ConstraintSet::from(false),
|
None => ConstraintSet::from(false),
|
||||||
Some(TypeVarBoundOrConstraints::UpperBound(bound)) => bound
|
Some(TypeVarBoundOrConstraints::UpperBound(bound)) => bound
|
||||||
|
|
@ -3300,7 +3308,7 @@ impl<'db> Type<'db> {
|
||||||
// the bound is a final singleton class, since it can still be specialized to `Never`.
|
// the bound is a final singleton class, since it can still be specialized to `Never`.
|
||||||
// A constrained typevar is a singleton if all of its constraints are singletons. (Note
|
// A constrained typevar is a singleton if all of its constraints are singletons. (Note
|
||||||
// that you cannot specialize a constrained typevar to a subtype of a constraint.)
|
// that you cannot specialize a constrained typevar to a subtype of a constraint.)
|
||||||
Type::NonInferableTypeVar(bound_typevar) => {
|
Type::TypeVar(bound_typevar) => {
|
||||||
match bound_typevar.typevar(db).bound_or_constraints(db) {
|
match bound_typevar.typevar(db).bound_or_constraints(db) {
|
||||||
None => false,
|
None => false,
|
||||||
Some(TypeVarBoundOrConstraints::UpperBound(_)) => false,
|
Some(TypeVarBoundOrConstraints::UpperBound(_)) => false,
|
||||||
|
|
@ -3311,8 +3319,6 @@ impl<'db> Type<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::TypeVar(_) => false,
|
|
||||||
|
|
||||||
// We eagerly transform `SubclassOf` to `ClassLiteral` for final types, so `SubclassOf` is never a singleton.
|
// We eagerly transform `SubclassOf` to `ClassLiteral` for final types, so `SubclassOf` is never a singleton.
|
||||||
Type::SubclassOf(..) => false,
|
Type::SubclassOf(..) => false,
|
||||||
Type::BoundSuper(..) => false,
|
Type::BoundSuper(..) => false,
|
||||||
|
|
@ -3411,7 +3417,7 @@ impl<'db> Type<'db> {
|
||||||
// `Never`. A constrained typevar is single-valued if all of its constraints are
|
// `Never`. A constrained typevar is single-valued if all of its constraints are
|
||||||
// single-valued. (Note that you cannot specialize a constrained typevar to a subtype
|
// single-valued. (Note that you cannot specialize a constrained typevar to a subtype
|
||||||
// of a constraint.)
|
// of a constraint.)
|
||||||
Type::NonInferableTypeVar(bound_typevar) => {
|
Type::TypeVar(bound_typevar) => {
|
||||||
match bound_typevar.typevar(db).bound_or_constraints(db) {
|
match bound_typevar.typevar(db).bound_or_constraints(db) {
|
||||||
None => false,
|
None => false,
|
||||||
Some(TypeVarBoundOrConstraints::UpperBound(_)) => false,
|
Some(TypeVarBoundOrConstraints::UpperBound(_)) => false,
|
||||||
|
|
@ -3422,8 +3428,6 @@ impl<'db> Type<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::TypeVar(_) => false,
|
|
||||||
|
|
||||||
Type::SubclassOf(..) => {
|
Type::SubclassOf(..) => {
|
||||||
// TODO: Same comment as above for `is_singleton`
|
// TODO: Same comment as above for `is_singleton`
|
||||||
false
|
false
|
||||||
|
|
@ -3588,7 +3592,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::LiteralString
|
| Type::LiteralString
|
||||||
| Type::BytesLiteral(_)
|
| Type::BytesLiteral(_)
|
||||||
| Type::EnumLiteral(_)
|
| Type::EnumLiteral(_)
|
||||||
| Type::NonInferableTypeVar(_)
|
|
||||||
| Type::TypeVar(_)
|
| Type::TypeVar(_)
|
||||||
| Type::NominalInstance(_)
|
| Type::NominalInstance(_)
|
||||||
| Type::ProtocolInstance(_)
|
| Type::ProtocolInstance(_)
|
||||||
|
|
@ -3699,7 +3702,7 @@ impl<'db> Type<'db> {
|
||||||
Type::object().instance_member(db, name)
|
Type::object().instance_member(db, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::NonInferableTypeVar(bound_typevar) => {
|
Type::TypeVar(bound_typevar) => {
|
||||||
match bound_typevar.typevar(db).bound_or_constraints(db) {
|
match bound_typevar.typevar(db).bound_or_constraints(db) {
|
||||||
None => Type::object().instance_member(db, name),
|
None => Type::object().instance_member(db, name),
|
||||||
Some(TypeVarBoundOrConstraints::UpperBound(bound)) => {
|
Some(TypeVarBoundOrConstraints::UpperBound(bound)) => {
|
||||||
|
|
@ -3712,16 +3715,6 @@ impl<'db> Type<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::TypeVar(_) => {
|
|
||||||
debug_assert!(
|
|
||||||
false,
|
|
||||||
"should not be able to access instance member `{name}` \
|
|
||||||
of type variable {} in inferable position",
|
|
||||||
self.display(db)
|
|
||||||
);
|
|
||||||
Place::Undefined.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
Type::IntLiteral(_) => KnownClass::Int.to_instance(db).instance_member(db, name),
|
Type::IntLiteral(_) => KnownClass::Int.to_instance(db).instance_member(db, name),
|
||||||
Type::BooleanLiteral(_) | Type::TypeIs(_) => {
|
Type::BooleanLiteral(_) | Type::TypeIs(_) => {
|
||||||
KnownClass::Bool.to_instance(db).instance_member(db, name)
|
KnownClass::Bool.to_instance(db).instance_member(db, name)
|
||||||
|
|
@ -4298,7 +4291,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::BytesLiteral(..)
|
| Type::BytesLiteral(..)
|
||||||
| Type::EnumLiteral(..)
|
| Type::EnumLiteral(..)
|
||||||
| Type::LiteralString
|
| Type::LiteralString
|
||||||
| Type::NonInferableTypeVar(..)
|
|
||||||
| Type::TypeVar(..)
|
| Type::TypeVar(..)
|
||||||
| Type::SpecialForm(..)
|
| Type::SpecialForm(..)
|
||||||
| Type::KnownInstance(..)
|
| Type::KnownInstance(..)
|
||||||
|
|
@ -4647,7 +4639,7 @@ impl<'db> Type<'db> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
Type::NonInferableTypeVar(bound_typevar) => {
|
Type::TypeVar(bound_typevar) => {
|
||||||
match bound_typevar.typevar(db).bound_or_constraints(db) {
|
match bound_typevar.typevar(db).bound_or_constraints(db) {
|
||||||
None => Truthiness::Ambiguous,
|
None => Truthiness::Ambiguous,
|
||||||
Some(TypeVarBoundOrConstraints::UpperBound(bound)) => {
|
Some(TypeVarBoundOrConstraints::UpperBound(bound)) => {
|
||||||
|
|
@ -4658,7 +4650,6 @@ impl<'db> Type<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::TypeVar(_) => Truthiness::Ambiguous,
|
|
||||||
|
|
||||||
Type::NominalInstance(instance) => instance
|
Type::NominalInstance(instance) => instance
|
||||||
.known_class(db)
|
.known_class(db)
|
||||||
|
|
@ -4757,7 +4748,7 @@ impl<'db> Type<'db> {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::NonInferableTypeVar(bound_typevar) => {
|
Type::TypeVar(bound_typevar) => {
|
||||||
match bound_typevar.typevar(db).bound_or_constraints(db) {
|
match bound_typevar.typevar(db).bound_or_constraints(db) {
|
||||||
None => CallableBinding::not_callable(self).into(),
|
None => CallableBinding::not_callable(self).into(),
|
||||||
Some(TypeVarBoundOrConstraints::UpperBound(bound)) => bound.bindings(db),
|
Some(TypeVarBoundOrConstraints::UpperBound(bound)) => bound.bindings(db),
|
||||||
|
|
@ -4770,15 +4761,6 @@ impl<'db> Type<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::TypeVar(_) => {
|
|
||||||
debug_assert!(
|
|
||||||
false,
|
|
||||||
"should not be able to call type variable {} in inferable position",
|
|
||||||
self.display(db)
|
|
||||||
);
|
|
||||||
CallableBinding::not_callable(self).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
Type::BoundMethod(bound_method) => {
|
Type::BoundMethod(bound_method) => {
|
||||||
let signature = bound_method.function(db).signature(db);
|
let signature = bound_method.function(db).signature(db);
|
||||||
CallableBinding::from_overloads(self, signature.overloads.iter().cloned())
|
CallableBinding::from_overloads(self, signature.overloads.iter().cloned())
|
||||||
|
|
@ -5635,16 +5617,12 @@ impl<'db> Type<'db> {
|
||||||
Type::TypeAlias(alias) => {
|
Type::TypeAlias(alias) => {
|
||||||
non_async_special_case(db, alias.value_type(db))
|
non_async_special_case(db, alias.value_type(db))
|
||||||
}
|
}
|
||||||
Type::NonInferableTypeVar(tvar) => match tvar.typevar(db).bound_or_constraints(db)? {
|
Type::TypeVar(tvar) => match tvar.typevar(db).bound_or_constraints(db)? {
|
||||||
TypeVarBoundOrConstraints::UpperBound(bound) => {
|
TypeVarBoundOrConstraints::UpperBound(bound) => {
|
||||||
non_async_special_case(db, bound)
|
non_async_special_case(db, bound)
|
||||||
}
|
}
|
||||||
TypeVarBoundOrConstraints::Constraints(union) => non_async_special_case(db, Type::Union(union)),
|
TypeVarBoundOrConstraints::Constraints(union) => non_async_special_case(db, Type::Union(union)),
|
||||||
},
|
},
|
||||||
Type::TypeVar(_) => unreachable!(
|
|
||||||
"should not be able to iterate over type variable {} in inferable position",
|
|
||||||
ty.display(db)
|
|
||||||
),
|
|
||||||
Type::Union(union) => {
|
Type::Union(union) => {
|
||||||
let elements = union.elements(db);
|
let elements = union.elements(db);
|
||||||
if elements.len() < MAX_TUPLE_LENGTH {
|
if elements.len() < MAX_TUPLE_LENGTH {
|
||||||
|
|
@ -6040,7 +6018,7 @@ impl<'db> Type<'db> {
|
||||||
// It is important that identity_specialization specializes the class with
|
// It is important that identity_specialization specializes the class with
|
||||||
// _inferable_ typevars, so that our specialization inference logic will
|
// _inferable_ typevars, so that our specialization inference logic will
|
||||||
// try to find a specialization for them.
|
// try to find a specialization for them.
|
||||||
Type::from(class.identity_specialization(db, &Type::TypeVar)),
|
Type::from(class.identity_specialization(db)),
|
||||||
),
|
),
|
||||||
_ => (None, None, self),
|
_ => (None, None, self),
|
||||||
},
|
},
|
||||||
|
|
@ -6193,9 +6171,6 @@ impl<'db> Type<'db> {
|
||||||
// If there is no bound or constraints on a typevar `T`, `T: object` implicitly, which
|
// If there is no bound or constraints on a typevar `T`, `T: object` implicitly, which
|
||||||
// has no instance type. Otherwise, synthesize a typevar with bound or constraints
|
// has no instance type. Otherwise, synthesize a typevar with bound or constraints
|
||||||
// mapped through `to_instance`.
|
// mapped through `to_instance`.
|
||||||
Type::NonInferableTypeVar(bound_typevar) => {
|
|
||||||
Some(Type::NonInferableTypeVar(bound_typevar.to_instance(db)?))
|
|
||||||
}
|
|
||||||
Type::TypeVar(bound_typevar) => Some(Type::TypeVar(bound_typevar.to_instance(db)?)),
|
Type::TypeVar(bound_typevar) => Some(Type::TypeVar(bound_typevar.to_instance(db)?)),
|
||||||
Type::TypeAlias(alias) => alias.value_type(db).to_instance(db),
|
Type::TypeAlias(alias) => alias.value_type(db).to_instance(db),
|
||||||
Type::Intersection(_) => Some(todo_type!("Type::Intersection.to_instance")),
|
Type::Intersection(_) => Some(todo_type!("Type::Intersection.to_instance")),
|
||||||
|
|
@ -6279,7 +6254,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::LiteralString
|
| Type::LiteralString
|
||||||
| Type::ModuleLiteral(_)
|
| Type::ModuleLiteral(_)
|
||||||
| Type::StringLiteral(_)
|
| Type::StringLiteral(_)
|
||||||
| Type::NonInferableTypeVar(_)
|
|
||||||
| Type::TypeVar(_)
|
| Type::TypeVar(_)
|
||||||
| Type::Callable(_)
|
| Type::Callable(_)
|
||||||
| Type::BoundMethod(_)
|
| Type::BoundMethod(_)
|
||||||
|
|
@ -6311,7 +6285,7 @@ impl<'db> Type<'db> {
|
||||||
typevar_binding_context,
|
typevar_binding_context,
|
||||||
*typevar,
|
*typevar,
|
||||||
)
|
)
|
||||||
.map(Type::NonInferableTypeVar)
|
.map(Type::TypeVar)
|
||||||
.unwrap_or(*self))
|
.unwrap_or(*self))
|
||||||
}
|
}
|
||||||
KnownInstanceType::Deprecated(_) => Err(InvalidTypeExpressionError {
|
KnownInstanceType::Deprecated(_) => Err(InvalidTypeExpressionError {
|
||||||
|
|
@ -6388,14 +6362,7 @@ impl<'db> Type<'db> {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(typing_self(
|
Ok(typing_self(db, scope_id, typevar_binding_context, class).unwrap_or(*self))
|
||||||
db,
|
|
||||||
scope_id,
|
|
||||||
typevar_binding_context,
|
|
||||||
class,
|
|
||||||
&Type::NonInferableTypeVar,
|
|
||||||
)
|
|
||||||
.unwrap_or(*self))
|
|
||||||
}
|
}
|
||||||
SpecialFormType::TypeAlias => Ok(Type::Dynamic(DynamicType::TodoTypeAlias)),
|
SpecialFormType::TypeAlias => Ok(Type::Dynamic(DynamicType::TodoTypeAlias)),
|
||||||
SpecialFormType::TypedDict => Err(InvalidTypeExpressionError {
|
SpecialFormType::TypedDict => Err(InvalidTypeExpressionError {
|
||||||
|
|
@ -6565,7 +6532,7 @@ impl<'db> Type<'db> {
|
||||||
}
|
}
|
||||||
Type::Callable(_) | Type::DataclassTransformer(_) => KnownClass::Type.to_instance(db),
|
Type::Callable(_) | Type::DataclassTransformer(_) => KnownClass::Type.to_instance(db),
|
||||||
Type::ModuleLiteral(_) => KnownClass::ModuleType.to_class_literal(db),
|
Type::ModuleLiteral(_) => KnownClass::ModuleType.to_class_literal(db),
|
||||||
Type::NonInferableTypeVar(bound_typevar) => {
|
Type::TypeVar(bound_typevar) => {
|
||||||
match bound_typevar.typevar(db).bound_or_constraints(db) {
|
match bound_typevar.typevar(db).bound_or_constraints(db) {
|
||||||
None => KnownClass::Type.to_instance(db),
|
None => KnownClass::Type.to_instance(db),
|
||||||
Some(TypeVarBoundOrConstraints::UpperBound(bound)) => bound.to_meta_type(db),
|
Some(TypeVarBoundOrConstraints::UpperBound(bound)) => bound.to_meta_type(db),
|
||||||
|
|
@ -6576,7 +6543,6 @@ impl<'db> Type<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::TypeVar(_) => KnownClass::Type.to_instance(db),
|
|
||||||
|
|
||||||
Type::ClassLiteral(class) => class.metaclass(db),
|
Type::ClassLiteral(class) => class.metaclass(db),
|
||||||
Type::GenericAlias(alias) => ClassType::from(alias).metaclass(db),
|
Type::GenericAlias(alias) => ClassType::from(alias).metaclass(db),
|
||||||
|
|
@ -6710,36 +6676,12 @@ impl<'db> Type<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TypeMapping::PromoteLiterals
|
TypeMapping::PromoteLiterals
|
||||||
| TypeMapping::BindLegacyTypevars(_)
|
| TypeMapping::BindLegacyTypevars(_) => self,
|
||||||
| TypeMapping::MarkTypeVarsInferable(_) => self,
|
|
||||||
TypeMapping::Materialize(materialization_kind) => {
|
TypeMapping::Materialize(materialization_kind) => {
|
||||||
Type::TypeVar(bound_typevar.materialize_impl(db, *materialization_kind, visitor))
|
Type::TypeVar(bound_typevar.materialize_impl(db, *materialization_kind, visitor))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::NonInferableTypeVar(bound_typevar) => match type_mapping {
|
|
||||||
TypeMapping::Specialization(specialization) => {
|
|
||||||
specialization.get(db, bound_typevar).unwrap_or(self)
|
|
||||||
}
|
|
||||||
TypeMapping::PartialSpecialization(partial) => {
|
|
||||||
partial.get(db, bound_typevar).unwrap_or(self)
|
|
||||||
}
|
|
||||||
TypeMapping::MarkTypeVarsInferable(binding_context) => {
|
|
||||||
if binding_context.is_none_or(|context| context == bound_typevar.binding_context(db)) {
|
|
||||||
Type::TypeVar(bound_typevar.mark_typevars_inferable(db, visitor))
|
|
||||||
} else {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TypeMapping::PromoteLiterals
|
|
||||||
| TypeMapping::BindLegacyTypevars(_)
|
|
||||||
| TypeMapping::BindSelf(_)
|
|
||||||
| TypeMapping::ReplaceSelf { .. }
|
|
||||||
=> self,
|
|
||||||
TypeMapping::Materialize(materialization_kind) => Type::NonInferableTypeVar(bound_typevar.materialize_impl(db, *materialization_kind, visitor))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Type::KnownInstance(KnownInstanceType::TypeVar(typevar)) => match type_mapping {
|
Type::KnownInstance(KnownInstanceType::TypeVar(typevar)) => match type_mapping {
|
||||||
TypeMapping::BindLegacyTypevars(binding_context) => {
|
TypeMapping::BindLegacyTypevars(binding_context) => {
|
||||||
Type::TypeVar(BoundTypeVarInstance::new(db, typevar, *binding_context))
|
Type::TypeVar(BoundTypeVarInstance::new(db, typevar, *binding_context))
|
||||||
|
|
@ -6749,7 +6691,6 @@ impl<'db> Type<'db> {
|
||||||
TypeMapping::PromoteLiterals |
|
TypeMapping::PromoteLiterals |
|
||||||
TypeMapping::BindSelf(_) |
|
TypeMapping::BindSelf(_) |
|
||||||
TypeMapping::ReplaceSelf { .. } |
|
TypeMapping::ReplaceSelf { .. } |
|
||||||
TypeMapping::MarkTypeVarsInferable(_) |
|
|
||||||
TypeMapping::Materialize(_) => self,
|
TypeMapping::Materialize(_) => self,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -6864,7 +6805,6 @@ impl<'db> Type<'db> {
|
||||||
TypeMapping::BindLegacyTypevars(_) |
|
TypeMapping::BindLegacyTypevars(_) |
|
||||||
TypeMapping::BindSelf(_) |
|
TypeMapping::BindSelf(_) |
|
||||||
TypeMapping::ReplaceSelf { .. } |
|
TypeMapping::ReplaceSelf { .. } |
|
||||||
TypeMapping::MarkTypeVarsInferable(_) |
|
|
||||||
TypeMapping::Materialize(_) => self,
|
TypeMapping::Materialize(_) => self,
|
||||||
TypeMapping::PromoteLiterals => self.promote_literals_impl(db, tcx)
|
TypeMapping::PromoteLiterals => self.promote_literals_impl(db, tcx)
|
||||||
}
|
}
|
||||||
|
|
@ -6875,7 +6815,6 @@ impl<'db> Type<'db> {
|
||||||
TypeMapping::BindLegacyTypevars(_) |
|
TypeMapping::BindLegacyTypevars(_) |
|
||||||
TypeMapping::BindSelf(_) |
|
TypeMapping::BindSelf(_) |
|
||||||
TypeMapping::ReplaceSelf { .. } |
|
TypeMapping::ReplaceSelf { .. } |
|
||||||
TypeMapping::MarkTypeVarsInferable(_) |
|
|
||||||
TypeMapping::PromoteLiterals => self,
|
TypeMapping::PromoteLiterals => self,
|
||||||
TypeMapping::Materialize(materialization_kind) => match materialization_kind {
|
TypeMapping::Materialize(materialization_kind) => match materialization_kind {
|
||||||
MaterializationKind::Top => Type::object(),
|
MaterializationKind::Top => Type::object(),
|
||||||
|
|
@ -6925,7 +6864,7 @@ impl<'db> Type<'db> {
|
||||||
visitor: &FindLegacyTypeVarsVisitor<'db>,
|
visitor: &FindLegacyTypeVarsVisitor<'db>,
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
Type::NonInferableTypeVar(bound_typevar) | Type::TypeVar(bound_typevar) => {
|
Type::TypeVar(bound_typevar) => {
|
||||||
if matches!(
|
if matches!(
|
||||||
bound_typevar.typevar(db).kind(db),
|
bound_typevar.typevar(db).kind(db),
|
||||||
TypeVarKind::Legacy | TypeVarKind::TypingSelf
|
TypeVarKind::Legacy | TypeVarKind::TypingSelf
|
||||||
|
|
@ -7157,7 +7096,6 @@ impl<'db> Type<'db> {
|
||||||
| Self::PropertyInstance(_)
|
| Self::PropertyInstance(_)
|
||||||
| Self::BoundSuper(_) => self.to_meta_type(db).definition(db),
|
| Self::BoundSuper(_) => self.to_meta_type(db).definition(db),
|
||||||
|
|
||||||
Self::NonInferableTypeVar(bound_typevar) |
|
|
||||||
Self::TypeVar(bound_typevar) => Some(TypeDefinition::TypeVar(bound_typevar.typevar(db).definition(db)?)),
|
Self::TypeVar(bound_typevar) => Some(TypeDefinition::TypeVar(bound_typevar.typevar(db).definition(db)?)),
|
||||||
|
|
||||||
Self::ProtocolInstance(protocol) => match protocol.inner {
|
Self::ProtocolInstance(protocol) => match protocol.inner {
|
||||||
|
|
@ -7299,9 +7237,7 @@ impl<'db> VarianceInferable<'db> for Type<'db> {
|
||||||
Type::GenericAlias(generic_alias) => generic_alias.variance_of(db, typevar),
|
Type::GenericAlias(generic_alias) => generic_alias.variance_of(db, typevar),
|
||||||
Type::Callable(callable_type) => callable_type.signatures(db).variance_of(db, typevar),
|
Type::Callable(callable_type) => callable_type.signatures(db).variance_of(db, typevar),
|
||||||
// A type variable is always covariant in itself.
|
// A type variable is always covariant in itself.
|
||||||
Type::TypeVar(other_typevar) | Type::NonInferableTypeVar(other_typevar)
|
Type::TypeVar(other_typevar) if other_typevar == typevar => {
|
||||||
if other_typevar == typevar =>
|
|
||||||
{
|
|
||||||
// type variables are covariant in themselves
|
// type variables are covariant in themselves
|
||||||
TypeVarVariance::Covariant
|
TypeVarVariance::Covariant
|
||||||
}
|
}
|
||||||
|
|
@ -7357,7 +7293,6 @@ impl<'db> VarianceInferable<'db> for Type<'db> {
|
||||||
| Type::AlwaysTruthy
|
| Type::AlwaysTruthy
|
||||||
| Type::BoundSuper(_)
|
| Type::BoundSuper(_)
|
||||||
| Type::TypeVar(_)
|
| Type::TypeVar(_)
|
||||||
| Type::NonInferableTypeVar(_)
|
|
||||||
| Type::TypedDict(_)
|
| Type::TypedDict(_)
|
||||||
| Type::TypeAlias(_) => TypeVarVariance::Bivariant,
|
| Type::TypeAlias(_) => TypeVarVariance::Bivariant,
|
||||||
};
|
};
|
||||||
|
|
@ -7430,17 +7365,6 @@ pub enum TypeMapping<'a, 'db> {
|
||||||
BindSelf(Type<'db>),
|
BindSelf(Type<'db>),
|
||||||
/// Replaces occurrences of `typing.Self` with a new `Self` type variable with the given upper bound.
|
/// Replaces occurrences of `typing.Self` with a new `Self` type variable with the given upper bound.
|
||||||
ReplaceSelf { new_upper_bound: Type<'db> },
|
ReplaceSelf { new_upper_bound: Type<'db> },
|
||||||
/// Marks type variables as inferable.
|
|
||||||
///
|
|
||||||
/// When we create the signature for a generic function, we mark its type variables as inferable. Since
|
|
||||||
/// the generic function might reference type variables from enclosing generic scopes, we include the
|
|
||||||
/// function's binding context in order to only mark those type variables as inferable that are actually
|
|
||||||
/// bound by that function.
|
|
||||||
///
|
|
||||||
/// When the parameter is set to `None`, *all* type variables will be marked as inferable. We use this
|
|
||||||
/// variant when descending into the bounds and/or constraints, and the default value of a type variable,
|
|
||||||
/// which may include nested type variables (`Self` has a bound of `C[T]` for a generic class `C[T]`).
|
|
||||||
MarkTypeVarsInferable(Option<BindingContext<'db>>),
|
|
||||||
/// Create the top or bottom materialization of a type.
|
/// Create the top or bottom materialization of a type.
|
||||||
Materialize(MaterializationKind),
|
Materialize(MaterializationKind),
|
||||||
}
|
}
|
||||||
|
|
@ -7457,7 +7381,6 @@ impl<'db> TypeMapping<'_, 'db> {
|
||||||
| TypeMapping::PartialSpecialization(_)
|
| TypeMapping::PartialSpecialization(_)
|
||||||
| TypeMapping::PromoteLiterals
|
| TypeMapping::PromoteLiterals
|
||||||
| TypeMapping::BindLegacyTypevars(_)
|
| TypeMapping::BindLegacyTypevars(_)
|
||||||
| TypeMapping::MarkTypeVarsInferable(_)
|
|
||||||
| TypeMapping::Materialize(_) => context,
|
| TypeMapping::Materialize(_) => context,
|
||||||
TypeMapping::BindSelf(_) => GenericContext::from_typevar_instances(
|
TypeMapping::BindSelf(_) => GenericContext::from_typevar_instances(
|
||||||
db,
|
db,
|
||||||
|
|
@ -8344,48 +8267,6 @@ impl<'db> TypeVarInstance<'db> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mark_typevars_inferable(
|
|
||||||
self,
|
|
||||||
db: &'db dyn Db,
|
|
||||||
visitor: &ApplyTypeMappingVisitor<'db>,
|
|
||||||
) -> Self {
|
|
||||||
// Type variables can have nested type variables in their bounds, constraints, or default value.
|
|
||||||
// When we mark a type variable as inferable, we also mark all of these nested type variables as
|
|
||||||
// inferable, so we set the parameter to `None` here.
|
|
||||||
let type_mapping = &TypeMapping::MarkTypeVarsInferable(None);
|
|
||||||
|
|
||||||
let new_bound_or_constraints =
|
|
||||||
self._bound_or_constraints(db)
|
|
||||||
.map(|bound_or_constraints| match bound_or_constraints {
|
|
||||||
TypeVarBoundOrConstraintsEvaluation::Eager(bound_or_constraints) => {
|
|
||||||
bound_or_constraints
|
|
||||||
.mark_typevars_inferable(db, visitor)
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
TypeVarBoundOrConstraintsEvaluation::LazyUpperBound
|
|
||||||
| TypeVarBoundOrConstraintsEvaluation::LazyConstraints => bound_or_constraints,
|
|
||||||
});
|
|
||||||
|
|
||||||
let new_default = self._default(db).and_then(|default| match default {
|
|
||||||
TypeVarDefaultEvaluation::Eager(ty) => Some(
|
|
||||||
ty.apply_type_mapping_impl(db, type_mapping, TypeContext::default(), visitor)
|
|
||||||
.into(),
|
|
||||||
),
|
|
||||||
TypeVarDefaultEvaluation::Lazy => self.lazy_default(db).map(|ty| {
|
|
||||||
ty.apply_type_mapping_impl(db, type_mapping, TypeContext::default(), visitor)
|
|
||||||
.into()
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
Self::new(
|
|
||||||
db,
|
|
||||||
self.identity(db),
|
|
||||||
new_bound_or_constraints,
|
|
||||||
self.explicit_variance(db),
|
|
||||||
new_default,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_instance(self, db: &'db dyn Db) -> Option<Self> {
|
fn to_instance(self, db: &'db dyn Db) -> Option<Self> {
|
||||||
let bound_or_constraints = match self.bound_or_constraints(db)? {
|
let bound_or_constraints = match self.bound_or_constraints(db)? {
|
||||||
TypeVarBoundOrConstraints::UpperBound(upper_bound) => {
|
TypeVarBoundOrConstraints::UpperBound(upper_bound) => {
|
||||||
|
|
@ -8543,7 +8424,7 @@ impl<'db> BindingContext<'db> {
|
||||||
/// independent of the typevar's bounds or constraints. Two bound typevars have the same identity
|
/// independent of the typevar's bounds or constraints. Two bound typevars have the same identity
|
||||||
/// if they represent the same logical typevar bound in the same context, even if their bounds
|
/// if they represent the same logical typevar bound in the same context, even if their bounds
|
||||||
/// have been materialized differently.
|
/// have been materialized differently.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, get_size2::GetSize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, get_size2::GetSize, salsa::Update)]
|
||||||
pub struct BoundTypeVarIdentity<'db> {
|
pub struct BoundTypeVarIdentity<'db> {
|
||||||
pub(crate) identity: TypeVarIdentity<'db>,
|
pub(crate) identity: TypeVarIdentity<'db>,
|
||||||
pub(crate) binding_context: BindingContext<'db>,
|
pub(crate) binding_context: BindingContext<'db>,
|
||||||
|
|
@ -8708,18 +8589,6 @@ impl<'db> BoundTypeVarInstance<'db> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mark_typevars_inferable(
|
|
||||||
self,
|
|
||||||
db: &'db dyn Db,
|
|
||||||
visitor: &ApplyTypeMappingVisitor<'db>,
|
|
||||||
) -> Self {
|
|
||||||
Self::new(
|
|
||||||
db,
|
|
||||||
self.typevar(db).mark_typevars_inferable(db, visitor),
|
|
||||||
self.binding_context(db),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_instance(self, db: &'db dyn Db) -> Option<Self> {
|
fn to_instance(self, db: &'db dyn Db) -> Option<Self> {
|
||||||
Some(Self::new(
|
Some(Self::new(
|
||||||
db,
|
db,
|
||||||
|
|
@ -8825,38 +8694,6 @@ impl<'db> TypeVarBoundOrConstraints<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mark_typevars_inferable(
|
|
||||||
self,
|
|
||||||
db: &'db dyn Db,
|
|
||||||
visitor: &ApplyTypeMappingVisitor<'db>,
|
|
||||||
) -> Self {
|
|
||||||
let type_mapping = &TypeMapping::MarkTypeVarsInferable(None);
|
|
||||||
|
|
||||||
match self {
|
|
||||||
TypeVarBoundOrConstraints::UpperBound(bound) => TypeVarBoundOrConstraints::UpperBound(
|
|
||||||
bound.apply_type_mapping_impl(db, type_mapping, TypeContext::default(), visitor),
|
|
||||||
),
|
|
||||||
TypeVarBoundOrConstraints::Constraints(constraints) => {
|
|
||||||
TypeVarBoundOrConstraints::Constraints(UnionType::new(
|
|
||||||
db,
|
|
||||||
constraints
|
|
||||||
.elements(db)
|
|
||||||
.iter()
|
|
||||||
.map(|ty| {
|
|
||||||
ty.apply_type_mapping_impl(
|
|
||||||
db,
|
|
||||||
type_mapping,
|
|
||||||
TypeContext::default(),
|
|
||||||
visitor,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.into_boxed_slice(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error returned if a type is not awaitable.
|
/// Error returned if a type is not awaitable.
|
||||||
|
|
|
||||||
|
|
@ -343,7 +343,7 @@ impl<'db> BoundSuperType<'db> {
|
||||||
Type::TypeAlias(alias) => {
|
Type::TypeAlias(alias) => {
|
||||||
return delegate_with_error_mapped(alias.value_type(db), None);
|
return delegate_with_error_mapped(alias.value_type(db), None);
|
||||||
}
|
}
|
||||||
Type::TypeVar(type_var) | Type::NonInferableTypeVar(type_var) => {
|
Type::TypeVar(type_var) => {
|
||||||
let type_var = type_var.typevar(db);
|
let type_var = type_var.typevar(db);
|
||||||
return match type_var.bound_or_constraints(db) {
|
return match type_var.bound_or_constraints(db) {
|
||||||
Some(TypeVarBoundOrConstraints::UpperBound(bound)) => {
|
Some(TypeVarBoundOrConstraints::UpperBound(bound)) => {
|
||||||
|
|
|
||||||
|
|
@ -1062,8 +1062,7 @@ impl<'db> InnerIntersectionBuilder<'db> {
|
||||||
let mut positive_to_remove = SmallVec::<[usize; 1]>::new();
|
let mut positive_to_remove = SmallVec::<[usize; 1]>::new();
|
||||||
|
|
||||||
for (typevar_index, ty) in self.positive.iter().enumerate() {
|
for (typevar_index, ty) in self.positive.iter().enumerate() {
|
||||||
let (Type::NonInferableTypeVar(bound_typevar) | Type::TypeVar(bound_typevar)) = ty
|
let Type::TypeVar(bound_typevar) = ty else {
|
||||||
else {
|
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let Some(TypeVarBoundOrConstraints::Constraints(constraints)) =
|
let Some(TypeVarBoundOrConstraints::Constraints(constraints)) =
|
||||||
|
|
|
||||||
|
|
@ -2589,7 +2589,7 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Use the list of inferable typevars from the generic context of the callable.
|
self.inferable_typevars = generic_context.inferable_typevars(self.db);
|
||||||
let mut builder = SpecializationBuilder::new(self.db, self.inferable_typevars);
|
let mut builder = SpecializationBuilder::new(self.db, self.inferable_typevars);
|
||||||
|
|
||||||
let parameters = self.signature.parameters();
|
let parameters = self.signature.parameters();
|
||||||
|
|
|
||||||
|
|
@ -1627,15 +1627,10 @@ impl<'db> ClassLiteral<'db> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a specialization of this class where each typevar is mapped to itself. The second
|
/// Returns a specialization of this class where each typevar is mapped to itself.
|
||||||
/// parameter can be `Type::TypeVar` or `Type::NonInferableTypeVar`, depending on the use case.
|
pub(crate) fn identity_specialization(self, db: &'db dyn Db) -> ClassType<'db> {
|
||||||
pub(crate) fn identity_specialization(
|
|
||||||
self,
|
|
||||||
db: &'db dyn Db,
|
|
||||||
typevar_to_type: &impl Fn(BoundTypeVarInstance<'db>) -> Type<'db>,
|
|
||||||
) -> ClassType<'db> {
|
|
||||||
self.apply_specialization(db, |generic_context| {
|
self.apply_specialization(db, |generic_context| {
|
||||||
generic_context.identity_specialization(db, typevar_to_type)
|
generic_context.identity_specialization(db)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -155,7 +155,6 @@ impl<'db> ClassBase<'db> {
|
||||||
| Type::StringLiteral(_)
|
| Type::StringLiteral(_)
|
||||||
| Type::LiteralString
|
| Type::LiteralString
|
||||||
| Type::ModuleLiteral(_)
|
| Type::ModuleLiteral(_)
|
||||||
| Type::NonInferableTypeVar(_)
|
|
||||||
| Type::TypeVar(_)
|
| Type::TypeVar(_)
|
||||||
| Type::BoundSuper(_)
|
| Type::BoundSuper(_)
|
||||||
| Type::ProtocolInstance(_)
|
| Type::ProtocolInstance(_)
|
||||||
|
|
|
||||||
|
|
@ -560,9 +560,7 @@ impl Display for DisplayRepresentation<'_> {
|
||||||
.display_with(self.db, self.settings.clone()),
|
.display_with(self.db, self.settings.clone()),
|
||||||
literal_name = enum_literal.name(self.db)
|
literal_name = enum_literal.name(self.db)
|
||||||
),
|
),
|
||||||
Type::NonInferableTypeVar(bound_typevar) | Type::TypeVar(bound_typevar) => {
|
Type::TypeVar(bound_typevar) => bound_typevar.identity(self.db).display(self.db).fmt(f),
|
||||||
bound_typevar.identity(self.db).display(self.db).fmt(f)
|
|
||||||
}
|
|
||||||
Type::AlwaysTruthy => f.write_str("AlwaysTruthy"),
|
Type::AlwaysTruthy => f.write_str("AlwaysTruthy"),
|
||||||
Type::AlwaysFalsy => f.write_str("AlwaysFalsy"),
|
Type::AlwaysFalsy => f.write_str("AlwaysFalsy"),
|
||||||
Type::BoundSuper(bound_super) => {
|
Type::BoundSuper(bound_super) => {
|
||||||
|
|
|
||||||
|
|
@ -365,28 +365,12 @@ impl<'db> OverloadLiteral<'db> {
|
||||||
if function_node.is_async && !is_generator {
|
if function_node.is_async && !is_generator {
|
||||||
signature = signature.wrap_coroutine_return_type(db);
|
signature = signature.wrap_coroutine_return_type(db);
|
||||||
}
|
}
|
||||||
signature = signature.mark_typevars_inferable(db);
|
|
||||||
|
|
||||||
let pep695_ctx = function_node.type_params.as_ref().map(|type_params| {
|
|
||||||
GenericContext::from_type_params(db, index, self.definition(db), type_params)
|
|
||||||
});
|
|
||||||
let legacy_ctx = GenericContext::from_function_params(
|
|
||||||
db,
|
|
||||||
self.definition(db),
|
|
||||||
signature.parameters(),
|
|
||||||
signature.return_ty,
|
|
||||||
);
|
|
||||||
// We need to update `signature.generic_context` here,
|
|
||||||
// because type variables in `GenericContext::variables` are still non-inferable.
|
|
||||||
signature.generic_context =
|
|
||||||
GenericContext::merge_pep695_and_legacy(db, pep695_ctx, legacy_ctx);
|
|
||||||
|
|
||||||
signature
|
signature
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Typed internally-visible "raw" signature for this function.
|
/// Typed internally-visible "raw" signature for this function.
|
||||||
/// That is, type variables in parameter types and the return type remain non-inferable,
|
/// That is, the return types of async functions are not wrapped in `CoroutineType[...]`.
|
||||||
/// and the return types of async functions are not wrapped in `CoroutineType[...]`.
|
|
||||||
///
|
///
|
||||||
/// ## Warning
|
/// ## Warning
|
||||||
///
|
///
|
||||||
|
|
@ -1133,7 +1117,6 @@ fn is_instance_truthiness<'db>(
|
||||||
| Type::PropertyInstance(..)
|
| Type::PropertyInstance(..)
|
||||||
| Type::AlwaysTruthy
|
| Type::AlwaysTruthy
|
||||||
| Type::AlwaysFalsy
|
| Type::AlwaysFalsy
|
||||||
| Type::NonInferableTypeVar(..)
|
|
||||||
| Type::TypeVar(..)
|
| Type::TypeVar(..)
|
||||||
| Type::BoundSuper(..)
|
| Type::BoundSuper(..)
|
||||||
| Type::TypeIs(..)
|
| Type::TypeIs(..)
|
||||||
|
|
@ -1729,11 +1712,7 @@ impl KnownFunction {
|
||||||
}
|
}
|
||||||
|
|
||||||
KnownFunction::RangeConstraint => {
|
KnownFunction::RangeConstraint => {
|
||||||
let [
|
let [Some(lower), Some(Type::TypeVar(typevar)), Some(upper)] = parameter_types
|
||||||
Some(lower),
|
|
||||||
Some(Type::NonInferableTypeVar(typevar)),
|
|
||||||
Some(upper),
|
|
||||||
] = parameter_types
|
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
@ -1746,11 +1725,7 @@ impl KnownFunction {
|
||||||
}
|
}
|
||||||
|
|
||||||
KnownFunction::NegatedRangeConstraint => {
|
KnownFunction::NegatedRangeConstraint => {
|
||||||
let [
|
let [Some(lower), Some(Type::TypeVar(typevar)), Some(upper)] = parameter_types
|
||||||
Some(lower),
|
|
||||||
Some(Type::NonInferableTypeVar(typevar)),
|
|
||||||
Some(upper),
|
|
||||||
] = parameter_types
|
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
use std::marker::PhantomData;
|
use std::cell::RefCell;
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use ruff_python_ast as ast;
|
use ruff_python_ast as ast;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
use crate::semantic_index::definition::Definition;
|
use crate::semantic_index::definition::Definition;
|
||||||
use crate::semantic_index::scope::{FileScopeId, NodeWithScopeKind, ScopeId};
|
use crate::semantic_index::scope::{FileScopeId, NodeWithScopeKind, ScopeId};
|
||||||
|
|
@ -14,14 +15,16 @@ use crate::types::infer::infer_definition_types;
|
||||||
use crate::types::instance::{Protocol, ProtocolInstanceType};
|
use crate::types::instance::{Protocol, ProtocolInstanceType};
|
||||||
use crate::types::signatures::{Parameter, Parameters, Signature};
|
use crate::types::signatures::{Parameter, Parameters, Signature};
|
||||||
use crate::types::tuple::{TupleSpec, TupleType, walk_tuple_type};
|
use crate::types::tuple::{TupleSpec, TupleType, walk_tuple_type};
|
||||||
|
use crate::types::visitor::{NonAtomicType, TypeKind, TypeVisitor, walk_non_atomic_type};
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
ApplyTypeMappingVisitor, BoundTypeVarIdentity, BoundTypeVarInstance, ClassLiteral,
|
ApplyTypeMappingVisitor, BoundTypeVarIdentity, BoundTypeVarInstance, ClassLiteral,
|
||||||
FindLegacyTypeVarsVisitor, HasRelationToVisitor, IsDisjointVisitor, IsEquivalentVisitor,
|
FindLegacyTypeVarsVisitor, HasRelationToVisitor, IsDisjointVisitor, IsEquivalentVisitor,
|
||||||
KnownClass, KnownInstanceType, MaterializationKind, NormalizedVisitor, Type, TypeContext,
|
KnownClass, KnownInstanceType, MaterializationKind, NormalizedVisitor, Type, TypeContext,
|
||||||
TypeMapping, TypeRelation, TypeVarBoundOrConstraints, TypeVarIdentity, TypeVarInstance,
|
TypeMapping, TypeRelation, TypeVarBoundOrConstraints, TypeVarIdentity, TypeVarInstance,
|
||||||
TypeVarKind, TypeVarVariance, UnionType, binding_type, declaration_type,
|
TypeVarKind, TypeVarVariance, UnionType, binding_type, declaration_type,
|
||||||
|
walk_bound_type_var_type,
|
||||||
};
|
};
|
||||||
use crate::{Db, FxOrderMap, FxOrderSet};
|
use crate::{Db, FxIndexSet, FxOrderMap, FxOrderSet};
|
||||||
|
|
||||||
/// Returns an iterator of any generic context introduced by the given scope or any enclosing
|
/// Returns an iterator of any generic context introduced by the given scope or any enclosing
|
||||||
/// scope.
|
/// scope.
|
||||||
|
|
@ -106,7 +109,6 @@ pub(crate) fn typing_self<'db>(
|
||||||
scope_id: ScopeId,
|
scope_id: ScopeId,
|
||||||
typevar_binding_context: Option<Definition<'db>>,
|
typevar_binding_context: Option<Definition<'db>>,
|
||||||
class: ClassLiteral<'db>,
|
class: ClassLiteral<'db>,
|
||||||
typevar_to_type: &impl Fn(BoundTypeVarInstance<'db>) -> Type<'db>,
|
|
||||||
) -> Option<Type<'db>> {
|
) -> Option<Type<'db>> {
|
||||||
let index = semantic_index(db, scope_id.file(db));
|
let index = semantic_index(db, scope_id.file(db));
|
||||||
|
|
||||||
|
|
@ -118,7 +120,7 @@ pub(crate) fn typing_self<'db>(
|
||||||
);
|
);
|
||||||
let bounds = TypeVarBoundOrConstraints::UpperBound(Type::instance(
|
let bounds = TypeVarBoundOrConstraints::UpperBound(Type::instance(
|
||||||
db,
|
db,
|
||||||
class.identity_specialization(db, typevar_to_type),
|
class.identity_specialization(db),
|
||||||
));
|
));
|
||||||
let typevar = TypeVarInstance::new(
|
let typevar = TypeVarInstance::new(
|
||||||
db,
|
db,
|
||||||
|
|
@ -138,17 +140,70 @@ pub(crate) fn typing_self<'db>(
|
||||||
typevar_binding_context,
|
typevar_binding_context,
|
||||||
typevar,
|
typevar,
|
||||||
)
|
)
|
||||||
.map(typevar_to_type)
|
.map(Type::TypeVar)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub(crate) enum InferableTypeVars<'a, 'db> {
|
pub(crate) enum InferableTypeVars<'a, 'db> {
|
||||||
None,
|
None,
|
||||||
// TODO: This variant isn't used, and only exists so that we can include the 'a and 'db in the
|
One(&'a FxHashSet<BoundTypeVarIdentity<'db>>),
|
||||||
// type definition. They will be used soon when we start creating real InferableTypeVars
|
Two(
|
||||||
// instances.
|
&'a InferableTypeVars<'a, 'db>,
|
||||||
#[expect(unused)]
|
&'a InferableTypeVars<'a, 'db>,
|
||||||
Unused(PhantomData<&'a &'db ()>),
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'db> BoundTypeVarInstance<'db> {
|
||||||
|
pub(crate) fn is_inferable(
|
||||||
|
self,
|
||||||
|
db: &'db dyn Db,
|
||||||
|
inferable: InferableTypeVars<'_, 'db>,
|
||||||
|
) -> bool {
|
||||||
|
match inferable {
|
||||||
|
InferableTypeVars::None => false,
|
||||||
|
InferableTypeVars::One(typevars) => typevars.contains(&self.identity(db)),
|
||||||
|
InferableTypeVars::Two(left, right) => {
|
||||||
|
self.is_inferable(db, *left) || self.is_inferable(db, *right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'db> InferableTypeVars<'a, 'db> {
|
||||||
|
pub(crate) fn merge(&'a self, other: Option<&'a InferableTypeVars<'a, 'db>>) -> Self {
|
||||||
|
match other {
|
||||||
|
Some(other) => InferableTypeVars::Two(self, other),
|
||||||
|
None => *self,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep this around for debugging purposes
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub(crate) fn display(&self, db: &'db dyn Db) -> impl Display {
|
||||||
|
fn find_typevars<'db>(
|
||||||
|
result: &mut FxHashSet<BoundTypeVarIdentity<'db>>,
|
||||||
|
inferable: &InferableTypeVars<'_, 'db>,
|
||||||
|
) {
|
||||||
|
match inferable {
|
||||||
|
InferableTypeVars::None => {}
|
||||||
|
InferableTypeVars::One(typevars) => result.extend(typevars.iter().copied()),
|
||||||
|
InferableTypeVars::Two(left, right) => {
|
||||||
|
find_typevars(result, left);
|
||||||
|
find_typevars(result, right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut typevars = FxHashSet::default();
|
||||||
|
find_typevars(&mut typevars, self);
|
||||||
|
format!(
|
||||||
|
"[{}]",
|
||||||
|
typevars
|
||||||
|
.into_iter()
|
||||||
|
.map(|identity| identity.display(db))
|
||||||
|
.format(", ")
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, get_size2::GetSize)]
|
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, get_size2::GetSize)]
|
||||||
|
|
@ -255,6 +310,66 @@ impl<'db> GenericContext<'db> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn inferable_typevars(self, db: &'db dyn Db) -> InferableTypeVars<'db, 'db> {
|
||||||
|
#[derive(Default)]
|
||||||
|
struct CollectTypeVars<'db> {
|
||||||
|
typevars: RefCell<FxHashSet<BoundTypeVarIdentity<'db>>>,
|
||||||
|
seen_types: RefCell<FxIndexSet<NonAtomicType<'db>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'db> TypeVisitor<'db> for CollectTypeVars<'db> {
|
||||||
|
fn should_visit_lazy_type_attributes(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_bound_type_var_type(
|
||||||
|
&self,
|
||||||
|
db: &'db dyn Db,
|
||||||
|
bound_typevar: BoundTypeVarInstance<'db>,
|
||||||
|
) {
|
||||||
|
self.typevars
|
||||||
|
.borrow_mut()
|
||||||
|
.insert(bound_typevar.identity(db));
|
||||||
|
walk_bound_type_var_type(db, bound_typevar, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_type(&self, db: &'db dyn Db, ty: Type<'db>) {
|
||||||
|
match TypeKind::from(ty) {
|
||||||
|
TypeKind::Atomic => {}
|
||||||
|
TypeKind::NonAtomic(non_atomic_type) => {
|
||||||
|
if !self.seen_types.borrow_mut().insert(non_atomic_type) {
|
||||||
|
// If we have already seen this type, we can skip it.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
walk_non_atomic_type(db, non_atomic_type, self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[salsa::tracked(
|
||||||
|
returns(ref),
|
||||||
|
cycle_fn=inferable_typevars_cycle_recover,
|
||||||
|
cycle_initial=inferable_typevars_cycle_initial,
|
||||||
|
heap_size=ruff_memory_usage::heap_size,
|
||||||
|
)]
|
||||||
|
fn inferable_typevars_inner<'db>(
|
||||||
|
db: &'db dyn Db,
|
||||||
|
generic_context: GenericContext<'db>,
|
||||||
|
) -> FxHashSet<BoundTypeVarIdentity<'db>> {
|
||||||
|
let visitor = CollectTypeVars::default();
|
||||||
|
for bound_typevar in generic_context.variables(db) {
|
||||||
|
visitor.visit_bound_type_var_type(db, bound_typevar);
|
||||||
|
}
|
||||||
|
visitor.typevars.into_inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
// This ensures that salsa caches the FxHashSet, not the InferableTypeVars that wraps it.
|
||||||
|
// (That way InferableTypeVars can contain references, and doesn't need to impl
|
||||||
|
// salsa::Update.)
|
||||||
|
InferableTypeVars::One(inferable_typevars_inner(db, self))
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn variables(
|
pub(crate) fn variables(
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
|
|
@ -410,14 +525,8 @@ impl<'db> GenericContext<'db> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a specialization of this generic context where each typevar is mapped to itself.
|
/// Returns a specialization of this generic context where each typevar is mapped to itself.
|
||||||
/// The second parameter can be `Type::TypeVar` or `Type::NonInferableTypeVar`, depending on
|
pub(crate) fn identity_specialization(self, db: &'db dyn Db) -> Specialization<'db> {
|
||||||
/// the use case.
|
let types = self.variables(db).map(Type::TypeVar).collect();
|
||||||
pub(crate) fn identity_specialization(
|
|
||||||
self,
|
|
||||||
db: &'db dyn Db,
|
|
||||||
typevar_to_type: &impl Fn(BoundTypeVarInstance<'db>) -> Type<'db>,
|
|
||||||
) -> Specialization<'db> {
|
|
||||||
let types = self.variables(db).map(typevar_to_type).collect();
|
|
||||||
self.specialize(db, types)
|
self.specialize(db, types)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -543,6 +652,22 @@ impl<'db> GenericContext<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inferable_typevars_cycle_recover<'db>(
|
||||||
|
_db: &'db dyn Db,
|
||||||
|
_value: &FxHashSet<BoundTypeVarIdentity<'db>>,
|
||||||
|
_count: u32,
|
||||||
|
_self: GenericContext<'db>,
|
||||||
|
) -> salsa::CycleRecoveryAction<FxHashSet<BoundTypeVarIdentity<'db>>> {
|
||||||
|
salsa::CycleRecoveryAction::Iterate
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inferable_typevars_cycle_initial<'db>(
|
||||||
|
_db: &'db dyn Db,
|
||||||
|
_self: GenericContext<'db>,
|
||||||
|
) -> FxHashSet<BoundTypeVarIdentity<'db>> {
|
||||||
|
FxHashSet::default()
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
pub(super) enum LegacyGenericBase {
|
pub(super) enum LegacyGenericBase {
|
||||||
Generic,
|
Generic,
|
||||||
|
|
@ -1357,7 +1482,9 @@ impl<'db> SpecializationBuilder<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(Type::TypeVar(bound_typevar), ty) | (ty, Type::TypeVar(bound_typevar)) => {
|
(Type::TypeVar(bound_typevar), ty) | (ty, Type::TypeVar(bound_typevar))
|
||||||
|
if bound_typevar.is_inferable(self.db, self.inferable) =>
|
||||||
|
{
|
||||||
match bound_typevar.typevar(self.db).bound_or_constraints(self.db) {
|
match bound_typevar.typevar(self.db).bound_or_constraints(self.db) {
|
||||||
Some(TypeVarBoundOrConstraints::UpperBound(bound)) => {
|
Some(TypeVarBoundOrConstraints::UpperBound(bound)) => {
|
||||||
if !ty
|
if !ty
|
||||||
|
|
|
||||||
|
|
@ -194,7 +194,6 @@ impl<'db> AllMembers<'db> {
|
||||||
| Type::ProtocolInstance(_)
|
| Type::ProtocolInstance(_)
|
||||||
| Type::SpecialForm(_)
|
| Type::SpecialForm(_)
|
||||||
| Type::KnownInstance(_)
|
| Type::KnownInstance(_)
|
||||||
| Type::NonInferableTypeVar(_)
|
|
||||||
| Type::TypeVar(_)
|
| Type::TypeVar(_)
|
||||||
| Type::BoundSuper(_)
|
| Type::BoundSuper(_)
|
||||||
| Type::TypeIs(_) => match ty.to_meta_type(db) {
|
| Type::TypeIs(_) => match ty.to_meta_type(db) {
|
||||||
|
|
|
||||||
|
|
@ -3617,7 +3617,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
| Type::WrapperDescriptor(_)
|
| Type::WrapperDescriptor(_)
|
||||||
| Type::DataclassDecorator(_)
|
| Type::DataclassDecorator(_)
|
||||||
| Type::DataclassTransformer(_)
|
| Type::DataclassTransformer(_)
|
||||||
| Type::NonInferableTypeVar(..)
|
|
||||||
| Type::TypeVar(..)
|
| Type::TypeVar(..)
|
||||||
| Type::AlwaysTruthy
|
| Type::AlwaysTruthy
|
||||||
| Type::AlwaysFalsy
|
| Type::AlwaysFalsy
|
||||||
|
|
@ -5513,6 +5512,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve the parameter type for the current argument in a given overload and its binding.
|
// Retrieve the parameter type for the current argument in a given overload and its binding.
|
||||||
|
let db = self.db();
|
||||||
let parameter_type = |overload: &Binding<'db>, binding: &CallableBinding<'db>| {
|
let parameter_type = |overload: &Binding<'db>, binding: &CallableBinding<'db>| {
|
||||||
let argument_index = if binding.bound_type.is_some() {
|
let argument_index = if binding.bound_type.is_some() {
|
||||||
argument_index + 1
|
argument_index + 1
|
||||||
|
|
@ -5525,7 +5525,36 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
overload.signature.parameters()[*parameter_index].annotated_type()
|
let parameter_type =
|
||||||
|
overload.signature.parameters()[*parameter_index].annotated_type()?;
|
||||||
|
|
||||||
|
// TODO: For now, skip any parameter annotations that mention any typevars. There
|
||||||
|
// are two issues:
|
||||||
|
//
|
||||||
|
// First, if we include those typevars in the type context that we use to infer the
|
||||||
|
// corresponding argument type, the typevars might end up appearing in the inferred
|
||||||
|
// argument type as well. As part of analyzing this call, we're going to (try to)
|
||||||
|
// infer a specialization of those typevars, and would need to substitute those
|
||||||
|
// typevars in the inferred argument type. We can't do that easily at the moment,
|
||||||
|
// since specialization inference occurs _after_ we've inferred argument types, and
|
||||||
|
// we can't _update_ an expression's inferred type after the fact.
|
||||||
|
//
|
||||||
|
// Second, certain kinds of arguments themselves have typevars that we need to
|
||||||
|
// infer specializations for. (For instance, passing the result of _another_ call
|
||||||
|
// to the argument of _this_ call, where both are calls to generic functions.) In
|
||||||
|
// that case, we want to "tie together" the typevars of the two calls so that we
|
||||||
|
// can infer their specializations at the same time — or at least, for the
|
||||||
|
// specialization of one to influence the specialization of the other. It's not yet
|
||||||
|
// clear how we're going to do that. (We might have to start inferring constraint
|
||||||
|
// sets for each expression, instead of simple types?)
|
||||||
|
//
|
||||||
|
// Regardless, for now, the expedient "solution" is to not perform bidi type
|
||||||
|
// checking for these kinds of parameters.
|
||||||
|
if parameter_type.has_typevar(db) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(parameter_type)
|
||||||
};
|
};
|
||||||
|
|
||||||
// If there is only a single binding and overload, we can infer the argument directly with
|
// If there is only a single binding and overload, we can infer the argument directly with
|
||||||
|
|
@ -5910,11 +5939,13 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
parenthesized: _,
|
parenthesized: _,
|
||||||
} = tuple;
|
} = tuple;
|
||||||
|
|
||||||
// TODO: Use the list of inferable typevars from the generic context of tuple.
|
|
||||||
let inferable = InferableTypeVars::None;
|
|
||||||
|
|
||||||
// Remove any union elements of that are unrelated to the tuple type.
|
// Remove any union elements of that are unrelated to the tuple type.
|
||||||
let tcx = tcx.map(|annotation| {
|
let tcx = tcx.map(|annotation| {
|
||||||
|
let inferable = KnownClass::Tuple
|
||||||
|
.try_to_class_literal(self.db())
|
||||||
|
.and_then(|class| class.generic_context(self.db()))
|
||||||
|
.map(|generic_context| generic_context.inferable_typevars(self.db()))
|
||||||
|
.unwrap_or(InferableTypeVars::None);
|
||||||
annotation.filter_disjoint_elements(
|
annotation.filter_disjoint_elements(
|
||||||
self.db(),
|
self.db(),
|
||||||
KnownClass::Tuple.to_instance(self.db()),
|
KnownClass::Tuple.to_instance(self.db()),
|
||||||
|
|
@ -6057,10 +6088,14 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
let elt_tys = |collection_class: KnownClass| {
|
let elt_tys = |collection_class: KnownClass| {
|
||||||
let class_literal = collection_class.try_to_class_literal(self.db())?;
|
let class_literal = collection_class.try_to_class_literal(self.db())?;
|
||||||
let generic_context = class_literal.generic_context(self.db())?;
|
let generic_context = class_literal.generic_context(self.db())?;
|
||||||
Some((class_literal, generic_context.variables(self.db())))
|
Some((
|
||||||
|
class_literal,
|
||||||
|
generic_context,
|
||||||
|
generic_context.variables(self.db()),
|
||||||
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some((class_literal, elt_tys)) = elt_tys(collection_class) else {
|
let Some((class_literal, generic_context, elt_tys)) = elt_tys(collection_class) else {
|
||||||
// Infer the element types without type context, and fallback to unknown for
|
// Infer the element types without type context, and fallback to unknown for
|
||||||
// custom typesheds.
|
// custom typesheds.
|
||||||
for elt in elts.flatten().flatten() {
|
for elt in elts.flatten().flatten() {
|
||||||
|
|
@ -6070,9 +6105,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Use the list of inferable typevars from the generic context of the collection
|
let inferable = generic_context.inferable_typevars(self.db());
|
||||||
// class.
|
|
||||||
let inferable = InferableTypeVars::None;
|
|
||||||
|
|
||||||
// Remove any union elements of that are unrelated to the collection type.
|
// Remove any union elements of that are unrelated to the collection type.
|
||||||
//
|
//
|
||||||
|
|
@ -6154,7 +6187,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let class_type = class_literal.apply_specialization(self.db(), |generic_context| {
|
let class_type = class_literal.apply_specialization(self.db(), |_| {
|
||||||
builder.build(generic_context, TypeContext::default())
|
builder.build(generic_context, TypeContext::default())
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -7732,7 +7765,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
| Type::BytesLiteral(_)
|
| Type::BytesLiteral(_)
|
||||||
| Type::EnumLiteral(_)
|
| Type::EnumLiteral(_)
|
||||||
| Type::BoundSuper(_)
|
| Type::BoundSuper(_)
|
||||||
| Type::NonInferableTypeVar(_)
|
|
||||||
| Type::TypeVar(_)
|
| Type::TypeVar(_)
|
||||||
| Type::TypeIs(_)
|
| Type::TypeIs(_)
|
||||||
| Type::TypedDict(_),
|
| Type::TypedDict(_),
|
||||||
|
|
@ -8119,7 +8151,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
| Type::BytesLiteral(_)
|
| Type::BytesLiteral(_)
|
||||||
| Type::EnumLiteral(_)
|
| Type::EnumLiteral(_)
|
||||||
| Type::BoundSuper(_)
|
| Type::BoundSuper(_)
|
||||||
| Type::NonInferableTypeVar(_)
|
|
||||||
| Type::TypeVar(_)
|
| Type::TypeVar(_)
|
||||||
| Type::TypeIs(_)
|
| Type::TypeIs(_)
|
||||||
| Type::TypedDict(_),
|
| Type::TypedDict(_),
|
||||||
|
|
@ -8149,7 +8180,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
| Type::BytesLiteral(_)
|
| Type::BytesLiteral(_)
|
||||||
| Type::EnumLiteral(_)
|
| Type::EnumLiteral(_)
|
||||||
| Type::BoundSuper(_)
|
| Type::BoundSuper(_)
|
||||||
| Type::NonInferableTypeVar(_)
|
|
||||||
| Type::TypeVar(_)
|
| Type::TypeVar(_)
|
||||||
| Type::TypeIs(_)
|
| Type::TypeIs(_)
|
||||||
| Type::TypedDict(_),
|
| Type::TypedDict(_),
|
||||||
|
|
|
||||||
|
|
@ -207,15 +207,16 @@ impl ClassInfoConstraintFunction {
|
||||||
Type::Union(union) => {
|
Type::Union(union) => {
|
||||||
union.try_map(db, |element| self.generate_constraint(db, *element))
|
union.try_map(db, |element| self.generate_constraint(db, *element))
|
||||||
}
|
}
|
||||||
Type::NonInferableTypeVar(bound_typevar) => match bound_typevar
|
Type::TypeVar(bound_typevar) => {
|
||||||
.typevar(db)
|
match bound_typevar.typevar(db).bound_or_constraints(db)? {
|
||||||
.bound_or_constraints(db)?
|
TypeVarBoundOrConstraints::UpperBound(bound) => {
|
||||||
{
|
self.generate_constraint(db, bound)
|
||||||
TypeVarBoundOrConstraints::UpperBound(bound) => self.generate_constraint(db, bound),
|
}
|
||||||
TypeVarBoundOrConstraints::Constraints(constraints) => {
|
TypeVarBoundOrConstraints::Constraints(constraints) => {
|
||||||
self.generate_constraint(db, Type::Union(constraints))
|
self.generate_constraint(db, Type::Union(constraints))
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// It's not valid to use a generic alias as the second argument to `isinstance()` or `issubclass()`,
|
// It's not valid to use a generic alias as the second argument to `isinstance()` or `issubclass()`,
|
||||||
// e.g. `isinstance(x, list[int])` fails at runtime.
|
// e.g. `isinstance(x, list[int])` fails at runtime.
|
||||||
|
|
@ -251,7 +252,6 @@ impl ClassInfoConstraintFunction {
|
||||||
| Type::IntLiteral(_)
|
| Type::IntLiteral(_)
|
||||||
| Type::KnownInstance(_)
|
| Type::KnownInstance(_)
|
||||||
| Type::TypeIs(_)
|
| Type::TypeIs(_)
|
||||||
| Type::TypeVar(_)
|
|
||||||
| Type::WrapperDescriptor(_)
|
| Type::WrapperDescriptor(_)
|
||||||
| Type::DataclassTransformer(_)
|
| Type::DataclassTransformer(_)
|
||||||
| Type::TypedDict(_) => None,
|
| Type::TypedDict(_) => None,
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,9 @@ use crate::types::generics::{
|
||||||
};
|
};
|
||||||
use crate::types::infer::nearest_enclosing_class;
|
use crate::types::infer::nearest_enclosing_class;
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
ApplyTypeMappingVisitor, BindingContext, BoundTypeVarInstance, ClassLiteral,
|
ApplyTypeMappingVisitor, BoundTypeVarInstance, ClassLiteral, FindLegacyTypeVarsVisitor,
|
||||||
FindLegacyTypeVarsVisitor, HasRelationToVisitor, IsDisjointVisitor, IsEquivalentVisitor,
|
HasRelationToVisitor, IsDisjointVisitor, IsEquivalentVisitor, KnownClass, MaterializationKind,
|
||||||
KnownClass, MaterializationKind, NormalizedVisitor, TypeContext, TypeMapping, TypeRelation,
|
NormalizedVisitor, TypeContext, TypeMapping, TypeRelation, VarianceInferable, todo_type,
|
||||||
VarianceInferable, todo_type,
|
|
||||||
};
|
};
|
||||||
use crate::{Db, FxOrderSet};
|
use crate::{Db, FxOrderSet};
|
||||||
use ruff_python_ast::{self as ast, name::Name};
|
use ruff_python_ast::{self as ast, name::Name};
|
||||||
|
|
@ -446,19 +445,6 @@ impl<'db> Signature<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn mark_typevars_inferable(self, db: &'db dyn Db) -> Self {
|
|
||||||
if let Some(definition) = self.definition {
|
|
||||||
self.apply_type_mapping_impl(
|
|
||||||
db,
|
|
||||||
&TypeMapping::MarkTypeVarsInferable(Some(BindingContext::Definition(definition))),
|
|
||||||
TypeContext::default(),
|
|
||||||
&ApplyTypeMappingVisitor::default(),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn wrap_coroutine_return_type(self, db: &'db dyn Db) -> Self {
|
pub(super) fn wrap_coroutine_return_type(self, db: &'db dyn Db) -> Self {
|
||||||
let return_ty = self.return_ty.map(|return_ty| {
|
let return_ty = self.return_ty.map(|return_ty| {
|
||||||
KnownClass::CoroutineType
|
KnownClass::CoroutineType
|
||||||
|
|
@ -617,6 +603,15 @@ impl<'db> Signature<'db> {
|
||||||
inferable: InferableTypeVars<'_, 'db>,
|
inferable: InferableTypeVars<'_, 'db>,
|
||||||
visitor: &IsEquivalentVisitor<'db>,
|
visitor: &IsEquivalentVisitor<'db>,
|
||||||
) -> ConstraintSet<'db> {
|
) -> ConstraintSet<'db> {
|
||||||
|
// The typevars in self and other should also be considered inferable when checking whether
|
||||||
|
// two signatures are equivalent.
|
||||||
|
let self_inferable =
|
||||||
|
(self.generic_context).map(|generic_context| generic_context.inferable_typevars(db));
|
||||||
|
let other_inferable =
|
||||||
|
(other.generic_context).map(|generic_context| generic_context.inferable_typevars(db));
|
||||||
|
let inferable = inferable.merge(self_inferable.as_ref());
|
||||||
|
let inferable = inferable.merge(other_inferable.as_ref());
|
||||||
|
|
||||||
let mut result = ConstraintSet::from(true);
|
let mut result = ConstraintSet::from(true);
|
||||||
let mut check_types = |self_type: Option<Type<'db>>, other_type: Option<Type<'db>>| {
|
let mut check_types = |self_type: Option<Type<'db>>, other_type: Option<Type<'db>>| {
|
||||||
let self_type = self_type.unwrap_or(Type::unknown());
|
let self_type = self_type.unwrap_or(Type::unknown());
|
||||||
|
|
@ -767,6 +762,15 @@ impl<'db> Signature<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The typevars in self and other should also be considered inferable when checking whether
|
||||||
|
// two signatures are equivalent.
|
||||||
|
let self_inferable =
|
||||||
|
(self.generic_context).map(|generic_context| generic_context.inferable_typevars(db));
|
||||||
|
let other_inferable =
|
||||||
|
(other.generic_context).map(|generic_context| generic_context.inferable_typevars(db));
|
||||||
|
let inferable = inferable.merge(self_inferable.as_ref());
|
||||||
|
let inferable = inferable.merge(other_inferable.as_ref());
|
||||||
|
|
||||||
let mut result = ConstraintSet::from(true);
|
let mut result = ConstraintSet::from(true);
|
||||||
let mut check_types = |type1: Option<Type<'db>>, type2: Option<Type<'db>>| {
|
let mut check_types = |type1: Option<Type<'db>>, type2: Option<Type<'db>>| {
|
||||||
let type1 = type1.unwrap_or(Type::unknown());
|
let type1 = type1.unwrap_or(Type::unknown());
|
||||||
|
|
@ -1301,19 +1305,8 @@ impl<'db> Parameters<'db> {
|
||||||
let class = nearest_enclosing_class(db, index, scope_id).unwrap();
|
let class = nearest_enclosing_class(db, index, scope_id).unwrap();
|
||||||
|
|
||||||
Some(
|
Some(
|
||||||
// It looks like unnecessary work here that we create the implicit Self
|
typing_self(db, scope_id, typevar_binding_context, class)
|
||||||
// annotation using non-inferable typevars and then immediately apply
|
.expect("We should always find the surrounding class for an implicit self: Self annotation"),
|
||||||
// `MarkTypeVarsInferable` to it. However, this is currently necessary to
|
|
||||||
// ensure that implicit-Self and explicit Self annotations are both treated
|
|
||||||
// the same. Marking type vars inferable will cause reification of lazy
|
|
||||||
// typevar defaults/bounds/constraints; this needs to happen for both
|
|
||||||
// implicit and explicit Self so they remain the "same" typevar.
|
|
||||||
typing_self(db, scope_id, typevar_binding_context, class, &Type::NonInferableTypeVar)
|
|
||||||
.expect("We should always find the surrounding class for an implicit self: Self annotation").apply_type_mapping(
|
|
||||||
db,
|
|
||||||
&TypeMapping::MarkTypeVarsInferable(None),
|
|
||||||
TypeContext::default()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// For methods of non-generic classes that are not otherwise generic (e.g. return `Self` or
|
// For methods of non-generic classes that are not otherwise generic (e.g. return `Self` or
|
||||||
|
|
|
||||||
|
|
@ -137,10 +137,6 @@ pub(super) fn union_or_intersection_elements_ordering<'db>(
|
||||||
(Type::ProtocolInstance(_), _) => Ordering::Less,
|
(Type::ProtocolInstance(_), _) => Ordering::Less,
|
||||||
(_, Type::ProtocolInstance(_)) => Ordering::Greater,
|
(_, Type::ProtocolInstance(_)) => Ordering::Greater,
|
||||||
|
|
||||||
(Type::NonInferableTypeVar(left), Type::NonInferableTypeVar(right)) => left.cmp(right),
|
|
||||||
(Type::NonInferableTypeVar(_), _) => Ordering::Less,
|
|
||||||
(_, Type::NonInferableTypeVar(_)) => Ordering::Greater,
|
|
||||||
|
|
||||||
(Type::TypeVar(left), Type::TypeVar(right)) => left.cmp(right),
|
(Type::TypeVar(left), Type::TypeVar(right)) => left.cmp(right),
|
||||||
(Type::TypeVar(_), _) => Ordering::Less,
|
(Type::TypeVar(_), _) => Ordering::Less,
|
||||||
(_, Type::TypeVar(_)) => Ordering::Greater,
|
(_, Type::TypeVar(_)) => Ordering::Greater,
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,6 @@ pub(super) enum NonAtomicType<'db> {
|
||||||
NominalInstance(NominalInstanceType<'db>),
|
NominalInstance(NominalInstanceType<'db>),
|
||||||
PropertyInstance(PropertyInstanceType<'db>),
|
PropertyInstance(PropertyInstanceType<'db>),
|
||||||
TypeIs(TypeIsType<'db>),
|
TypeIs(TypeIsType<'db>),
|
||||||
NonInferableTypeVar(BoundTypeVarInstance<'db>),
|
|
||||||
TypeVar(BoundTypeVarInstance<'db>),
|
TypeVar(BoundTypeVarInstance<'db>),
|
||||||
ProtocolInstance(ProtocolInstanceType<'db>),
|
ProtocolInstance(ProtocolInstanceType<'db>),
|
||||||
TypedDict(TypedDictType<'db>),
|
TypedDict(TypedDictType<'db>),
|
||||||
|
|
@ -186,9 +185,6 @@ impl<'db> From<Type<'db>> for TypeKind<'db> {
|
||||||
Type::PropertyInstance(property) => {
|
Type::PropertyInstance(property) => {
|
||||||
TypeKind::NonAtomic(NonAtomicType::PropertyInstance(property))
|
TypeKind::NonAtomic(NonAtomicType::PropertyInstance(property))
|
||||||
}
|
}
|
||||||
Type::NonInferableTypeVar(bound_typevar) => {
|
|
||||||
TypeKind::NonAtomic(NonAtomicType::NonInferableTypeVar(bound_typevar))
|
|
||||||
}
|
|
||||||
Type::TypeVar(bound_typevar) => {
|
Type::TypeVar(bound_typevar) => {
|
||||||
TypeKind::NonAtomic(NonAtomicType::TypeVar(bound_typevar))
|
TypeKind::NonAtomic(NonAtomicType::TypeVar(bound_typevar))
|
||||||
}
|
}
|
||||||
|
|
@ -228,9 +224,6 @@ pub(super) fn walk_non_atomic_type<'db, V: TypeVisitor<'db> + ?Sized>(
|
||||||
visitor.visit_property_instance_type(db, property);
|
visitor.visit_property_instance_type(db, property);
|
||||||
}
|
}
|
||||||
NonAtomicType::TypeIs(type_is) => visitor.visit_typeis_type(db, type_is),
|
NonAtomicType::TypeIs(type_is) => visitor.visit_typeis_type(db, type_is),
|
||||||
NonAtomicType::NonInferableTypeVar(bound_typevar) => {
|
|
||||||
visitor.visit_bound_type_var_type(db, bound_typevar);
|
|
||||||
}
|
|
||||||
NonAtomicType::TypeVar(bound_typevar) => {
|
NonAtomicType::TypeVar(bound_typevar) => {
|
||||||
visitor.visit_bound_type_var_type(db, bound_typevar);
|
visitor.visit_bound_type_var_type(db, bound_typevar);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue