add static_asserts

This commit is contained in:
Douglas Creager 2025-09-23 15:43:43 -04:00
parent 6b6937fde5
commit 38f857af13

View file

@ -129,7 +129,7 @@ specialization. Thus, the typevar is a subtype of itself and of `object`, but no
(including other typevars). (including other typevars).
```py ```py
from ty_extensions import is_assignable_to, is_subtype_of from ty_extensions import is_assignable_to, is_subtype_of, static_assert
class Super: ... class Super: ...
class Base(Super): ... class Base(Super): ...
@ -139,45 +139,83 @@ class Unrelated: ...
def unbounded_unconstrained[T, U](t: T, u: U) -> None: def unbounded_unconstrained[T, U](t: T, u: U) -> None:
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_assignable_to(T, T)) reveal_type(is_assignable_to(T, T))
static_assert(is_assignable_to(T, T))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_assignable_to(T, object)) reveal_type(is_assignable_to(T, object))
static_assert(is_assignable_to(T, object))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_assignable_to(T, Super)) reveal_type(is_assignable_to(T, Super))
static_assert(not is_assignable_to(T, Super))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_assignable_to(T, Any)) reveal_type(is_assignable_to(T, Any))
static_assert(is_assignable_to(T, Any))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_assignable_to(Any, T)) reveal_type(is_assignable_to(Any, T))
static_assert(is_assignable_to(Any, T))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_assignable_to(U, U)) reveal_type(is_assignable_to(U, U))
static_assert(is_assignable_to(U, U))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_assignable_to(U, object)) reveal_type(is_assignable_to(U, object))
static_assert(is_assignable_to(U, object))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_assignable_to(U, Super)) reveal_type(is_assignable_to(U, Super))
static_assert(not is_assignable_to(U, Super))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_assignable_to(T, U)) reveal_type(is_assignable_to(T, U))
static_assert(not is_assignable_to(T, U))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_assignable_to(U, T)) reveal_type(is_assignable_to(U, T))
static_assert(not is_assignable_to(U, T))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_subtype_of(T, T)) reveal_type(is_subtype_of(T, T))
static_assert(is_subtype_of(T, T))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_subtype_of(T, object)) reveal_type(is_subtype_of(T, object))
static_assert(is_subtype_of(T, object))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(T, Super)) reveal_type(is_subtype_of(T, Super))
static_assert(not is_subtype_of(T, Super))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(T, Any)) reveal_type(is_subtype_of(T, Any))
static_assert(not is_subtype_of(T, Any))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(Any, T)) reveal_type(is_subtype_of(Any, T))
static_assert(not is_subtype_of(Any, T))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_subtype_of(U, U)) reveal_type(is_subtype_of(U, U))
static_assert(is_subtype_of(U, U))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_subtype_of(U, object)) reveal_type(is_subtype_of(U, object))
static_assert(is_subtype_of(U, object))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(U, Super)) reveal_type(is_subtype_of(U, Super))
static_assert(not is_subtype_of(U, Super))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(T, U)) reveal_type(is_subtype_of(T, U))
static_assert(not is_subtype_of(T, U))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(U, T)) reveal_type(is_subtype_of(U, T))
static_assert(not is_subtype_of(U, T))
``` ```
A bounded typevar is assignable to its bound, and a bounded, fully static typevar is a subtype of A bounded typevar is assignable to its bound, and a bounded, fully static typevar is a subtype of
@ -193,56 +231,100 @@ from typing_extensions import final
def bounded[T: Super](t: T) -> None: def bounded[T: Super](t: T) -> None:
# revealed: ty_extensions.ConstraintSet[all valid specializations: (T@bounded ≤ Super)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (T@bounded ≤ Super)]
reveal_type(is_assignable_to(T, Any)) reveal_type(is_assignable_to(T, Any))
static_assert(is_assignable_to(T, Any))
# revealed: ty_extensions.ConstraintSet[all valid specializations: (T@bounded ≤ Super)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (T@bounded ≤ Super)]
reveal_type(is_assignable_to(Any, T)) reveal_type(is_assignable_to(Any, T))
static_assert(is_assignable_to(Any, T))
# revealed: ty_extensions.ConstraintSet[all valid specializations: (T@bounded ≤ Super)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (T@bounded ≤ Super)]
reveal_type(is_assignable_to(T, Super)) reveal_type(is_assignable_to(T, Super))
static_assert(is_assignable_to(T, Super))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_assignable_to(T, Sub)) reveal_type(is_assignable_to(T, Sub))
static_assert(not is_assignable_to(T, Sub))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_assignable_to(Super, T)) reveal_type(is_assignable_to(Super, T))
static_assert(not is_assignable_to(Super, T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_assignable_to(Sub, T)) reveal_type(is_assignable_to(Sub, T))
static_assert(not is_assignable_to(Sub, T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(T, Any)) reveal_type(is_subtype_of(T, Any))
static_assert(not is_subtype_of(T, Any))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(Any, T)) reveal_type(is_subtype_of(Any, T))
static_assert(not is_subtype_of(Any, T))
# revealed: ty_extensions.ConstraintSet[all valid specializations: (T@bounded ≤ Super)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (T@bounded ≤ Super)]
reveal_type(is_subtype_of(T, Super)) reveal_type(is_subtype_of(T, Super))
static_assert(is_subtype_of(T, Super))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(T, Sub)) reveal_type(is_subtype_of(T, Sub))
static_assert(not is_subtype_of(T, Sub))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(Super, T)) reveal_type(is_subtype_of(Super, T))
static_assert(not is_subtype_of(Super, T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(Sub, T)) reveal_type(is_subtype_of(Sub, T))
static_assert(not is_subtype_of(Sub, T))
def bounded_by_gradual[T: Any](t: T) -> None: def bounded_by_gradual[T: Any](t: T) -> None:
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_assignable_to(T, Any)) reveal_type(is_assignable_to(T, Any))
static_assert(is_assignable_to(T, Any))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_assignable_to(Any, T)) reveal_type(is_assignable_to(Any, T))
static_assert(is_assignable_to(Any, T))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_assignable_to(T, Super)) reveal_type(is_assignable_to(T, Super))
static_assert(is_assignable_to(T, Super))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_assignable_to(Super, T)) reveal_type(is_assignable_to(Super, T))
static_assert(not is_assignable_to(Super, T))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_assignable_to(T, Sub)) reveal_type(is_assignable_to(T, Sub))
static_assert(is_assignable_to(T, Sub))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_assignable_to(Sub, T)) reveal_type(is_assignable_to(Sub, T))
static_assert(not is_assignable_to(Sub, T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(T, Any)) reveal_type(is_subtype_of(T, Any))
static_assert(not is_subtype_of(T, Any))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(Any, T)) reveal_type(is_subtype_of(Any, T))
static_assert(not is_subtype_of(Any, T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(T, Super)) reveal_type(is_subtype_of(T, Super))
static_assert(not is_subtype_of(T, Super))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(Super, T)) reveal_type(is_subtype_of(Super, T))
static_assert(not is_subtype_of(Super, T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(T, Sub)) reveal_type(is_subtype_of(T, Sub))
static_assert(not is_subtype_of(T, Sub))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(Sub, T)) reveal_type(is_subtype_of(Sub, T))
static_assert(not is_subtype_of(Sub, T))
@final @final
class FinalClass: ... class FinalClass: ...
@ -250,21 +332,35 @@ class FinalClass: ...
def bounded_final[T: FinalClass](t: T) -> None: def bounded_final[T: FinalClass](t: T) -> None:
# revealed: ty_extensions.ConstraintSet[all valid specializations: (T@bounded_final ≤ FinalClass)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (T@bounded_final ≤ FinalClass)]
reveal_type(is_assignable_to(T, Any)) reveal_type(is_assignable_to(T, Any))
static_assert(is_assignable_to(T, Any))
# revealed: ty_extensions.ConstraintSet[all valid specializations: (T@bounded_final ≤ FinalClass)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (T@bounded_final ≤ FinalClass)]
reveal_type(is_assignable_to(Any, T)) reveal_type(is_assignable_to(Any, T))
static_assert(is_assignable_to(Any, T))
# revealed: ty_extensions.ConstraintSet[all valid specializations: (T@bounded_final ≤ FinalClass)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (T@bounded_final ≤ FinalClass)]
reveal_type(is_assignable_to(T, FinalClass)) reveal_type(is_assignable_to(T, FinalClass))
static_assert(is_assignable_to(T, FinalClass))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_assignable_to(FinalClass, T)) reveal_type(is_assignable_to(FinalClass, T))
static_assert(not is_assignable_to(FinalClass, T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(T, Any)) reveal_type(is_subtype_of(T, Any))
static_assert(not is_subtype_of(T, Any))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(Any, T)) reveal_type(is_subtype_of(Any, T))
static_assert(not is_subtype_of(Any, T))
# revealed: ty_extensions.ConstraintSet[all valid specializations: (T@bounded_final ≤ FinalClass)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (T@bounded_final ≤ FinalClass)]
reveal_type(is_subtype_of(T, FinalClass)) reveal_type(is_subtype_of(T, FinalClass))
static_assert(is_subtype_of(T, FinalClass))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(FinalClass, T)) reveal_type(is_subtype_of(FinalClass, T))
static_assert(not is_subtype_of(FinalClass, T))
``` ```
Two distinct fully static typevars are not subtypes of each other, even if they have the same Two distinct fully static typevars are not subtypes of each other, even if they have the same
@ -276,24 +372,36 @@ typevars to `Never` in addition to that final class.
def two_bounded[T: Super, U: Super](t: T, u: U) -> None: def two_bounded[T: Super, U: Super](t: T, u: U) -> None:
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_assignable_to(T, U)) reveal_type(is_assignable_to(T, U))
static_assert(not is_assignable_to(T, U))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_assignable_to(U, T)) reveal_type(is_assignable_to(U, T))
static_assert(not is_assignable_to(U, T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(T, U)) reveal_type(is_subtype_of(T, U))
static_assert(not is_subtype_of(T, U))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(U, T)) reveal_type(is_subtype_of(U, T))
static_assert(not is_subtype_of(U, T))
def two_final_bounded[T: FinalClass, U: FinalClass](t: T, u: U) -> None: def two_final_bounded[T: FinalClass, U: FinalClass](t: T, u: U) -> None:
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_assignable_to(T, U)) reveal_type(is_assignable_to(T, U))
static_assert(not is_assignable_to(T, U))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_assignable_to(U, T)) reveal_type(is_assignable_to(U, T))
static_assert(not is_assignable_to(U, T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(T, U)) reveal_type(is_subtype_of(T, U))
static_assert(not is_subtype_of(T, U))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(U, T)) reveal_type(is_subtype_of(U, T))
static_assert(not is_subtype_of(U, T))
``` ```
A constrained fully static typevar is assignable to the union of its constraints, but not to any of A constrained fully static typevar is assignable to the union of its constraints, but not to any of
@ -306,124 +414,236 @@ from ty_extensions import Intersection
def constrained[T: (Base, Unrelated)](t: T) -> None: def constrained[T: (Base, Unrelated)](t: T) -> None:
# revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained = Base)] # revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained = Base)]
reveal_type(is_assignable_to(T, Super)) reveal_type(is_assignable_to(T, Super))
static_assert(not is_assignable_to(T, Super))
# revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained = Base)] # revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained = Base)]
reveal_type(is_assignable_to(T, Base)) reveal_type(is_assignable_to(T, Base))
static_assert(not is_assignable_to(T, Base))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_assignable_to(T, Sub)) reveal_type(is_assignable_to(T, Sub))
static_assert(not is_assignable_to(T, Sub))
# revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained = Unrelated)] # revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained = Unrelated)]
reveal_type(is_assignable_to(T, Unrelated)) reveal_type(is_assignable_to(T, Unrelated))
static_assert(not is_assignable_to(T, Unrelated))
# revealed: ty_extensions.ConstraintSet[all valid specializations: (T@constrained = Base) (T@constrained = Unrelated)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (T@constrained = Base) (T@constrained = Unrelated)]
reveal_type(is_assignable_to(T, Any)) reveal_type(is_assignable_to(T, Any))
static_assert(is_assignable_to(T, Any))
# revealed: ty_extensions.ConstraintSet[all valid specializations: (T@constrained = Base) (T@constrained = Unrelated)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (T@constrained = Base) (T@constrained = Unrelated)]
reveal_type(is_assignable_to(T, Super | Unrelated)) reveal_type(is_assignable_to(T, Super | Unrelated))
static_assert(is_assignable_to(T, Super | Unrelated))
# revealed: ty_extensions.ConstraintSet[all valid specializations: (T@constrained = Base) (T@constrained = Unrelated)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (T@constrained = Base) (T@constrained = Unrelated)]
reveal_type(is_assignable_to(T, Base | Unrelated)) reveal_type(is_assignable_to(T, Base | Unrelated))
static_assert(is_assignable_to(T, Base | Unrelated))
# revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained = Unrelated)] # revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained = Unrelated)]
reveal_type(is_assignable_to(T, Sub | Unrelated)) reveal_type(is_assignable_to(T, Sub | Unrelated))
static_assert(not is_assignable_to(T, Sub | Unrelated))
# revealed: ty_extensions.ConstraintSet[all valid specializations: (T@constrained = Base) (T@constrained = Unrelated)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (T@constrained = Base) (T@constrained = Unrelated)]
reveal_type(is_assignable_to(Any, T)) reveal_type(is_assignable_to(Any, T))
static_assert(is_assignable_to(Any, T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_assignable_to(Super, T)) reveal_type(is_assignable_to(Super, T))
static_assert(not is_assignable_to(Super, T))
# revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained = Unrelated)] # revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained = Unrelated)]
reveal_type(is_assignable_to(Unrelated, T)) reveal_type(is_assignable_to(Unrelated, T))
static_assert(not is_assignable_to(Unrelated, T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_assignable_to(Super | Unrelated, T)) reveal_type(is_assignable_to(Super | Unrelated, T))
static_assert(not is_assignable_to(Super | Unrelated, T))
# revealed: ty_extensions.ConstraintSet[all valid specializations: (T@constrained = Base) (T@constrained = Unrelated)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (T@constrained = Base) (T@constrained = Unrelated)]
reveal_type(is_assignable_to(Intersection[Base, Unrelated], T)) reveal_type(is_assignable_to(Intersection[Base, Unrelated], T))
static_assert(is_assignable_to(Intersection[Base, Unrelated], T))
# revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained = Base)] # revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained = Base)]
reveal_type(is_subtype_of(T, Super)) reveal_type(is_subtype_of(T, Super))
static_assert(not is_subtype_of(T, Super))
# revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained = Base)] # revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained = Base)]
reveal_type(is_subtype_of(T, Base)) reveal_type(is_subtype_of(T, Base))
static_assert(not is_subtype_of(T, Base))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(T, Sub)) reveal_type(is_subtype_of(T, Sub))
static_assert(not is_subtype_of(T, Sub))
# revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained = Unrelated)] # revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained = Unrelated)]
reveal_type(is_subtype_of(T, Unrelated)) reveal_type(is_subtype_of(T, Unrelated))
static_assert(not is_subtype_of(T, Unrelated))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(T, Any)) reveal_type(is_subtype_of(T, Any))
static_assert(not is_subtype_of(T, Any))
# revealed: ty_extensions.ConstraintSet[all valid specializations: (T@constrained = Base) (T@constrained = Unrelated)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (T@constrained = Base) (T@constrained = Unrelated)]
reveal_type(is_subtype_of(T, Super | Unrelated)) reveal_type(is_subtype_of(T, Super | Unrelated))
static_assert(is_subtype_of(T, Super | Unrelated))
# revealed: ty_extensions.ConstraintSet[all valid specializations: (T@constrained = Base) (T@constrained = Unrelated)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (T@constrained = Base) (T@constrained = Unrelated)]
reveal_type(is_subtype_of(T, Base | Unrelated)) reveal_type(is_subtype_of(T, Base | Unrelated))
static_assert(is_subtype_of(T, Base | Unrelated))
# revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained = Unrelated)] # revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained = Unrelated)]
reveal_type(is_subtype_of(T, Sub | Unrelated)) reveal_type(is_subtype_of(T, Sub | Unrelated))
static_assert(not is_subtype_of(T, Sub | Unrelated))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(Any, T)) reveal_type(is_subtype_of(Any, T))
static_assert(not is_subtype_of(Any, T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(Super, T)) reveal_type(is_subtype_of(Super, T))
static_assert(not is_subtype_of(Super, T))
# revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained = Unrelated)] # revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained = Unrelated)]
reveal_type(is_subtype_of(Unrelated, T)) reveal_type(is_subtype_of(Unrelated, T))
static_assert(not is_subtype_of(Unrelated, T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(Super | Unrelated, T)) reveal_type(is_subtype_of(Super | Unrelated, T))
static_assert(not is_subtype_of(Super | Unrelated, T))
# revealed: ty_extensions.ConstraintSet[all valid specializations: (T@constrained = Base) (T@constrained = Unrelated)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (T@constrained = Base) (T@constrained = Unrelated)]
reveal_type(is_subtype_of(Intersection[Base, Unrelated], T)) reveal_type(is_subtype_of(Intersection[Base, Unrelated], T))
static_assert(is_subtype_of(Intersection[Base, Unrelated], T))
def constrained_by_gradual[T: (Base, Any)](t: T) -> None: def constrained_by_gradual[T: (Base, Any)](t: T) -> None:
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_assignable_to(T, Super)) reveal_type(is_assignable_to(T, Super))
static_assert(is_assignable_to(T, Super))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_assignable_to(T, Base)) reveal_type(is_assignable_to(T, Base))
static_assert(is_assignable_to(T, Base))
# revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained_by_gradual ≠ Base)] # revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained_by_gradual ≠ Base)]
reveal_type(is_assignable_to(T, Sub)) reveal_type(is_assignable_to(T, Sub))
static_assert(not is_assignable_to(T, Sub))
# revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained_by_gradual ≠ Base)] # revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained_by_gradual ≠ Base)]
reveal_type(is_assignable_to(T, Unrelated)) reveal_type(is_assignable_to(T, Unrelated))
static_assert(not is_assignable_to(T, Unrelated))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_assignable_to(T, Any)) reveal_type(is_assignable_to(T, Any))
static_assert(is_assignable_to(T, Any))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_assignable_to(T, Super | Any)) reveal_type(is_assignable_to(T, Super | Any))
static_assert(is_assignable_to(T, Super | Any))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_assignable_to(T, Super | Unrelated)) reveal_type(is_assignable_to(T, Super | Unrelated))
static_assert(is_assignable_to(T, Super | Unrelated))
# revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained_by_gradual ≠ Base)] # revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained_by_gradual ≠ Base)]
reveal_type(is_assignable_to(Super, T)) reveal_type(is_assignable_to(Super, T))
static_assert(not is_assignable_to(Super, T))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_assignable_to(Base, T)) reveal_type(is_assignable_to(Base, T))
static_assert(is_assignable_to(Base, T))
# revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained_by_gradual ≠ Base)] # revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained_by_gradual ≠ Base)]
reveal_type(is_assignable_to(Unrelated, T)) reveal_type(is_assignable_to(Unrelated, T))
static_assert(not is_assignable_to(Unrelated, T))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_assignable_to(Any, T)) reveal_type(is_assignable_to(Any, T))
static_assert(is_assignable_to(Any, T))
# revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained_by_gradual ≠ Base)] # revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained_by_gradual ≠ Base)]
reveal_type(is_assignable_to(Super | Any, T)) reveal_type(is_assignable_to(Super | Any, T))
static_assert(not is_assignable_to(Super | Any, T))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_assignable_to(Base | Any, T)) reveal_type(is_assignable_to(Base | Any, T))
static_assert(is_assignable_to(Base | Any, T))
# revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained_by_gradual ≠ Base)] # revealed: ty_extensions.ConstraintSet[some valid specializations: (T@constrained_by_gradual ≠ Base)]
reveal_type(is_assignable_to(Super | Unrelated, T)) reveal_type(is_assignable_to(Super | Unrelated, T))
static_assert(not is_assignable_to(Super | Unrelated, T))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_assignable_to(Intersection[Base, Unrelated], T)) reveal_type(is_assignable_to(Intersection[Base, Unrelated], T))
static_assert(is_assignable_to(Intersection[Base, Unrelated], T))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_assignable_to(Intersection[Base, Any], T)) reveal_type(is_assignable_to(Intersection[Base, Any], T))
static_assert(is_assignable_to(Intersection[Base, Any], T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(T, Super)) reveal_type(is_subtype_of(T, Super))
static_assert(not is_subtype_of(T, Super))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(T, Base)) reveal_type(is_subtype_of(T, Base))
static_assert(not is_subtype_of(T, Base))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(T, Sub)) reveal_type(is_subtype_of(T, Sub))
static_assert(not is_subtype_of(T, Sub))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(T, Unrelated)) reveal_type(is_subtype_of(T, Unrelated))
static_assert(not is_subtype_of(T, Unrelated))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(T, Any)) reveal_type(is_subtype_of(T, Any))
static_assert(not is_subtype_of(T, Any))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(T, Super | Any)) reveal_type(is_subtype_of(T, Super | Any))
static_assert(not is_subtype_of(T, Super | Any))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(T, Super | Unrelated)) reveal_type(is_subtype_of(T, Super | Unrelated))
static_assert(not is_subtype_of(T, Super | Unrelated))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(Super, T)) reveal_type(is_subtype_of(Super, T))
static_assert(not is_subtype_of(Super, T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(Base, T)) reveal_type(is_subtype_of(Base, T))
static_assert(not is_subtype_of(Base, T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(Unrelated, T)) reveal_type(is_subtype_of(Unrelated, T))
static_assert(not is_subtype_of(Unrelated, T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(Any, T)) reveal_type(is_subtype_of(Any, T))
static_assert(not is_subtype_of(Any, T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(Super | Any, T)) reveal_type(is_subtype_of(Super | Any, T))
static_assert(not is_subtype_of(Super | Any, T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(Base | Any, T)) reveal_type(is_subtype_of(Base | Any, T))
static_assert(not is_subtype_of(Base | Any, T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(Super | Unrelated, T)) reveal_type(is_subtype_of(Super | Unrelated, T))
static_assert(not is_subtype_of(Super | Unrelated, T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(Intersection[Base, Unrelated], T)) reveal_type(is_subtype_of(Intersection[Base, Unrelated], T))
static_assert(not is_subtype_of(Intersection[Base, Unrelated], T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(Intersection[Base, Any], T)) reveal_type(is_subtype_of(Intersection[Base, Any], T))
static_assert(not is_subtype_of(Intersection[Base, Any], T))
``` ```
Two distinct fully static typevars are not subtypes of each other, even if they have the same Two distinct fully static typevars are not subtypes of each other, even if they have the same
@ -435,13 +655,19 @@ the same type.
def two_constrained[T: (int, str), U: (int, str)](t: T, u: U) -> None: def two_constrained[T: (int, str), U: (int, str)](t: T, u: U) -> None:
# revealed: ty_extensions.ConstraintSet[some valid specializations: ((T@two_constrained = str) ∧ (U@two_constrained = str)) ((T@two_constrained = int) ∧ (U@two_constrained = int))] # revealed: ty_extensions.ConstraintSet[some valid specializations: ((T@two_constrained = str) ∧ (U@two_constrained = str)) ((T@two_constrained = int) ∧ (U@two_constrained = int))]
reveal_type(is_assignable_to(T, U)) reveal_type(is_assignable_to(T, U))
static_assert(not is_assignable_to(T, U))
# revealed: ty_extensions.ConstraintSet[some valid specializations: ((U@two_constrained = str) ∧ (T@two_constrained = str)) ((U@two_constrained = int) ∧ (T@two_constrained = int))] # revealed: ty_extensions.ConstraintSet[some valid specializations: ((U@two_constrained = str) ∧ (T@two_constrained = str)) ((U@two_constrained = int) ∧ (T@two_constrained = int))]
reveal_type(is_assignable_to(U, T)) reveal_type(is_assignable_to(U, T))
static_assert(not is_assignable_to(U, T))
# revealed: ty_extensions.ConstraintSet[some valid specializations: ((T@two_constrained = str) ∧ (U@two_constrained = str)) ((T@two_constrained = int) ∧ (U@two_constrained = int))] # revealed: ty_extensions.ConstraintSet[some valid specializations: ((T@two_constrained = str) ∧ (U@two_constrained = str)) ((T@two_constrained = int) ∧ (U@two_constrained = int))]
reveal_type(is_subtype_of(T, U)) reveal_type(is_subtype_of(T, U))
static_assert(not is_subtype_of(T, U))
# revealed: ty_extensions.ConstraintSet[some valid specializations: ((U@two_constrained = str) ∧ (T@two_constrained = str)) ((U@two_constrained = int) ∧ (T@two_constrained = int))] # revealed: ty_extensions.ConstraintSet[some valid specializations: ((U@two_constrained = str) ∧ (T@two_constrained = str)) ((U@two_constrained = int) ∧ (T@two_constrained = int))]
reveal_type(is_subtype_of(U, T)) reveal_type(is_subtype_of(U, T))
static_assert(not is_subtype_of(U, T))
@final @final
class AnotherFinalClass: ... class AnotherFinalClass: ...
@ -449,13 +675,19 @@ class AnotherFinalClass: ...
def two_final_constrained[T: (FinalClass, AnotherFinalClass), U: (FinalClass, AnotherFinalClass)](t: T, u: U) -> None: def two_final_constrained[T: (FinalClass, AnotherFinalClass), U: (FinalClass, AnotherFinalClass)](t: T, u: U) -> None:
# revealed: ty_extensions.ConstraintSet[some valid specializations: ((T@two_final_constrained = AnotherFinalClass) ∧ (U@two_final_constrained = AnotherFinalClass)) ((T@two_final_constrained = FinalClass) ∧ (U@two_final_constrained = FinalClass))] # revealed: ty_extensions.ConstraintSet[some valid specializations: ((T@two_final_constrained = AnotherFinalClass) ∧ (U@two_final_constrained = AnotherFinalClass)) ((T@two_final_constrained = FinalClass) ∧ (U@two_final_constrained = FinalClass))]
reveal_type(is_assignable_to(T, U)) reveal_type(is_assignable_to(T, U))
static_assert(not is_assignable_to(T, U))
# revealed: ty_extensions.ConstraintSet[some valid specializations: ((U@two_final_constrained = AnotherFinalClass) ∧ (T@two_final_constrained = AnotherFinalClass)) ((U@two_final_constrained = FinalClass) ∧ (T@two_final_constrained = FinalClass))] # revealed: ty_extensions.ConstraintSet[some valid specializations: ((U@two_final_constrained = AnotherFinalClass) ∧ (T@two_final_constrained = AnotherFinalClass)) ((U@two_final_constrained = FinalClass) ∧ (T@two_final_constrained = FinalClass))]
reveal_type(is_assignable_to(U, T)) reveal_type(is_assignable_to(U, T))
static_assert(not is_assignable_to(U, T))
# revealed: ty_extensions.ConstraintSet[some valid specializations: ((T@two_final_constrained = AnotherFinalClass) ∧ (U@two_final_constrained = AnotherFinalClass)) ((T@two_final_constrained = FinalClass) ∧ (U@two_final_constrained = FinalClass))] # revealed: ty_extensions.ConstraintSet[some valid specializations: ((T@two_final_constrained = AnotherFinalClass) ∧ (U@two_final_constrained = AnotherFinalClass)) ((T@two_final_constrained = FinalClass) ∧ (U@two_final_constrained = FinalClass))]
reveal_type(is_subtype_of(T, U)) reveal_type(is_subtype_of(T, U))
static_assert(not is_subtype_of(T, U))
# revealed: ty_extensions.ConstraintSet[some valid specializations: ((U@two_final_constrained = AnotherFinalClass) ∧ (T@two_final_constrained = AnotherFinalClass)) ((U@two_final_constrained = FinalClass) ∧ (T@two_final_constrained = FinalClass))] # revealed: ty_extensions.ConstraintSet[some valid specializations: ((U@two_final_constrained = AnotherFinalClass) ∧ (T@two_final_constrained = AnotherFinalClass)) ((U@two_final_constrained = FinalClass) ∧ (T@two_final_constrained = FinalClass))]
reveal_type(is_subtype_of(U, T)) reveal_type(is_subtype_of(U, T))
static_assert(not is_subtype_of(U, T))
``` ```
A bound or constrained typevar is a subtype of itself in a union: A bound or constrained typevar is a subtype of itself in a union:
@ -464,13 +696,19 @@ A bound or constrained typevar is a subtype of itself in a union:
def union[T: Base, U: (Base, Unrelated)](t: T, u: U) -> None: def union[T: Base, U: (Base, Unrelated)](t: T, u: U) -> None:
# revealed: ty_extensions.ConstraintSet[all valid specializations: (T@union ≤ Base)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (T@union ≤ Base)]
reveal_type(is_assignable_to(T, T | None)) reveal_type(is_assignable_to(T, T | None))
static_assert(is_assignable_to(T, T | None))
# revealed: ty_extensions.ConstraintSet[all valid specializations: (U@union = Base) (U@union = Unrelated)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (U@union = Base) (U@union = Unrelated)]
reveal_type(is_assignable_to(U, U | None)) reveal_type(is_assignable_to(U, U | None))
static_assert(is_assignable_to(U, U | None))
# revealed: ty_extensions.ConstraintSet[all valid specializations: (T@union ≤ Base)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (T@union ≤ Base)]
reveal_type(is_subtype_of(T, T | None)) reveal_type(is_subtype_of(T, T | None))
static_assert(is_subtype_of(T, T | None))
# revealed: ty_extensions.ConstraintSet[all valid specializations: (U@union = Base) (U@union = Unrelated)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (U@union = Base) (U@union = Unrelated)]
reveal_type(is_subtype_of(U, U | None)) reveal_type(is_subtype_of(U, U | None))
static_assert(is_subtype_of(U, U | None))
``` ```
A bound or constrained typevar in a union with a dynamic type is assignable to the typevar: A bound or constrained typevar in a union with a dynamic type is assignable to the typevar:
@ -479,32 +717,44 @@ A bound or constrained typevar in a union with a dynamic type is assignable to t
def union_with_dynamic[T: Base, U: (Base, Unrelated)](t: T, u: U) -> None: def union_with_dynamic[T: Base, U: (Base, Unrelated)](t: T, u: U) -> None:
# revealed: ty_extensions.ConstraintSet[all valid specializations: (T@union_with_dynamic ≤ Base)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (T@union_with_dynamic ≤ Base)]
reveal_type(is_assignable_to(T | Any, T)) reveal_type(is_assignable_to(T | Any, T))
static_assert(is_assignable_to(T | Any, T))
# revealed: ty_extensions.ConstraintSet[all valid specializations: (U@union_with_dynamic = Base) (U@union_with_dynamic = Unrelated)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (U@union_with_dynamic = Base) (U@union_with_dynamic = Unrelated)]
reveal_type(is_assignable_to(U | Any, U)) reveal_type(is_assignable_to(U | Any, U))
static_assert(is_assignable_to(U | Any, U))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(T | Any, T)) reveal_type(is_subtype_of(T | Any, T))
static_assert(not is_subtype_of(T | Any, T))
# revealed: ty_extensions.ConstraintSet[never] # revealed: ty_extensions.ConstraintSet[never]
reveal_type(is_subtype_of(U | Any, U)) reveal_type(is_subtype_of(U | Any, U))
static_assert(not is_subtype_of(U | Any, U))
``` ```
And an intersection of a typevar with another type is always a subtype of the TypeVar: And an intersection of a typevar with another type is always a subtype of the TypeVar:
```py ```py
from ty_extensions import Intersection, Not, is_disjoint_from, static_assert from ty_extensions import Intersection, Not, is_disjoint_from
class A: ... class A: ...
def inter[T: Base, U: (Base, Unrelated)](t: T, u: U) -> None: def inter[T: Base, U: (Base, Unrelated)](t: T, u: U) -> None:
# revealed: ty_extensions.ConstraintSet[all valid specializations: (T@inter ≤ Base)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (T@inter ≤ Base)]
reveal_type(is_assignable_to(Intersection[T, Unrelated], T)) reveal_type(is_assignable_to(Intersection[T, Unrelated], T))
static_assert(is_assignable_to(Intersection[T, Unrelated], T))
# revealed: ty_extensions.ConstraintSet[all valid specializations: (T@inter ≤ Base)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (T@inter ≤ Base)]
reveal_type(is_subtype_of(Intersection[T, Unrelated], T)) reveal_type(is_subtype_of(Intersection[T, Unrelated], T))
static_assert(is_subtype_of(Intersection[T, Unrelated], T))
# revealed: ty_extensions.ConstraintSet[all valid specializations: (U@inter = Base) (U@inter = Unrelated)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (U@inter = Base) (U@inter = Unrelated)]
reveal_type(is_assignable_to(Intersection[U, A], U)) reveal_type(is_assignable_to(Intersection[U, A], U))
static_assert(is_assignable_to(Intersection[U, A], U))
# revealed: ty_extensions.ConstraintSet[all valid specializations: (U@inter = Base) (U@inter = Unrelated)] # revealed: ty_extensions.ConstraintSet[all valid specializations: (U@inter = Base) (U@inter = Unrelated)]
reveal_type(is_subtype_of(Intersection[U, A], U)) reveal_type(is_subtype_of(Intersection[U, A], U))
static_assert(is_subtype_of(Intersection[U, A], U))
static_assert(is_disjoint_from(Not[T], T)) static_assert(is_disjoint_from(Not[T], T))
static_assert(is_disjoint_from(T, Not[T])) static_assert(is_disjoint_from(T, Not[T]))
@ -801,18 +1051,24 @@ The intersection of a typevar with any other type is assignable to (and if fully
of) itself. of) itself.
```py ```py
from ty_extensions import is_assignable_to, is_subtype_of, Not from ty_extensions import is_assignable_to, is_subtype_of, Not, static_assert
def intersection_is_assignable[T](t: T) -> None: def intersection_is_assignable[T](t: T) -> None:
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_assignable_to(Intersection[T, None], T)) reveal_type(is_assignable_to(Intersection[T, None], T))
static_assert(is_assignable_to(Intersection[T, None], T))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_assignable_to(Intersection[T, Not[None]], T)) reveal_type(is_assignable_to(Intersection[T, Not[None]], T))
static_assert(is_assignable_to(Intersection[T, Not[None]], T))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_subtype_of(Intersection[T, None], T)) reveal_type(is_subtype_of(Intersection[T, None], T))
static_assert(is_subtype_of(Intersection[T, None], T))
# revealed: ty_extensions.ConstraintSet[always] # revealed: ty_extensions.ConstraintSet[always]
reveal_type(is_subtype_of(Intersection[T, Not[None]], T)) reveal_type(is_subtype_of(Intersection[T, Not[None]], T))
static_assert(is_subtype_of(Intersection[T, Not[None]], T))
``` ```
## Narrowing ## Narrowing