@@ -6183,21 +6183,23 @@ def find_isinstance_check_helper(
61836183 attr = try_getting_str_literals (node .args [1 ], self .lookup_type (node .args [1 ]))
61846184 if literal (expr ) == LITERAL_TYPE and attr and len (attr ) == 1 :
61856185 return self .hasattr_type_maps (expr , self .lookup_type (expr ), attr [0 ])
6186- elif isinstance (node .callee , RefExpr ):
6187- if node .callee .type_guard is not None or node .callee .type_is is not None :
6186+ elif isinstance (node .callee , (RefExpr , CallExpr )):
6187+ type_is , type_guard = None , None
6188+ # the first argument might be used as a kwarg
6189+ called_type = get_proper_type (self .lookup_type (node .callee ))
6190+
6191+ # TODO: there are some more cases in check_call() to handle.
6192+ if isinstance (called_type , Instance ):
6193+ call = find_member ("__call__" , called_type , called_type , is_operator = True )
6194+ if call is not None :
6195+ called_type = get_proper_type (call )
6196+ if isinstance (called_type , CallableType ):
6197+ type_is , type_guard = called_type .type_is , called_type .type_guard
6198+ if isinstance (node .callee , RefExpr ):
6199+ type_is , type_guard = node .callee .type_is , node .callee .type_guard
6200+ if type_guard is not None or type_is is not None :
61886201 # TODO: Follow *args, **kwargs
61896202 if node .arg_kinds [0 ] != nodes .ARG_POS :
6190- # the first argument might be used as a kwarg
6191- called_type = get_proper_type (self .lookup_type (node .callee ))
6192-
6193- # TODO: there are some more cases in check_call() to handle.
6194- if isinstance (called_type , Instance ):
6195- call = find_member (
6196- "__call__" , called_type , called_type , is_operator = True
6197- )
6198- if call is not None :
6199- called_type = get_proper_type (call )
6200-
62016203 # *assuming* the overloaded function is correct, there's a couple cases:
62026204 # 1) The first argument has different names, but is pos-only. We don't
62036205 # care about this case, the argument must be passed positionally.
@@ -6210,9 +6212,7 @@ def find_isinstance_check_helper(
62106212 # we want the idx-th variable to be narrowed
62116213 expr = collapse_walrus (node .args [idx ])
62126214 else :
6213- kind = (
6214- "guard" if node .callee .type_guard is not None else "narrower"
6215- )
6215+ kind = "guard" if type_guard is not None else "narrower"
62166216 self .fail (
62176217 message_registry .TYPE_GUARD_POS_ARG_REQUIRED .format (kind ), node
62186218 )
@@ -6223,71 +6223,20 @@ def find_isinstance_check_helper(
62236223 # considered "always right" (i.e. even if the types are not overlapping).
62246224 # Also note that a care must be taken to unwrap this back at read places
62256225 # where we use this to narrow down declared type.
6226- if node . callee . type_guard is not None :
6227- return {expr : TypeGuardedType (node . callee . type_guard )}, {}
6226+ if type_guard is not None :
6227+ return {expr : TypeGuardedType (type_guard )}, {}
62286228 else :
6229- assert node . callee . type_is is not None
6229+ assert type_is is not None
62306230 return conditional_types_to_typemaps (
62316231 expr ,
62326232 * self .conditional_types_with_intersection (
62336233 self .lookup_type (expr ),
6234- [TypeRange (node . callee . type_is , is_upper_bound = False )],
6234+ [TypeRange (type_is , is_upper_bound = False )],
62356235 expr ,
62366236 consider_runtime_isinstance = False ,
62376237 ),
62386238 )
6239- elif isinstance (node .callee , CallExpr ) and len (node .args ) != 0 :
6240- # Handle case where callee is a call expression like E()(x)
6241- # where E() returns an object with __call__ method that has TypeGuard
6242- callee_type = get_proper_type (self .lookup_type (node .callee ))
6243- if isinstance (callee_type , Instance ):
6244- call_member = find_member (
6245- "__call__" , callee_type , callee_type , is_operator = True
6246- )
6247- if call_member is not None :
6248- call_type = get_proper_type (call_member )
6249- # Check if the __call__ method has type_guard or type_is
6250- if isinstance (call_type , CallableType ) and (
6251- call_type .type_guard is not None or call_type .type_is is not None
6252- ):
6253- # Handle keyword arguments similar to RefExpr case
6254- expr = collapse_walrus (node .args [0 ]) # Default to first positional arg
6255- if node .arg_kinds [0 ] != nodes .ARG_POS :
6256- if call_type .arg_names :
6257- name = call_type .arg_names [0 ]
6258- if name in node .arg_names :
6259- idx = node .arg_names .index (name )
6260- # we want the idx-th variable to be narrowed
6261- expr = collapse_walrus (node .args [idx ])
6262- else :
6263- kind = (
6264- "guard"
6265- if call_type .type_guard is not None
6266- else "narrower"
6267- )
6268- self .fail (
6269- message_registry .TYPE_GUARD_POS_ARG_REQUIRED .format (
6270- kind
6271- ),
6272- node ,
6273- )
6274- return {}, {}
6275-
6276- if literal (expr ) == LITERAL_TYPE :
6277- # Apply the same TypeGuard narrowing logic
6278- if call_type .type_guard is not None :
6279- return {expr : TypeGuardedType (call_type .type_guard )}, {}
6280- else :
6281- assert call_type .type_is is not None
6282- return conditional_types_to_typemaps (
6283- expr ,
6284- * self .conditional_types_with_intersection (
6285- self .lookup_type (expr ),
6286- [TypeRange (call_type .type_is , is_upper_bound = False )],
6287- expr ,
6288- consider_runtime_isinstance = False ,
6289- ),
6290- )
6239+
62916240 elif isinstance (node , ComparisonExpr ):
62926241 return self .comparison_type_narrowing_helper (node )
62936242 elif isinstance (node , AssignmentExpr ):
0 commit comments