mirror of https://github.com/astral-sh/ruff
[ty] Fix false positives for `class F(Generic[*Ts]): ...` (#21723)
This commit is contained in:
parent
116fd7c7af
commit
0e651b50b7
|
|
@ -5,6 +5,11 @@
|
||||||
At its simplest, to define a generic class using the legacy syntax, you inherit from the
|
At its simplest, to define a generic class using the legacy syntax, you inherit from the
|
||||||
`typing.Generic` special form, which is "specialized" with the generic class's type variables.
|
`typing.Generic` special form, which is "specialized" with the generic class's type variables.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[environment]
|
||||||
|
python-version = "3.11"
|
||||||
|
```
|
||||||
|
|
||||||
```py
|
```py
|
||||||
from ty_extensions import generic_context
|
from ty_extensions import generic_context
|
||||||
from typing_extensions import Generic, TypeVar, TypeVarTuple, ParamSpec, Unpack
|
from typing_extensions import Generic, TypeVar, TypeVarTuple, ParamSpec, Unpack
|
||||||
|
|
@ -19,7 +24,9 @@ class MultipleTypevars(Generic[T, S]): ...
|
||||||
class SingleParamSpec(Generic[P]): ...
|
class SingleParamSpec(Generic[P]): ...
|
||||||
class TypeVarAndParamSpec(Generic[P, T]): ...
|
class TypeVarAndParamSpec(Generic[P, T]): ...
|
||||||
class SingleTypeVarTuple(Generic[Unpack[Ts]]): ...
|
class SingleTypeVarTuple(Generic[Unpack[Ts]]): ...
|
||||||
|
class StarredSingleTypeVarTuple(Generic[*Ts]): ...
|
||||||
class TypeVarAndTypeVarTuple(Generic[T, Unpack[Ts]]): ...
|
class TypeVarAndTypeVarTuple(Generic[T, Unpack[Ts]]): ...
|
||||||
|
class StarredTypeVarAndTypeVarTuple(Generic[T, *Ts]): ...
|
||||||
|
|
||||||
# revealed: ty_extensions.GenericContext[T@SingleTypevar]
|
# revealed: ty_extensions.GenericContext[T@SingleTypevar]
|
||||||
reveal_type(generic_context(SingleTypevar))
|
reveal_type(generic_context(SingleTypevar))
|
||||||
|
|
@ -34,6 +41,8 @@ reveal_type(generic_context(TypeVarAndParamSpec))
|
||||||
# TODO: support `TypeVarTuple` properly (these should not reveal `None`)
|
# TODO: support `TypeVarTuple` properly (these should not reveal `None`)
|
||||||
reveal_type(generic_context(SingleTypeVarTuple)) # revealed: None
|
reveal_type(generic_context(SingleTypeVarTuple)) # revealed: None
|
||||||
reveal_type(generic_context(TypeVarAndTypeVarTuple)) # revealed: None
|
reveal_type(generic_context(TypeVarAndTypeVarTuple)) # revealed: None
|
||||||
|
reveal_type(generic_context(StarredSingleTypeVarTuple)) # revealed: None
|
||||||
|
reveal_type(generic_context(StarredTypeVarAndTypeVarTuple)) # revealed: None
|
||||||
```
|
```
|
||||||
|
|
||||||
Inheriting from `Generic` multiple times yields a `duplicate-base` diagnostic, just like any other
|
Inheriting from `Generic` multiple times yields a `duplicate-base` diagnostic, just like any other
|
||||||
|
|
|
||||||
|
|
@ -956,8 +956,13 @@ impl<'db> Type<'db> {
|
||||||
self.is_instance_of(db, KnownClass::NotImplementedType)
|
self.is_instance_of(db, KnownClass::NotImplementedType)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) const fn is_todo(&self) -> bool {
|
pub(crate) fn is_todo(&self) -> bool {
|
||||||
matches!(self, Type::Dynamic(DynamicType::Todo(_)))
|
self.as_dynamic().is_some_and(|dynamic| match dynamic {
|
||||||
|
DynamicType::Any | DynamicType::Unknown | DynamicType::Divergent(_) => false,
|
||||||
|
DynamicType::Todo(_) | DynamicType::TodoStarredExpression | DynamicType::TodoUnpack => {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn is_generic_alias(&self) -> bool {
|
pub const fn is_generic_alias(&self) -> bool {
|
||||||
|
|
@ -8133,7 +8138,7 @@ impl<'db> Type<'db> {
|
||||||
Self::AlwaysFalsy => Type::SpecialForm(SpecialFormType::AlwaysFalsy).definition(db),
|
Self::AlwaysFalsy => Type::SpecialForm(SpecialFormType::AlwaysFalsy).definition(db),
|
||||||
|
|
||||||
// These types have no definition
|
// These types have no definition
|
||||||
Self::Dynamic(DynamicType::Divergent(_) | DynamicType::Todo(_) | DynamicType::TodoUnpack)
|
Self::Dynamic(DynamicType::Divergent(_) | DynamicType::Todo(_) | DynamicType::TodoUnpack | DynamicType::TodoStarredExpression)
|
||||||
| Self::Callable(_)
|
| Self::Callable(_)
|
||||||
| Self::TypeIs(_) => None,
|
| Self::TypeIs(_) => None,
|
||||||
}
|
}
|
||||||
|
|
@ -8794,6 +8799,8 @@ pub enum DynamicType {
|
||||||
Todo(TodoType),
|
Todo(TodoType),
|
||||||
/// A special Todo-variant for `Unpack[Ts]`, so that we can treat it specially in `Generic[Unpack[Ts]]`
|
/// A special Todo-variant for `Unpack[Ts]`, so that we can treat it specially in `Generic[Unpack[Ts]]`
|
||||||
TodoUnpack,
|
TodoUnpack,
|
||||||
|
/// A special Todo-variant for `*Ts`, so that we can treat it specially in `Generic[Unpack[Ts]]`
|
||||||
|
TodoStarredExpression,
|
||||||
/// A type that is determined to be divergent during recursive type inference.
|
/// A type that is determined to be divergent during recursive type inference.
|
||||||
Divergent(DivergentType),
|
Divergent(DivergentType),
|
||||||
}
|
}
|
||||||
|
|
@ -8824,13 +8831,8 @@ impl std::fmt::Display for DynamicType {
|
||||||
// `DynamicType::Todo`'s display should be explicit that is not a valid display of
|
// `DynamicType::Todo`'s display should be explicit that is not a valid display of
|
||||||
// any other type
|
// any other type
|
||||||
DynamicType::Todo(todo) => write!(f, "@Todo{todo}"),
|
DynamicType::Todo(todo) => write!(f, "@Todo{todo}"),
|
||||||
DynamicType::TodoUnpack => {
|
DynamicType::TodoUnpack => f.write_str("@Todo(typing.Unpack)"),
|
||||||
if cfg!(debug_assertions) {
|
DynamicType::TodoStarredExpression => f.write_str("@Todo(StarredExpression)"),
|
||||||
f.write_str("@Todo(typing.Unpack)")
|
|
||||||
} else {
|
|
||||||
f.write_str("@Todo")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DynamicType::Divergent(_) => f.write_str("Divergent"),
|
DynamicType::Divergent(_) => f.write_str("Divergent"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,9 @@ impl<'db> ClassBase<'db> {
|
||||||
ClassBase::Class(class) => class.name(db),
|
ClassBase::Class(class) => class.name(db),
|
||||||
ClassBase::Dynamic(DynamicType::Any) => "Any",
|
ClassBase::Dynamic(DynamicType::Any) => "Any",
|
||||||
ClassBase::Dynamic(DynamicType::Unknown) => "Unknown",
|
ClassBase::Dynamic(DynamicType::Unknown) => "Unknown",
|
||||||
ClassBase::Dynamic(DynamicType::Todo(_) | DynamicType::TodoUnpack) => "@Todo",
|
ClassBase::Dynamic(
|
||||||
|
DynamicType::Todo(_) | DynamicType::TodoUnpack | DynamicType::TodoStarredExpression,
|
||||||
|
) => "@Todo",
|
||||||
ClassBase::Dynamic(DynamicType::Divergent(_)) => "Divergent",
|
ClassBase::Dynamic(DynamicType::Divergent(_)) => "Divergent",
|
||||||
ClassBase::Protocol => "Protocol",
|
ClassBase::Protocol => "Protocol",
|
||||||
ClassBase::Generic => "Generic",
|
ClassBase::Generic => "Generic",
|
||||||
|
|
|
||||||
|
|
@ -8407,7 +8407,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
todo_type!("starred expression")
|
Type::Dynamic(DynamicType::TodoStarredExpression)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_yield_expression(&mut self, yield_expression: &ast::ExprYield) -> Type<'db> {
|
fn infer_yield_expression(&mut self, yield_expression: &ast::ExprYield) -> Type<'db> {
|
||||||
|
|
@ -9571,10 +9571,24 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
(unknown @ Type::Dynamic(DynamicType::Unknown), _, _)
|
(unknown @ Type::Dynamic(DynamicType::Unknown), _, _)
|
||||||
| (_, unknown @ Type::Dynamic(DynamicType::Unknown), _) => Some(unknown),
|
| (_, unknown @ Type::Dynamic(DynamicType::Unknown), _) => Some(unknown),
|
||||||
|
|
||||||
(todo @ Type::Dynamic(DynamicType::Todo(_) | DynamicType::TodoUnpack), _, _)
|
(
|
||||||
| (_, todo @ Type::Dynamic(DynamicType::Todo(_) | DynamicType::TodoUnpack), _) => {
|
todo @ Type::Dynamic(
|
||||||
Some(todo)
|
DynamicType::Todo(_)
|
||||||
}
|
| DynamicType::TodoUnpack
|
||||||
|
| DynamicType::TodoStarredExpression,
|
||||||
|
),
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
)
|
||||||
|
| (
|
||||||
|
_,
|
||||||
|
todo @ Type::Dynamic(
|
||||||
|
DynamicType::Todo(_)
|
||||||
|
| DynamicType::TodoUnpack
|
||||||
|
| DynamicType::TodoStarredExpression,
|
||||||
|
),
|
||||||
|
_,
|
||||||
|
) => Some(todo),
|
||||||
|
|
||||||
(Type::Never, _, _) | (_, Type::Never, _) => Some(Type::Never),
|
(Type::Never, _, _) | (_, Type::Never, _) => Some(Type::Never),
|
||||||
|
|
||||||
|
|
@ -11898,7 +11912,9 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
self.db(),
|
self.db(),
|
||||||
*typevar,
|
*typevar,
|
||||||
&|ty| match ty {
|
&|ty| match ty {
|
||||||
Type::Dynamic(DynamicType::TodoUnpack) => true,
|
Type::Dynamic(
|
||||||
|
DynamicType::TodoUnpack | DynamicType::TodoStarredExpression,
|
||||||
|
) => true,
|
||||||
Type::NominalInstance(nominal) => matches!(
|
Type::NominalInstance(nominal) => matches!(
|
||||||
nominal.known_class(self.db()),
|
nominal.known_class(self.db()),
|
||||||
Some(KnownClass::TypeVarTuple | KnownClass::ParamSpec)
|
Some(KnownClass::TypeVarTuple | KnownClass::ParamSpec)
|
||||||
|
|
|
||||||
|
|
@ -499,7 +499,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
if starred_type.exact_tuple_instance_spec(self.db()).is_some() {
|
if starred_type.exact_tuple_instance_spec(self.db()).is_some() {
|
||||||
starred_type
|
starred_type
|
||||||
} else {
|
} else {
|
||||||
todo_type!("PEP 646")
|
Type::Dynamic(DynamicType::TodoStarredExpression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -274,6 +274,9 @@ fn dynamic_elements_ordering(left: DynamicType, right: DynamicType) -> Ordering
|
||||||
(DynamicType::TodoUnpack, _) => Ordering::Less,
|
(DynamicType::TodoUnpack, _) => Ordering::Less,
|
||||||
(_, DynamicType::TodoUnpack) => Ordering::Greater,
|
(_, DynamicType::TodoUnpack) => Ordering::Greater,
|
||||||
|
|
||||||
|
(DynamicType::TodoStarredExpression, _) => Ordering::Less,
|
||||||
|
(_, DynamicType::TodoStarredExpression) => Ordering::Greater,
|
||||||
|
|
||||||
(DynamicType::Divergent(left), DynamicType::Divergent(right)) => left.cmp(&right),
|
(DynamicType::Divergent(left), DynamicType::Divergent(right)) => left.cmp(&right),
|
||||||
(DynamicType::Divergent(_), _) => Ordering::Less,
|
(DynamicType::Divergent(_), _) => Ordering::Less,
|
||||||
(_, DynamicType::Divergent(_)) => Ordering::Greater,
|
(_, DynamicType::Divergent(_)) => Ordering::Greater,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue