mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 13:51:37 +00:00
[ty] Report duplicate Protocol
or Generic
base classes with [duplicate-base]
, not [inconsistent-mro]
(#17971)
This commit is contained in:
parent
4d81a41107
commit
9b694ada82
4 changed files with 27 additions and 7 deletions
|
@ -19,6 +19,16 @@ reveal_type(generic_context(SingleTypevar)) # revealed: tuple[T]
|
||||||
reveal_type(generic_context(MultipleTypevars)) # revealed: tuple[T, S]
|
reveal_type(generic_context(MultipleTypevars)) # revealed: tuple[T, S]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Inheriting from `Generic` multiple times yields a `duplicate-base` diagnostic, just like any other
|
||||||
|
class:
|
||||||
|
|
||||||
|
```py
|
||||||
|
class Bad(Generic[T], Generic[T]): ... # error: [duplicate-base]
|
||||||
|
|
||||||
|
# TODO: should emit an error (fails at runtime)
|
||||||
|
class AlsoBad(Generic[T], Generic[S]): ...
|
||||||
|
```
|
||||||
|
|
||||||
You cannot use the same typevar more than once.
|
You cannot use the same typevar more than once.
|
||||||
|
|
||||||
```py
|
```py
|
||||||
|
|
|
@ -35,7 +35,7 @@ Just like for any other class base, it is an error for `Protocol` to appear mult
|
||||||
class's bases:
|
class's bases:
|
||||||
|
|
||||||
```py
|
```py
|
||||||
class Foo(Protocol, Protocol): ... # error: [inconsistent-mro]
|
class Foo(Protocol, Protocol): ... # error: [duplicate-base]
|
||||||
|
|
||||||
reveal_type(Foo.__mro__) # revealed: tuple[<class 'Foo'>, Unknown, <class 'object'>]
|
reveal_type(Foo.__mro__) # revealed: tuple[<class 'Foo'>, Unknown, <class 'object'>]
|
||||||
```
|
```
|
||||||
|
|
|
@ -65,6 +65,19 @@ impl<'db> ClassBase<'db> {
|
||||||
Display { base: self, db }
|
Display { base: self, db }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn name(self, db: &'db dyn Db) -> &'db str {
|
||||||
|
match self {
|
||||||
|
ClassBase::Class(class) => class.name(db),
|
||||||
|
ClassBase::Dynamic(DynamicType::Any) => "Any",
|
||||||
|
ClassBase::Dynamic(DynamicType::Unknown) => "Unknown",
|
||||||
|
ClassBase::Dynamic(DynamicType::Todo(_)) => "@Todo",
|
||||||
|
ClassBase::Protocol | ClassBase::Dynamic(DynamicType::SubscriptedProtocol) => {
|
||||||
|
"Protocol"
|
||||||
|
}
|
||||||
|
ClassBase::Generic(_) => "Generic",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Return a `ClassBase` representing the class `builtins.object`
|
/// Return a `ClassBase` representing the class `builtins.object`
|
||||||
pub(super) fn object(db: &'db dyn Db) -> Self {
|
pub(super) fn object(db: &'db dyn Db) -> Self {
|
||||||
KnownClass::Object
|
KnownClass::Object
|
||||||
|
|
|
@ -177,16 +177,13 @@ impl<'db> Mro<'db> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
match base {
|
match base {
|
||||||
ClassBase::Class(class) => {
|
ClassBase::Class(_) | ClassBase::Generic(_) | ClassBase::Protocol => {
|
||||||
errors.push(DuplicateBaseError {
|
errors.push(DuplicateBaseError {
|
||||||
duplicate_base: class.class_literal(db).0,
|
duplicate_base: base,
|
||||||
first_index: *first_index,
|
first_index: *first_index,
|
||||||
later_indices: later_indices.iter().copied().collect(),
|
later_indices: later_indices.iter().copied().collect(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// TODO these should also be reported as duplicate bases
|
|
||||||
// rather than using the less specific `inconsistent-mro` error
|
|
||||||
ClassBase::Generic(_) | ClassBase::Protocol => continue,
|
|
||||||
ClassBase::Dynamic(_) => duplicate_dynamic_bases = true,
|
ClassBase::Dynamic(_) => duplicate_dynamic_bases = true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -385,7 +382,7 @@ impl<'db> MroErrorKind<'db> {
|
||||||
#[derive(Debug, PartialEq, Eq, salsa::Update)]
|
#[derive(Debug, PartialEq, Eq, salsa::Update)]
|
||||||
pub(super) struct DuplicateBaseError<'db> {
|
pub(super) struct DuplicateBaseError<'db> {
|
||||||
/// The base that is duplicated in the class's bases list.
|
/// The base that is duplicated in the class's bases list.
|
||||||
pub(super) duplicate_base: ClassLiteral<'db>,
|
pub(super) duplicate_base: ClassBase<'db>,
|
||||||
/// The index of the first occurrence of the base in the class's bases list.
|
/// The index of the first occurrence of the base in the class's bases list.
|
||||||
pub(super) first_index: usize,
|
pub(super) first_index: usize,
|
||||||
/// The indices of the base's later occurrences in the class's bases list.
|
/// The indices of the base's later occurrences in the class's bases list.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue