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