mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 13:51:16 +00:00
[ty] Ban protocols from inheriting from non-protocol generic classes (#19941)
This commit is contained in:
parent
f4d8826428
commit
9ac39cee98
2 changed files with 15 additions and 10 deletions
|
@ -150,6 +150,14 @@ class AlsoInvalid(MyProtocol, OtherProtocol, NotAProtocol, Protocol): ...
|
||||||
|
|
||||||
# revealed: tuple[<class 'AlsoInvalid'>, <class 'MyProtocol'>, <class 'OtherProtocol'>, <class 'NotAProtocol'>, typing.Protocol, typing.Generic, <class 'object'>]
|
# revealed: tuple[<class 'AlsoInvalid'>, <class 'MyProtocol'>, <class 'OtherProtocol'>, <class 'NotAProtocol'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||||
reveal_type(AlsoInvalid.__mro__)
|
reveal_type(AlsoInvalid.__mro__)
|
||||||
|
|
||||||
|
class NotAGenericProtocol[T]: ...
|
||||||
|
|
||||||
|
# error: [invalid-protocol] "Protocol class `StillInvalid` cannot inherit from non-protocol class `NotAGenericProtocol`"
|
||||||
|
class StillInvalid(NotAGenericProtocol[int], Protocol): ...
|
||||||
|
|
||||||
|
# revealed: tuple[<class 'StillInvalid'>, <class 'NotAGenericProtocol[int]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||||
|
reveal_type(StillInvalid.__mro__)
|
||||||
```
|
```
|
||||||
|
|
||||||
But two exceptions to this rule are `object` and `Generic`:
|
But two exceptions to this rule are `object` and `Generic`:
|
||||||
|
|
|
@ -1117,13 +1117,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
// - Check for inheritance from a `@final` classes
|
// - Check for inheritance from a `@final` classes
|
||||||
// - If the class is a protocol class: check for inheritance from a non-protocol class
|
// - If the class is a protocol class: check for inheritance from a non-protocol class
|
||||||
for (i, base_class) in class.explicit_bases(self.db()).iter().enumerate() {
|
for (i, base_class) in class.explicit_bases(self.db()).iter().enumerate() {
|
||||||
if let Some((class, solid_base)) = base_class
|
|
||||||
.to_class_type(self.db())
|
|
||||||
.and_then(|class| Some((class, class.nearest_solid_base(self.db())?)))
|
|
||||||
{
|
|
||||||
solid_bases.insert(solid_base, i, class.class_literal(self.db()).0);
|
|
||||||
}
|
|
||||||
|
|
||||||
let base_class = match base_class {
|
let base_class = match base_class {
|
||||||
Type::SpecialForm(SpecialFormType::Generic) => {
|
Type::SpecialForm(SpecialFormType::Generic) => {
|
||||||
if let Some(builder) = self
|
if let Some(builder) = self
|
||||||
|
@ -1155,13 +1148,17 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Type::ClassLiteral(class) => class,
|
Type::ClassLiteral(class) => ClassType::NonGeneric(*class),
|
||||||
// dynamic/unknown bases are never `@final`
|
Type::GenericAlias(class) => ClassType::Generic(*class),
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let Some(solid_base) = base_class.nearest_solid_base(self.db()) {
|
||||||
|
solid_bases.insert(solid_base, i, base_class.class_literal(self.db()).0);
|
||||||
|
}
|
||||||
|
|
||||||
if is_protocol
|
if is_protocol
|
||||||
&& !(base_class.is_protocol(self.db())
|
&& !(base_class.class_literal(self.db()).0.is_protocol(self.db())
|
||||||
|| base_class.is_known(self.db(), KnownClass::Object))
|
|| base_class.is_known(self.db(), KnownClass::Object))
|
||||||
{
|
{
|
||||||
if let Some(builder) = self
|
if let Some(builder) = self
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue