diff --git a/crates/ty_python_semantic/resources/mdtest/type_compendium/never.md b/crates/ty_python_semantic/resources/mdtest/type_compendium/never.md index 98bff577a2..fbef3e571b 100644 --- a/crates/ty_python_semantic/resources/mdtest/type_compendium/never.md +++ b/crates/ty_python_semantic/resources/mdtest/type_compendium/never.md @@ -5,11 +5,11 @@ ## `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 -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 from ty_extensions import static_assert, is_subtype_of -from typing_extensions import Never +from typing_extensions import Never, TypeVar class C: ... @@ -19,6 +19,9 @@ static_assert(is_subtype_of(Never, C)) static_assert(is_subtype_of(Never, 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 diff --git a/crates/ty_python_semantic/resources/mdtest/type_properties/materialization.md b/crates/ty_python_semantic/resources/mdtest/type_properties/materialization.md index 638ad5ff20..cf03b08d21 100644 --- a/crates/ty_python_semantic/resources/mdtest/type_properties/materialization.md +++ b/crates/ty_python_semantic/resources/mdtest/type_properties/materialization.md @@ -337,8 +337,6 @@ def bounded_by_gradual[T: Any](t: T) -> None: # Bottom materialization of `T: Any` is `T: Never` 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)) def constrained_by_gradual[T: (int, Any)](t: T) -> None: diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index 08deb8327c..d02d784508 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -1204,9 +1204,7 @@ impl<'db> Type<'db> { // `Never` is the bottom type, the empty set. // 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) => false, // Everything is a subtype of `object`. (_, Type::NominalInstance(instance)) if instance.class.is_object(db) => true, @@ -1260,6 +1258,11 @@ impl<'db> Type<'db> { 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 .elements(db) .iter()