@@ -1203,6 +1203,22 @@ def check_func_def(
1203
1203
# visible from *inside* of this function/method.
1204
1204
ref_type : Type | None = self .scope .active_self_type ()
1205
1205
1206
+ if typ .type_is :
1207
+ arg_index = 0
1208
+ # For methods and classmethods, we want the second parameter
1209
+ if ref_type is not None and (not defn .is_static or defn .name == "__new__" ):
1210
+ arg_index = 1
1211
+ if arg_index < len (typ .arg_types ) and not is_subtype (
1212
+ typ .type_is , typ .arg_types [arg_index ]
1213
+ ):
1214
+ self .fail (
1215
+ message_registry .NARROWED_TYPE_NOT_SUBTYPE .format (
1216
+ format_type (typ .type_is , self .options ),
1217
+ format_type (typ .arg_types [arg_index ], self .options ),
1218
+ ),
1219
+ item ,
1220
+ )
1221
+
1206
1222
# Store argument types.
1207
1223
for i in range (len (typ .arg_types )):
1208
1224
arg_type = typ .arg_types [i ]
@@ -2178,6 +2194,8 @@ def check_override(
2178
2194
elif isinstance (original , CallableType ) and isinstance (override , CallableType ):
2179
2195
if original .type_guard is not None and override .type_guard is None :
2180
2196
fail = True
2197
+ if original .type_is is not None and override .type_is is None :
2198
+ fail = True
2181
2199
2182
2200
if is_private (name ):
2183
2201
fail = False
@@ -5643,7 +5661,7 @@ def combine_maps(list_maps: list[TypeMap]) -> TypeMap:
5643
5661
def find_isinstance_check (self , node : Expression ) -> tuple [TypeMap , TypeMap ]:
5644
5662
"""Find any isinstance checks (within a chain of ands). Includes
5645
5663
implicit and explicit checks for None and calls to callable.
5646
- Also includes TypeGuard functions.
5664
+ Also includes TypeGuard and TypeIs functions.
5647
5665
5648
5666
Return value is a map of variables to their types if the condition
5649
5667
is true and a map of variables to their types if the condition is false.
@@ -5695,7 +5713,7 @@ def find_isinstance_check_helper(self, node: Expression) -> tuple[TypeMap, TypeM
5695
5713
if literal (expr ) == LITERAL_TYPE and attr and len (attr ) == 1 :
5696
5714
return self .hasattr_type_maps (expr , self .lookup_type (expr ), attr [0 ])
5697
5715
elif isinstance (node .callee , RefExpr ):
5698
- if node .callee .type_guard is not None :
5716
+ if node .callee .type_guard is not None or node . callee . type_is is not None :
5699
5717
# TODO: Follow *args, **kwargs
5700
5718
if node .arg_kinds [0 ] != nodes .ARG_POS :
5701
5719
# the first argument might be used as a kwarg
@@ -5721,15 +5739,31 @@ def find_isinstance_check_helper(self, node: Expression) -> tuple[TypeMap, TypeM
5721
5739
# we want the idx-th variable to be narrowed
5722
5740
expr = collapse_walrus (node .args [idx ])
5723
5741
else :
5724
- self .fail (message_registry .TYPE_GUARD_POS_ARG_REQUIRED , node )
5742
+ kind = (
5743
+ "guard" if node .callee .type_guard is not None else "narrower"
5744
+ )
5745
+ self .fail (
5746
+ message_registry .TYPE_GUARD_POS_ARG_REQUIRED .format (kind ), node
5747
+ )
5725
5748
return {}, {}
5726
5749
if literal (expr ) == LITERAL_TYPE :
5727
5750
# Note: we wrap the target type, so that we can special case later.
5728
5751
# Namely, for isinstance() we use a normal meet, while TypeGuard is
5729
5752
# considered "always right" (i.e. even if the types are not overlapping).
5730
5753
# Also note that a care must be taken to unwrap this back at read places
5731
5754
# where we use this to narrow down declared type.
5732
- return {expr : TypeGuardedType (node .callee .type_guard )}, {}
5755
+ if node .callee .type_guard is not None :
5756
+ return {expr : TypeGuardedType (node .callee .type_guard )}, {}
5757
+ else :
5758
+ assert node .callee .type_is is not None
5759
+ return conditional_types_to_typemaps (
5760
+ expr ,
5761
+ * self .conditional_types_with_intersection (
5762
+ self .lookup_type (expr ),
5763
+ [TypeRange (node .callee .type_is , is_upper_bound = False )],
5764
+ expr ,
5765
+ ),
5766
+ )
5733
5767
elif isinstance (node , ComparisonExpr ):
5734
5768
# Step 1: Obtain the types of each operand and whether or not we can
5735
5769
# narrow their types. (For example, we shouldn't try narrowing the
0 commit comments