@@ -6156,6 +6156,9 @@ def find_isinstance_check_helper(
61566156
61576157 if isinstance (node , CallExpr ) and len (node .args ) != 0 :
61586158 expr = collapse_walrus (node .args [0 ])
6159+ print ("[TypeGuard Debug] --- find_isinstance_check_helper ---" )
6160+ print (f"[TypeGuard Debug] { node = } " )
6161+ print (f"[TypeGuard Debug] { node .callee = } " )
61596162 if refers_to_fullname (node .callee , "builtins.isinstance" ):
61606163 if len (node .args ) != 2 : # the error will be reported elsewhere
61616164 return {}, {}
@@ -6236,6 +6239,68 @@ def find_isinstance_check_helper(
62366239 consider_runtime_isinstance = False ,
62376240 ),
62386241 )
6242+ elif isinstance (node .callee , CallExpr ):
6243+ # Handle case where callee is a call expression like E()(x)
6244+ # where E() returns an object with __call__ method that has TypeGuard
6245+ if len (node .args ) == 0 :
6246+ return {}, {}
6247+ callee_type = get_proper_type (self .lookup_type (node .callee ))
6248+ if isinstance (callee_type , Instance ):
6249+ call_member = find_member (
6250+ "__call__" , callee_type , callee_type , is_operator = True
6251+ )
6252+ if call_member is not None :
6253+ call_type = get_proper_type (call_member )
6254+ # Check if the __call__ method has type_guard or type_is
6255+ if isinstance (call_type , CallableType ) and (
6256+ call_type .type_guard is not None or call_type .type_is is not None
6257+ ):
6258+ # Handle keyword arguments similar to RefExpr case
6259+ expr = collapse_walrus (node .args [0 ]) # Default to first positional arg
6260+ if node .arg_kinds [0 ] != nodes .ARG_POS :
6261+ # the first argument might be used as a kwarg
6262+ if isinstance (call_type , (CallableType , Overloaded )):
6263+ if isinstance (call_type , Overloaded ):
6264+ # Use first overload for argument name lookup
6265+ first_callable = call_type .items [0 ]
6266+ else :
6267+ first_callable = call_type
6268+
6269+ if first_callable .arg_names :
6270+ name = first_callable .arg_names [0 ]
6271+ if name in node .arg_names :
6272+ idx = node .arg_names .index (name )
6273+ # we want the idx-th variable to be narrowed
6274+ expr = collapse_walrus (node .args [idx ])
6275+ else :
6276+ kind = (
6277+ "guard"
6278+ if call_type .type_guard is not None
6279+ else "narrower"
6280+ )
6281+ self .fail (
6282+ message_registry .TYPE_GUARD_POS_ARG_REQUIRED .format (
6283+ kind
6284+ ),
6285+ node ,
6286+ )
6287+ return {}, {}
6288+
6289+ if literal (expr ) == LITERAL_TYPE :
6290+ # Apply the same TypeGuard narrowing logic
6291+ if call_type .type_guard is not None :
6292+ return {expr : TypeGuardedType (call_type .type_guard )}, {}
6293+ else :
6294+ assert call_type .type_is is not None
6295+ return conditional_types_to_typemaps (
6296+ expr ,
6297+ * self .conditional_types_with_intersection (
6298+ self .lookup_type (expr ),
6299+ [TypeRange (call_type .type_is , is_upper_bound = False )],
6300+ expr ,
6301+ consider_runtime_isinstance = False ,
6302+ ),
6303+ )
62396304 elif isinstance (node , ComparisonExpr ):
62406305 return self .comparison_type_narrowing_helper (node )
62416306 elif isinstance (node , AssignmentExpr ):
0 commit comments