@@ -6218,21 +6218,26 @@ def find_isinstance_check_helper(
62186218 attr = try_getting_str_literals (node .args [1 ], self .lookup_type (node .args [1 ]))
62196219 if literal (expr ) == LITERAL_TYPE and attr and len (attr ) == 1 :
62206220 return self .hasattr_type_maps (expr , self .lookup_type (expr ), attr [0 ])
6221- elif isinstance (node .callee , RefExpr ):
6222- if node .callee .type_guard is not None or node .callee .type_is is not None :
6221+ else :
6222+ type_is , type_guard = None , None
6223+ called_type = self .lookup_type_or_none (node .callee )
6224+ if called_type is not None :
6225+ called_type = get_proper_type (called_type )
6226+ # TODO: there are some more cases in check_call() to handle.
6227+ # If the callee is an instance, try to extract TypeGuard/TypeIs from its __call__ method.
6228+ if isinstance (called_type , Instance ):
6229+ call = find_member ("__call__" , called_type , called_type , is_operator = True )
6230+ if call is not None :
6231+ called_type = get_proper_type (call )
6232+ if isinstance (called_type , CallableType ):
6233+ type_is , type_guard = called_type .type_is , called_type .type_guard
6234+
6235+ # If the callee is a RefExpr, extract TypeGuard/TypeIs directly.
6236+ if isinstance (node .callee , RefExpr ):
6237+ type_is , type_guard = node .callee .type_is , node .callee .type_guard
6238+ if type_guard is not None or type_is is not None :
62236239 # TODO: Follow *args, **kwargs
62246240 if node .arg_kinds [0 ] != nodes .ARG_POS :
6225- # the first argument might be used as a kwarg
6226- called_type = get_proper_type (self .lookup_type (node .callee ))
6227-
6228- # TODO: there are some more cases in check_call() to handle.
6229- if isinstance (called_type , Instance ):
6230- call = find_member (
6231- "__call__" , called_type , called_type , is_operator = True
6232- )
6233- if call is not None :
6234- called_type = get_proper_type (call )
6235-
62366241 # *assuming* the overloaded function is correct, there's a couple cases:
62376242 # 1) The first argument has different names, but is pos-only. We don't
62386243 # care about this case, the argument must be passed positionally.
@@ -6245,9 +6250,7 @@ def find_isinstance_check_helper(
62456250 # we want the idx-th variable to be narrowed
62466251 expr = collapse_walrus (node .args [idx ])
62476252 else :
6248- kind = (
6249- "guard" if node .callee .type_guard is not None else "narrower"
6250- )
6253+ kind = "guard" if type_guard is not None else "narrower"
62516254 self .fail (
62526255 message_registry .TYPE_GUARD_POS_ARG_REQUIRED .format (kind ), node
62536256 )
@@ -6258,15 +6261,15 @@ def find_isinstance_check_helper(
62586261 # considered "always right" (i.e. even if the types are not overlapping).
62596262 # Also note that a care must be taken to unwrap this back at read places
62606263 # where we use this to narrow down declared type.
6261- if node . callee . type_guard is not None :
6262- return {expr : TypeGuardedType (node . callee . type_guard )}, {}
6264+ if type_guard is not None :
6265+ return {expr : TypeGuardedType (type_guard )}, {}
62636266 else :
6264- assert node . callee . type_is is not None
6267+ assert type_is is not None
62656268 return conditional_types_to_typemaps (
62666269 expr ,
62676270 * self .conditional_types_with_intersection (
62686271 self .lookup_type (expr ),
6269- [TypeRange (node . callee . type_is , is_upper_bound = False )],
6272+ [TypeRange (type_is , is_upper_bound = False )],
62706273 expr ,
62716274 consider_runtime_isinstance = False ,
62726275 ),
0 commit comments