[red-knot] GenericAlias instances as a base class (#17575)

## Summary

We currently emit a diagnostic for code like the following:
```py
from typing import Any

# error: Invalid class base with type `GenericAlias` (all bases must be a class, `Any`, `Unknown` or `Todo`)
class C(tuple[Any, ...]): ...
```

The changeset here silences this diagnostic by recognizing instances of
`GenericAlias` in `ClassBase::try_from_type`, and inferring a `@Todo`
type for them. This is a change in preparation for #17557, because `C`
previously had `Unknown` in its MRO …
```py
reveal_type(C.__mro__)  # tuple[Literal[C], Unknown, Literal[object]]
```
… which would cause us to think that `C` is assignable to everything.

The changeset also removes some false positive `invalid-base`
diagnostics across the ecosystem.

## Test Plan

Updated Markdown tests.
This commit is contained in:
David Peter
2025-04-23 10:39:10 +02:00
committed by GitHub
parent 3fae176345
commit b1b8ca3bcd
5 changed files with 8 additions and 11 deletions

View File

@@ -78,6 +78,9 @@ impl<'db> ClassBase<'db> {
Self::Class(literal.default_specialization(db))
}),
Type::GenericAlias(generic) => Some(Self::Class(ClassType::Generic(generic))),
Type::Instance(instance) if instance.class().is_known(db, KnownClass::GenericAlias) => {
Self::try_from_type(db, todo_type!("GenericAlias instance"))
}
Type::Union(_) => None, // TODO -- forces consideration of multiple possible MROs?
Type::Intersection(_) => None, // TODO -- probably incorrect?
Type::Instance(_) => None, // TODO -- handle `__mro_entries__`?