107107 OperatorAssignmentStmt ,
108108 OpExpr ,
109109 OverloadedFuncDef ,
110+ OverloadPart ,
110111 PassStmt ,
111112 PromoteExpr ,
112113 RaiseStmt ,
@@ -407,6 +408,11 @@ def __init__(
407408 # argument through various `checker` and `checkmember` functions.
408409 self ._is_final_def = False
409410
411+ # Track when we enter an overload implementation. Some checks should not be applied
412+ # to the implementation signature when specific overloads are available.
413+ # Use `enter_overload_impl` to modify.
414+ self .overload_impl_stack : list [OverloadPart ] = []
415+
410416 # This flag is set when we run type-check or attribute access check for the purpose
411417 # of giving a note on possibly missing "await". It is used to avoid infinite recursion.
412418 self .checking_missing_await = False
@@ -709,7 +715,8 @@ def _visit_overloaded_func_def(self, defn: OverloadedFuncDef) -> None:
709715 if num_abstract not in (0 , len (defn .items )):
710716 self .fail (message_registry .INCONSISTENT_ABSTRACT_OVERLOAD , defn )
711717 if defn .impl :
712- defn .impl .accept (self )
718+ with self .enter_overload_impl (defn .impl ):
719+ defn .impl .accept (self )
713720 if not defn .is_property :
714721 self .check_overlapping_overloads (defn )
715722 if defn .type is None :
@@ -752,6 +759,14 @@ def _visit_overloaded_func_def(self, defn: OverloadedFuncDef) -> None:
752759 self .check_explicit_override_decorator (defn , found_method_base_classes , defn .impl )
753760 self .check_inplace_operator_method (defn )
754761
762+ @contextmanager
763+ def enter_overload_impl (self , impl : OverloadPart ) -> Iterator [None ]:
764+ self .overload_impl_stack .append (impl )
765+ try :
766+ yield
767+ finally :
768+ assert self .overload_impl_stack .pop () == impl
769+
755770 def extract_callable_type (self , inner_type : Type | None , ctx : Context ) -> CallableType | None :
756771 """Get type as seen by an overload item caller."""
757772 inner_type = get_proper_type (inner_type )
@@ -1278,7 +1293,11 @@ def check_func_def(
12781293 )
12791294
12801295 if name : # Special method names
1281- if defn .info and self .is_reverse_op_method (name ):
1296+ if (
1297+ defn .info
1298+ and self .is_reverse_op_method (name )
1299+ and defn not in self .overload_impl_stack
1300+ ):
12821301 self .check_reverse_op_method (item , typ , name , defn )
12831302 elif name in ("__getattr__" , "__getattribute__" ):
12841303 self .check_getattr_method (typ , defn , name )
@@ -6166,6 +6185,7 @@ def find_isinstance_check_helper(
61666185 self .lookup_type (expr ),
61676186 [TypeRange (node .callee .type_is , is_upper_bound = False )],
61686187 expr ,
6188+ consider_runtime_isinstance = False ,
61696189 ),
61706190 )
61716191 elif isinstance (node , ComparisonExpr ):
@@ -7593,11 +7613,19 @@ def conditional_types_with_intersection(
75937613 type_ranges : list [TypeRange ] | None ,
75947614 ctx : Context ,
75957615 default : None = None ,
7616+ * ,
7617+ consider_runtime_isinstance : bool = True ,
75967618 ) -> tuple [Type | None , Type | None ]: ...
75977619
75987620 @overload
75997621 def conditional_types_with_intersection (
7600- self , expr_type : Type , type_ranges : list [TypeRange ] | None , ctx : Context , default : Type
7622+ self ,
7623+ expr_type : Type ,
7624+ type_ranges : list [TypeRange ] | None ,
7625+ ctx : Context ,
7626+ default : Type ,
7627+ * ,
7628+ consider_runtime_isinstance : bool = True ,
76017629 ) -> tuple [Type , Type ]: ...
76027630
76037631 def conditional_types_with_intersection (
@@ -7606,8 +7634,15 @@ def conditional_types_with_intersection(
76067634 type_ranges : list [TypeRange ] | None ,
76077635 ctx : Context ,
76087636 default : Type | None = None ,
7637+ * ,
7638+ consider_runtime_isinstance : bool = True ,
76097639 ) -> tuple [Type | None , Type | None ]:
7610- initial_types = conditional_types (expr_type , type_ranges , default )
7640+ initial_types = conditional_types (
7641+ expr_type ,
7642+ type_ranges ,
7643+ default ,
7644+ consider_runtime_isinstance = consider_runtime_isinstance ,
7645+ )
76117646 # For some reason, doing "yes_map, no_map = conditional_types_to_typemaps(...)"
76127647 # doesn't work: mypyc will decide that 'yes_map' is of type None if we try.
76137648 yes_type : Type | None = initial_types [0 ]
@@ -7919,18 +7954,30 @@ def visit_type_var(self, t: TypeVarType) -> None:
79197954
79207955@overload
79217956def conditional_types (
7922- current_type : Type , proposed_type_ranges : list [TypeRange ] | None , default : None = None
7957+ current_type : Type ,
7958+ proposed_type_ranges : list [TypeRange ] | None ,
7959+ default : None = None ,
7960+ * ,
7961+ consider_runtime_isinstance : bool = True ,
79237962) -> tuple [Type | None , Type | None ]: ...
79247963
79257964
79267965@overload
79277966def conditional_types (
7928- current_type : Type , proposed_type_ranges : list [TypeRange ] | None , default : Type
7967+ current_type : Type ,
7968+ proposed_type_ranges : list [TypeRange ] | None ,
7969+ default : Type ,
7970+ * ,
7971+ consider_runtime_isinstance : bool = True ,
79297972) -> tuple [Type , Type ]: ...
79307973
79317974
79327975def conditional_types (
7933- current_type : Type , proposed_type_ranges : list [TypeRange ] | None , default : Type | None = None
7976+ current_type : Type ,
7977+ proposed_type_ranges : list [TypeRange ] | None ,
7978+ default : Type | None = None ,
7979+ * ,
7980+ consider_runtime_isinstance : bool = True ,
79347981) -> tuple [Type | None , Type | None ]:
79357982 """Takes in the current type and a proposed type of an expression.
79367983
@@ -7972,7 +8019,11 @@ def conditional_types(
79728019 if not type_range .is_upper_bound
79738020 ]
79748021 )
7975- remaining_type = restrict_subtype_away (current_type , proposed_precise_type )
8022+ remaining_type = restrict_subtype_away (
8023+ current_type ,
8024+ proposed_precise_type ,
8025+ consider_runtime_isinstance = consider_runtime_isinstance ,
8026+ )
79768027 return proposed_type , remaining_type
79778028 else :
79788029 # An isinstance check, but we don't understand the type
0 commit comments