File tree Expand file tree Collapse file tree 2 files changed +42
-1
lines changed
crates/ty_python_semantic
resources/mdtest/generics/pep695 Expand file tree Collapse file tree 2 files changed +42
-1
lines changed Original file line number Diff line number Diff line change @@ -752,6 +752,36 @@ b_container = ClassContainer[B](B)
752752a_instance: A = use_a_class_container(b_container) # This should work
753753```
754754
755+ ## TypeIs
756+
757+ ``` toml
758+ [environment ]
759+ python-version = " 3.13"
760+ ```
761+
762+ ` TypeIs[T] ` is invariant in ` T ` . See the [ typing spec] [ typeis-spec ] for a justification.
763+
764+ ``` py
765+ from typing import TypeIs
766+ from ty_extensions import is_assignable_to, is_subtype_of, static_assert
767+
768+ class A :
769+ pass
770+
771+ class B (A ):
772+ pass
773+
774+ class C[T]:
775+ def check (x : object ) -> TypeIs[T]:
776+ # this is a bad check, but we only care about it type-checking
777+ return False
778+
779+ static_assert(not is_subtype_of(C[B], C[A]))
780+ static_assert(not is_subtype_of(C[A], C[B]))
781+ static_assert(not is_assignable_to(C[B], C[A]))
782+ static_assert(not is_assignable_to(C[A], C[B]))
783+ ```
784+
755785## Inheriting from generic classes with inferred variance
756786
757787When inheriting from a generic class with our type variable substituted in, we count its occurrences
@@ -837,3 +867,4 @@ static_assert(is_subtype_of(DerivedContravariant[A], DerivedContravariant[B]))
837867
838868[ linear-time-variance-talk ] : https://www.youtube.com/watch?v=7uixlNTOY4s&t=9705s
839869[ spec ] : https://typing.python.org/en/latest/spec/generics.html#variance
870+ [ typeis-spec ] : https://typing.python.org/en/latest/spec/narrowing.html#typeis
Original file line number Diff line number Diff line change @@ -6620,6 +6620,7 @@ impl<'db> VarianceInferable<'db> for Type<'db> {
66206620 . map ( |ty| ty. variance_of ( db, typevar) )
66216621 . collect ( ) ,
66226622 Type :: SubclassOf ( subclass_of_type) => subclass_of_type. variance_of ( db, typevar) ,
6623+ Type :: TypeIs ( type_is_type) => type_is_type. variance_of ( db, typevar) ,
66236624 Type :: Dynamic ( _)
66246625 | Type :: Never
66256626 | Type :: WrapperDescriptor ( _)
@@ -6640,7 +6641,6 @@ impl<'db> VarianceInferable<'db> for Type<'db> {
66406641 | Type :: BoundSuper ( _)
66416642 | Type :: TypeVar ( _)
66426643 | Type :: NonInferableTypeVar ( _)
6643- | Type :: TypeIs ( _)
66446644 | Type :: TypedDict ( _)
66456645 | Type :: TypeAlias ( _) => TypeVarVariance :: Bivariant ,
66466646 } ;
@@ -10956,6 +10956,16 @@ impl<'db> TypeIsType<'db> {
1095610956 }
1095710957}
1095810958
10959+ impl < ' db > VarianceInferable < ' db > for TypeIsType < ' db > {
10960+ // See the [typing spec] on why `TypeIs` is invariant in its type.
10961+ // [typing spec]: https://typing.python.org/en/latest/spec/narrowing.html#typeis
10962+ fn variance_of ( self , db : & ' db dyn Db , typevar : BoundTypeVarInstance < ' db > ) -> TypeVarVariance {
10963+ self . return_type ( db)
10964+ . with_polarity ( TypeVarVariance :: Invariant )
10965+ . variance_of ( db, typevar)
10966+ }
10967+ }
10968+
1095910969/// Walk the MRO of this class and return the last class just before the specified known base.
1096010970/// This can be used to determine upper bounds for `Self` type variables on methods that are
1096110971/// being added to the given class.
You can’t perform that action at this time.
0 commit comments