mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-19 12:16:43 +00:00
[ty] Fix is_disjoint_from with @final classes (#21167)
## Summary We currently perform a subtyping check instead of the intended subclass check (and the subtyping check is confusingly named `is_subclass_of`). This showed up in https://github.com/astral-sh/ruff/pull/21070.
This commit is contained in:
parent
3179b05221
commit
1baf98aab3
2 changed files with 33 additions and 3 deletions
|
|
@ -87,6 +87,31 @@ static_assert(is_disjoint_from(memoryview, Foo))
|
|||
static_assert(is_disjoint_from(type[memoryview], type[Foo]))
|
||||
```
|
||||
|
||||
## Specialized `@final` types
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
python-version = "3.12"
|
||||
```
|
||||
|
||||
```py
|
||||
from typing import final
|
||||
from ty_extensions import static_assert, is_disjoint_from
|
||||
|
||||
@final
|
||||
class Foo[T]:
|
||||
def get(self) -> T:
|
||||
raise NotImplementedError
|
||||
|
||||
class A: ...
|
||||
class B: ...
|
||||
|
||||
static_assert(not is_disjoint_from(Foo[A], Foo[B]))
|
||||
|
||||
# TODO: `int` and `str` are disjoint bases, so these should be disjoint.
|
||||
static_assert(not is_disjoint_from(Foo[int], Foo[str]))
|
||||
```
|
||||
|
||||
## "Disjoint base" builtin types
|
||||
|
||||
Most other builtins can be subclassed and can even be used in multiple inheritance. However, builtin
|
||||
|
|
|
|||
|
|
@ -637,12 +637,17 @@ impl<'db> ClassType<'db> {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Optimisation: if either class is `@final`, we only need to do one `is_subclass_of` call.
|
||||
if self.is_final(db) {
|
||||
return self.is_subclass_of(db, other);
|
||||
return self
|
||||
.iter_mro(db)
|
||||
.filter_map(ClassBase::into_class)
|
||||
.any(|class| class.class_literal(db).0 == other.class_literal(db).0);
|
||||
}
|
||||
if other.is_final(db) {
|
||||
return other.is_subclass_of(db, self);
|
||||
return other
|
||||
.iter_mro(db)
|
||||
.filter_map(ClassBase::into_class)
|
||||
.any(|class| class.class_literal(db).0 == self.class_literal(db).0);
|
||||
}
|
||||
|
||||
// Two disjoint bases can only coexist in an MRO if one is a subclass of the other.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue