1616from mypy import applytype , erasetype , join , message_registry , nodes , operators , types
1717from mypy .argmap import ArgTypeExpander , map_actuals_to_formals , map_formals_to_actuals
1818from mypy .checker_shared import ExpressionCheckerSharedApi
19- from mypy .checkmember import analyze_member_access
19+ from mypy .checkmember import analyze_member_access , has_operator
2020from mypy .checkstrformat import StringFormatterChecker
2121from mypy .erasetype import erase_type , remove_instance_last_known_values , replace_meta_vars
2222from mypy .errors import ErrorWatcher , report_internal_error
@@ -3834,13 +3834,16 @@ def check_method_call_by_name(
38343834 arg_kinds : list [ArgKind ],
38353835 context : Context ,
38363836 original_type : Type | None = None ,
3837+ self_type : Type | None = None ,
38373838 ) -> tuple [Type , Type ]:
38383839 """Type check a call to a named method on an object.
38393840
38403841 Return tuple (result type, inferred method type). The 'original_type'
3841- is used for error messages.
3842+ is used for error messages. The self_type is to bind self in methods
3843+ (see analyze_member_access for more details).
38423844 """
38433845 original_type = original_type or base_type
3846+ self_type = self_type or base_type
38443847 # Unions are special-cased to allow plugins to act on each element of the union.
38453848 base_type = get_proper_type (base_type )
38463849 if isinstance (base_type , UnionType ):
@@ -3856,7 +3859,7 @@ def check_method_call_by_name(
38563859 is_super = False ,
38573860 is_operator = True ,
38583861 original_type = original_type ,
3859- self_type = base_type ,
3862+ self_type = self_type ,
38603863 chk = self .chk ,
38613864 in_literal_context = self .is_literal_context (),
38623865 )
@@ -3933,11 +3936,8 @@ def lookup_operator(op_name: str, base_type: Type) -> Type | None:
39333936 """Looks up the given operator and returns the corresponding type,
39343937 if it exists."""
39353938
3936- # This check is an important performance optimization,
3937- # even though it is mostly a subset of
3938- # analyze_member_access.
3939- # TODO: Find a way to remove this call without performance implications.
3940- if not self .has_member (base_type , op_name ):
3939+ # This check is an important performance optimization.
3940+ if not has_operator (base_type , op_name , self .named_type ):
39413941 return None
39423942
39433943 with self .msg .filter_errors () as w :
@@ -4097,14 +4097,8 @@ def lookup_definer(typ: Instance, attr_name: str) -> str | None:
40974097 errors .append (local_errors .filtered_errors ())
40984098 results .append (result )
40994099 else :
4100- # In theory, we should never enter this case, but it seems
4101- # we sometimes do, when dealing with Type[...]? E.g. see
4102- # check-classes.testTypeTypeComparisonWorks.
4103- #
4104- # This is probably related to the TODO in lookup_operator(...)
4105- # up above.
4106- #
4107- # TODO: Remove this extra case
4100+ # Although we should not need this case anymore, we keep it just in case, as
4101+ # otherwise we will get a crash if we introduce inconsistency in checkmember.py
41084102 return result
41094103
41104104 self .msg .add_errors (errors [0 ])
@@ -4365,13 +4359,19 @@ def visit_index_expr_helper(self, e: IndexExpr) -> Type:
43654359 return self .visit_index_with_type (left_type , e )
43664360
43674361 def visit_index_with_type (
4368- self , left_type : Type , e : IndexExpr , original_type : ProperType | None = None
4362+ self ,
4363+ left_type : Type ,
4364+ e : IndexExpr ,
4365+ original_type : ProperType | None = None ,
4366+ self_type : Type | None = None ,
43694367 ) -> Type :
43704368 """Analyze type of an index expression for a given type of base expression.
43714369
4372- The 'original_type' is used for error messages (currently used for union types).
4370+ The 'original_type' is used for error messages (currently used for union types). The
4371+ 'self_type' is to bind self in methods (see analyze_member_access for more details).
43734372 """
43744373 index = e .index
4374+ self_type = self_type or left_type
43754375 left_type = get_proper_type (left_type )
43764376
43774377 # Visit the index, just to make sure we have a type for it available
@@ -4426,16 +4426,22 @@ def visit_index_with_type(
44264426 ):
44274427 return self .named_type ("types.GenericAlias" )
44284428
4429- if isinstance (left_type , TypeVarType ) and not self . has_member (
4430- left_type . upper_bound , "__getitem__"
4431- ):
4432- return self . visit_index_with_type ( left_type . upper_bound , e , original_type )
4429+ if isinstance (left_type , TypeVarType ):
4430+ return self . visit_index_with_type (
4431+ left_type . values_or_bound (), e , original_type , left_type
4432+ )
44334433 elif isinstance (left_type , Instance ) and left_type .type .fullname == "typing._SpecialForm" :
44344434 # Allow special forms to be indexed and used to create union types
44354435 return self .named_type ("typing._SpecialForm" )
44364436 else :
44374437 result , method_type = self .check_method_call_by_name (
4438- "__getitem__" , left_type , [e .index ], [ARG_POS ], e , original_type = original_type
4438+ "__getitem__" ,
4439+ left_type ,
4440+ [e .index ],
4441+ [ARG_POS ],
4442+ e ,
4443+ original_type = original_type ,
4444+ self_type = self_type ,
44394445 )
44404446 e .method_type = method_type
44414447 return result
@@ -5995,45 +6001,6 @@ def is_valid_keyword_var_arg(self, typ: Type) -> bool:
59956001 or isinstance (typ , ParamSpecType )
59966002 )
59976003
5998- def has_member (self , typ : Type , member : str ) -> bool :
5999- """Does type have member with the given name?"""
6000- # TODO: refactor this to use checkmember.analyze_member_access, otherwise
6001- # these two should be carefully kept in sync.
6002- # This is much faster than analyze_member_access, though, and so using
6003- # it first as a filter is important for performance.
6004- typ = get_proper_type (typ )
6005-
6006- if isinstance (typ , TypeVarType ):
6007- typ = get_proper_type (typ .upper_bound )
6008- if isinstance (typ , TupleType ):
6009- typ = tuple_fallback (typ )
6010- if isinstance (typ , LiteralType ):
6011- typ = typ .fallback
6012- if isinstance (typ , Instance ):
6013- return typ .type .has_readable_member (member )
6014- if isinstance (typ , FunctionLike ) and typ .is_type_obj ():
6015- return typ .fallback .type .has_readable_member (member )
6016- elif isinstance (typ , AnyType ):
6017- return True
6018- elif isinstance (typ , UnionType ):
6019- result = all (self .has_member (x , member ) for x in typ .relevant_items ())
6020- return result
6021- elif isinstance (typ , TypeType ):
6022- # Type[Union[X, ...]] is always normalized to Union[Type[X], ...],
6023- # so we don't need to care about unions here.
6024- item = typ .item
6025- if isinstance (item , TypeVarType ):
6026- item = get_proper_type (item .upper_bound )
6027- if isinstance (item , TupleType ):
6028- item = tuple_fallback (item )
6029- if isinstance (item , Instance ) and item .type .metaclass_type is not None :
6030- return self .has_member (item .type .metaclass_type , member )
6031- if isinstance (item , AnyType ):
6032- return True
6033- return False
6034- else :
6035- return False
6036-
60376004 def not_ready_callback (self , name : str , context : Context ) -> None :
60386005 """Called when we can't infer the type of a variable because it's not ready yet.
60396006
0 commit comments