@@ -427,7 +427,7 @@ def analyze_static_reference(
427427 # We special case NoneType, because its stub definition is not related to None.
428428 return TypeType (NoneType ())
429429 else :
430- return type_object_type (node , self . named_type )
430+ return type_object_type (node )
431431 elif isinstance (node , TypeAlias ):
432432 # Something that refers to a type alias appears in runtime context.
433433 # Note that we suppress bogus errors for alias redefinitions,
@@ -1908,7 +1908,7 @@ def analyze_type_type_callee(self, item: ProperType, context: Context) -> Type:
19081908 if isinstance (item , AnyType ):
19091909 return AnyType (TypeOfAny .from_another_any , source_any = item )
19101910 if isinstance (item , Instance ):
1911- res = type_object_type (item .type , self . named_type )
1911+ res = type_object_type (item .type )
19121912 if isinstance (res , CallableType ):
19131913 res = res .copy_modified (from_type_type = True )
19141914 expanded = expand_type_by_instance (res , item )
@@ -4076,6 +4076,44 @@ def check_method_call(
40764076 object_type = base_type ,
40774077 )
40784078
4079+ def lookup_operator (self , op_name : str , base_type : Type , context : Context ) -> Type | None :
4080+ """Looks up the given operator and returns the corresponding type,
4081+ if it exists."""
4082+
4083+ # This check is an important performance optimization.
4084+ if not has_operator (base_type , op_name ):
4085+ return None
4086+
4087+ with self .msg .filter_errors () as w :
4088+ member = analyze_member_access (
4089+ name = op_name ,
4090+ typ = base_type ,
4091+ is_lvalue = False ,
4092+ is_super = False ,
4093+ is_operator = True ,
4094+ original_type = base_type ,
4095+ context = context ,
4096+ chk = self .chk ,
4097+ in_literal_context = self .is_literal_context (),
4098+ )
4099+ return None if w .has_new_errors () else member
4100+
4101+ def lookup_definer (self , typ : Instance , attr_name : str ) -> str | None :
4102+ """Returns the name of the class that contains the actual definition of attr_name.
4103+
4104+ So if class A defines foo and class B subclasses A, running
4105+ `get_class_defined_in(B, "foo")` would return the full name of A.
4106+
4107+ However, if B were to override and redefine foo, that method call would
4108+ return the full name of B instead.
4109+
4110+ If the attr name is not present in the given class or its MRO, returns None.
4111+ """
4112+ for cls in typ .type .mro :
4113+ if cls .names .get (attr_name ):
4114+ return cls .fullname
4115+ return None
4116+
40794117 def check_op_reversible (
40804118 self ,
40814119 op_name : str ,
@@ -4085,48 +4123,10 @@ def check_op_reversible(
40854123 right_expr : Expression ,
40864124 context : Context ,
40874125 ) -> tuple [Type , Type ]:
4088- def lookup_operator (op_name : str , base_type : Type ) -> Type | None :
4089- """Looks up the given operator and returns the corresponding type,
4090- if it exists."""
4091-
4092- # This check is an important performance optimization.
4093- if not has_operator (base_type , op_name , self .named_type ):
4094- return None
4095-
4096- with self .msg .filter_errors () as w :
4097- member = analyze_member_access (
4098- name = op_name ,
4099- typ = base_type ,
4100- is_lvalue = False ,
4101- is_super = False ,
4102- is_operator = True ,
4103- original_type = base_type ,
4104- context = context ,
4105- chk = self .chk ,
4106- in_literal_context = self .is_literal_context (),
4107- )
4108- return None if w .has_new_errors () else member
4109-
4110- def lookup_definer (typ : Instance , attr_name : str ) -> str | None :
4111- """Returns the name of the class that contains the actual definition of attr_name.
4112-
4113- So if class A defines foo and class B subclasses A, running
4114- 'get_class_defined_in(B, "foo")` would return the full name of A.
4115-
4116- However, if B were to override and redefine foo, that method call would
4117- return the full name of B instead.
4118-
4119- If the attr name is not present in the given class or its MRO, returns None.
4120- """
4121- for cls in typ .type .mro :
4122- if cls .names .get (attr_name ):
4123- return cls .fullname
4124- return None
4125-
41264126 left_type = get_proper_type (left_type )
41274127 right_type = get_proper_type (right_type )
41284128
4129- # If either the LHS or the RHS are Any, we can't really concluding anything
4129+ # If either the LHS or the RHS are Any, we can't really conclude anything
41304130 # about the operation since the Any type may or may not define an
41314131 # __op__ or __rop__ method. So, we punt and return Any instead.
41324132
@@ -4142,8 +4142,8 @@ def lookup_definer(typ: Instance, attr_name: str) -> str | None:
41424142
41434143 rev_op_name = operators .reverse_op_methods [op_name ]
41444144
4145- left_op = lookup_operator (op_name , left_type )
4146- right_op = lookup_operator (rev_op_name , right_type )
4145+ left_op = self . lookup_operator (op_name , left_type , context )
4146+ right_op = self . lookup_operator (rev_op_name , right_type , context )
41474147
41484148 # STEP 2a:
41494149 # We figure out in which order Python will call the operator methods. As it
@@ -4168,7 +4168,8 @@ def lookup_definer(typ: Instance, attr_name: str) -> str | None:
41684168 # B: right's __rop__ method is different from left's __op__ method
41694169 not (isinstance (left_type , Instance ) and isinstance (right_type , Instance ))
41704170 or (
4171- lookup_definer (left_type , op_name ) != lookup_definer (right_type , rev_op_name )
4171+ self .lookup_definer (left_type , op_name )
4172+ != self .lookup_definer (right_type , rev_op_name )
41724173 and (
41734174 left_type .type .alt_promote is None
41744175 or left_type .type .alt_promote .type is not right_type .type
@@ -4931,10 +4932,10 @@ def visit_type_application(self, tapp: TypeApplication) -> Type:
49314932 )
49324933 item = get_proper_type (item )
49334934 if isinstance (item , Instance ):
4934- tp = type_object_type (item .type , self . named_type )
4935+ tp = type_object_type (item .type )
49354936 return self .apply_type_arguments_to_callable (tp , item .args , tapp )
49364937 elif isinstance (item , TupleType ) and item .partial_fallback .type .is_named_tuple :
4937- tp = type_object_type (item .partial_fallback .type , self . named_type )
4938+ tp = type_object_type (item .partial_fallback .type )
49384939 return self .apply_type_arguments_to_callable (tp , item .partial_fallback .args , tapp )
49394940 elif isinstance (item , TypedDictType ):
49404941 return self .typeddict_callable_from_context (item )
@@ -5003,7 +5004,7 @@ class LongName(Generic[T]): ...
50035004 if isinstance (item , Instance ):
50045005 # Normally we get a callable type (or overloaded) with .is_type_obj() true
50055006 # representing the class's constructor
5006- tp = type_object_type (item .type , self . named_type )
5007+ tp = type_object_type (item .type )
50075008 if alias .no_args :
50085009 return tp
50095010 return self .apply_type_arguments_to_callable (tp , item .args , ctx )
@@ -5013,7 +5014,7 @@ class LongName(Generic[T]): ...
50135014 # Tuple[str, int]() fails at runtime, only named tuples and subclasses work.
50145015 tuple_fallback (item ).type .fullname != "builtins.tuple"
50155016 ):
5016- return type_object_type (tuple_fallback (item ).type , self . named_type )
5017+ return type_object_type (tuple_fallback (item ).type )
50175018 elif isinstance (item , TypedDictType ):
50185019 return self .typeddict_callable_from_context (item )
50195020 elif isinstance (item , NoneType ):
0 commit comments