[red-knot] Use type[Unknown] rather than Unknown as the fallback metaclass for invalid classes (#14961)

This commit is contained in:
Alex Waygood 2024-12-13 19:48:51 +00:00 committed by GitHub
parent 4b2b126b9f
commit 90a5439791
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 8 additions and 10 deletions

View file

@ -68,7 +68,7 @@ class B(metaclass=M2): ...
# error: [conflicting-metaclass] "The metaclass of a derived class (`C`) must be a subclass of the metaclasses of all its bases, but `M1` (metaclass of base class `A`) and `M2` (metaclass of base class `B`) have no subclass relationship"
class C(A, B): ...
reveal_type(C.__class__) # revealed: Unknown
reveal_type(C.__class__) # revealed: type[Unknown]
```
## Conflict (2)
@ -85,7 +85,7 @@ class A(metaclass=M1): ...
# error: [conflicting-metaclass] "The metaclass of a derived class (`B`) must be a subclass of the metaclasses of all its bases, but `M2` (metaclass of `B`) and `M1` (metaclass of base class `A`) have no subclass relationship"
class B(A, metaclass=M2): ...
reveal_type(B.__class__) # revealed: Unknown
reveal_type(B.__class__) # revealed: type[Unknown]
```
## Common metaclass
@ -129,7 +129,7 @@ class C(metaclass=M12): ...
# error: [conflicting-metaclass] "The metaclass of a derived class (`D`) must be a subclass of the metaclasses of all its bases, but `M1` (metaclass of base class `A`) and `M2` (metaclass of base class `B`) have no subclass relationship"
class D(A, B, C): ...
reveal_type(D.__class__) # revealed: Unknown
reveal_type(D.__class__) # revealed: type[Unknown]
```
## Unknown
@ -183,7 +183,7 @@ class A(B): ... # error: [cyclic-class-definition]
class B(C): ... # error: [cyclic-class-definition]
class C(A): ... # error: [cyclic-class-definition]
reveal_type(A.__class__) # revealed: Unknown
reveal_type(A.__class__) # revealed: type[Unknown]
```
## PEP 695 generic

View file

@ -2925,10 +2925,10 @@ impl<'db> Class<'db> {
Some(metaclass_ty)
}
/// Return the metaclass of this class, or `Unknown` if the metaclass cannot be inferred.
/// Return the metaclass of this class, or `type[Unknown]` if the metaclass cannot be inferred.
pub(crate) fn metaclass(self, db: &'db dyn Db) -> Type<'db> {
// TODO: `type[Unknown]` would be a more precise fallback
self.try_metaclass(db).unwrap_or(Type::Unknown)
self.try_metaclass(db)
.unwrap_or_else(|_| Type::subclass_of_base(ClassBase::Unknown))
}
/// Return the metaclass of this class, or an error if the metaclass cannot be inferred.
@ -2941,9 +2941,7 @@ impl<'db> Class<'db> {
// We emit diagnostics for cyclic class definitions elsewhere.
// Avoid attempting to infer the metaclass if the class is cyclically defined:
// it would be easy to enter an infinite loop.
//
// TODO: `type[Unknown]` might be better here?
return Ok(Type::Unknown);
return Ok(Type::subclass_of_base(ClassBase::Unknown));
}
let explicit_metaclass = self.explicit_metaclass(db);