[ty] allow T: Never as subtype of Never (#18687)

This commit is contained in:
Felix Scherz 2025-06-16 19:46:17 +02:00 committed by GitHub
parent 5e57e4680f
commit 373a3bfcd6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 10 additions and 6 deletions

View file

@ -5,11 +5,11 @@
## `Never` is a subtype of every type ## `Never` is a subtype of every type
The `Never` type is the bottom type of Python's type system. It is a subtype of every type, but no The `Never` type is the bottom type of Python's type system. It is a subtype of every type, but no
type is a subtype of `Never`, except for `Never` itself. type is a subtype of `Never`, except for `Never` itself or type variables with upper bound `Never`.
```py ```py
from ty_extensions import static_assert, is_subtype_of from ty_extensions import static_assert, is_subtype_of
from typing_extensions import Never from typing_extensions import Never, TypeVar
class C: ... class C: ...
@ -19,6 +19,9 @@ static_assert(is_subtype_of(Never, C))
static_assert(is_subtype_of(Never, Never)) static_assert(is_subtype_of(Never, Never))
static_assert(not is_subtype_of(int, Never)) static_assert(not is_subtype_of(int, Never))
T = TypeVar("T", bound=Never)
static_assert(is_subtype_of(T, Never))
``` ```
## `Never` is assignable to every type ## `Never` is assignable to every type

View file

@ -337,8 +337,6 @@ def bounded_by_gradual[T: Any](t: T) -> None:
# Bottom materialization of `T: Any` is `T: Never` # Bottom materialization of `T: Any` is `T: Never`
static_assert(is_fully_static(TypeOf[bottom_materialization(T)])) static_assert(is_fully_static(TypeOf[bottom_materialization(T)]))
# TODO: This should not error, see https://github.com/astral-sh/ty/issues/638
# error: [static-assert-error]
static_assert(is_subtype_of(TypeOf[bottom_materialization(T)], Never)) static_assert(is_subtype_of(TypeOf[bottom_materialization(T)], Never))
def constrained_by_gradual[T: (int, Any)](t: T) -> None: def constrained_by_gradual[T: (int, Any)](t: T) -> None:

View file

@ -1204,9 +1204,7 @@ impl<'db> Type<'db> {
// `Never` is the bottom type, the empty set. // `Never` is the bottom type, the empty set.
// It is a subtype of all other fully static types. // It is a subtype of all other fully static types.
// No other fully static type is a subtype of `Never`.
(Type::Never, _) => true, (Type::Never, _) => true,
(_, Type::Never) => false,
// Everything is a subtype of `object`. // Everything is a subtype of `object`.
(_, Type::NominalInstance(instance)) if instance.class.is_object(db) => true, (_, Type::NominalInstance(instance)) if instance.class.is_object(db) => true,
@ -1260,6 +1258,11 @@ impl<'db> Type<'db> {
true true
} }
// `Never` is the bottom type, the empty set.
// Other than one unlikely edge case (TypeVars bound to `Never`),
// no other fully static type is a subtype of `Never`.
(_, Type::Never) => false,
(Type::Union(union), _) => union (Type::Union(union), _) => union
.elements(db) .elements(db)
.iter() .iter()