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)
752
752
a_instance: A = use_a_class_container(b_container) # This should work
753
753
```
754
754
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
+
755
785
## Inheriting from generic classes with inferred variance
756
786
757
787
When 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]))
837
867
838
868
[ linear-time-variance-talk ] : https://www.youtube.com/watch?v=7uixlNTOY4s&t=9705s
839
869
[ 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> {
6620
6620
. map ( |ty| ty. variance_of ( db, typevar) )
6621
6621
. collect ( ) ,
6622
6622
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) ,
6623
6624
Type :: Dynamic ( _)
6624
6625
| Type :: Never
6625
6626
| Type :: WrapperDescriptor ( _)
@@ -6640,7 +6641,6 @@ impl<'db> VarianceInferable<'db> for Type<'db> {
6640
6641
| Type :: BoundSuper ( _)
6641
6642
| Type :: TypeVar ( _)
6642
6643
| Type :: NonInferableTypeVar ( _)
6643
- | Type :: TypeIs ( _)
6644
6644
| Type :: TypedDict ( _)
6645
6645
| Type :: TypeAlias ( _) => TypeVarVariance :: Bivariant ,
6646
6646
} ;
@@ -10956,6 +10956,16 @@ impl<'db> TypeIsType<'db> {
10956
10956
}
10957
10957
}
10958
10958
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
+
10959
10969
/// Walk the MRO of this class and return the last class just before the specified known base.
10960
10970
/// This can be used to determine upper bounds for `Self` type variables on methods that are
10961
10971
/// being added to the given class.
You can’t perform that action at this time.
0 commit comments