MCPcopy Index your code
hub / github.com/python/mypy / check_op_reversible

Method check_op_reversible

mypy/checkexpr.py:4113–4257  ·  view source on GitHub ↗
(
        self,
        op_name: str,
        left_type: Type,
        left_expr: Expression,
        right_type: Type,
        right_expr: Expression,
        context: Context,
    )

Source from the content-addressed store, hash-verified

4111 return None
4112
4113 def check_op_reversible(
4114 self,
4115 op_name: str,
4116 left_type: Type,
4117 left_expr: Expression,
4118 right_type: Type,
4119 right_expr: Expression,
4120 context: Context,
4121 ) -> tuple[Type, Type]:
4122 left_type = get_proper_type(left_type)
4123 right_type = get_proper_type(right_type)
4124
4125 # If either the LHS or the RHS are Any, we can't really conclude anything
4126 # about the operation since the Any type may or may not define an
4127 # __op__ or __rop__ method. So, we punt and return Any instead.
4128
4129 if isinstance(left_type, AnyType):
4130 any_type = AnyType(TypeOfAny.from_another_any, source_any=left_type)
4131 return any_type, any_type
4132 if isinstance(right_type, AnyType):
4133 any_type = AnyType(TypeOfAny.from_another_any, source_any=right_type)
4134 return any_type, any_type
4135
4136 # STEP 1:
4137 # We start by getting the __op__ and __rop__ methods, if they exist.
4138
4139 rev_op_name = operators.reverse_op_methods[op_name]
4140
4141 left_op = self.lookup_operator(op_name, left_type, context)
4142 right_op = self.lookup_operator(rev_op_name, right_type, context)
4143
4144 # STEP 2a:
4145 # We figure out in which order Python will call the operator methods. As it
4146 # turns out, it's not as simple as just trying to call __op__ first and
4147 # __rop__ second.
4148 #
4149 # We store the determined order inside the 'variants_raw' variable,
4150 # which records tuples containing the method, base type, and the argument.
4151
4152 if op_name in operators.op_methods_that_shortcut and is_same_type(left_type, right_type):
4153 # When we do "A() + A()", for example, Python will only call the __add__ method,
4154 # never the __radd__ method.
4155 #
4156 # This is the case even if the __add__ method is completely missing and the __radd__
4157 # method is defined.
4158
4159 variants_raw = [(op_name, left_op, left_type, right_expr)]
4160 elif (
4161 (
4162 # Checking (A implies B) using the logically equivalent (not A or B), where
4163 # A: left and right are both `Instance` objects
4164 # B: right's __rop__ method is different from left's __op__ method
4165 not (isinstance(left_type, Instance) and isinstance(right_type, Instance))
4166 or (
4167 self.lookup_definer(left_type, op_name)
4168 != self.lookup_definer(right_type, rev_op_name)
4169 and (
4170 left_type.type.alt_promote is None

Callers 1

check_opMethod · 0.95

Calls 15

lookup_operatorMethod · 0.95
lookup_definerMethod · 0.95
check_method_callMethod · 0.95
get_proper_typeFunction · 0.90
AnyTypeClass · 0.90
is_same_typeFunction · 0.90
covers_at_runtimeFunction · 0.90
isinstanceFunction · 0.85
lenFunction · 0.85
filter_errorsMethod · 0.80
has_new_errorsMethod · 0.80

Tested by

no test coverage detected