@@ -2409,7 +2409,16 @@ def make_local_errors() -> MessageBuilder:
2409
2409
def lookup_operator (op_name : str , base_type : Type ) -> Optional [Type ]:
2410
2410
"""Looks up the given operator and returns the corresponding type,
2411
2411
if it exists."""
2412
+
2413
+ # This check is an important performance optimization,
2414
+ # even though it is mostly a subset of
2415
+ # analyze_member_access.
2416
+ # TODO: Find a way to remove this call without performance implications.
2417
+ if not self .has_member (base_type , op_name ):
2418
+ return None
2419
+
2412
2420
local_errors = make_local_errors ()
2421
+
2413
2422
member = analyze_member_access (
2414
2423
name = op_name ,
2415
2424
typ = base_type ,
@@ -3790,6 +3799,45 @@ def is_valid_keyword_var_arg(self, typ: Type) -> bool:
3790
3799
[self .named_type ('builtins.unicode' ),
3791
3800
AnyType (TypeOfAny .special_form )])))
3792
3801
3802
+ def has_member (self , typ : Type , member : str ) -> bool :
3803
+ """Does type have member with the given name?"""
3804
+ # TODO: refactor this to use checkmember.analyze_member_access, otherwise
3805
+ # these two should be carefully kept in sync.
3806
+ # This is much faster than analyze_member_access, though, and so using
3807
+ # it first as a filter is important for performance.
3808
+ typ = get_proper_type (typ )
3809
+
3810
+ if isinstance (typ , TypeVarType ):
3811
+ typ = get_proper_type (typ .upper_bound )
3812
+ if isinstance (typ , TupleType ):
3813
+ typ = tuple_fallback (typ )
3814
+ if isinstance (typ , LiteralType ):
3815
+ typ = typ .fallback
3816
+ if isinstance (typ , Instance ):
3817
+ return typ .type .has_readable_member (member )
3818
+ if isinstance (typ , CallableType ) and typ .is_type_obj ():
3819
+ return typ .fallback .type .has_readable_member (member )
3820
+ elif isinstance (typ , AnyType ):
3821
+ return True
3822
+ elif isinstance (typ , UnionType ):
3823
+ result = all (self .has_member (x , member ) for x in typ .relevant_items ())
3824
+ return result
3825
+ elif isinstance (typ , TypeType ):
3826
+ # Type[Union[X, ...]] is always normalized to Union[Type[X], ...],
3827
+ # so we don't need to care about unions here.
3828
+ item = typ .item
3829
+ if isinstance (item , TypeVarType ):
3830
+ item = get_proper_type (item .upper_bound )
3831
+ if isinstance (item , TupleType ):
3832
+ item = tuple_fallback (item )
3833
+ if isinstance (item , Instance ) and item .type .metaclass_type is not None :
3834
+ return self .has_member (item .type .metaclass_type , member )
3835
+ if isinstance (item , AnyType ):
3836
+ return True
3837
+ return False
3838
+ else :
3839
+ return False
3840
+
3793
3841
def not_ready_callback (self , name : str , context : Context ) -> None :
3794
3842
"""Called when we can't infer the type of a variable because it's not ready yet.
3795
3843
0 commit comments