From 51140776a16e7bbe31c8f8e8bcb4a1e211e6dcc8 Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Mon, 24 Feb 2020 18:03:21 -0800 Subject: [PATCH] mypy: remove has_member In particular: - The test case mentioned in the code passes without it - The test case changed seems to have more desirable behaviour now, consider: ``` from typing import Any """ class C: def __radd__(self, other) -> float: return 1.234 """ C: Any class D(C): pass reveal_type("str" + D()) ``` --- mypy/checkexpr.py | 46 ------------------------------- mypy/typeops.py | 2 +- test-data/unit/check-classes.test | 2 +- 3 files changed, 2 insertions(+), 48 deletions(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 310aac82b13c7..0141271eccbac 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -2410,15 +2410,6 @@ def lookup_operator(op_name: str, base_type: Type) -> Optional[Type]: """Looks up the given operator and returns the corresponding type, if it exists.""" local_errors = make_local_errors() - - # TODO: Remove this call and rely just on analyze_member_access - # Currently, it seems we still need this to correctly deal with - # things like metaclasses? - # - # E.g. see the pythoneval.testMetaclassOpAccessAny test case. - if not self.has_member(base_type, op_name): - return None - member = analyze_member_access( name=op_name, typ=base_type, @@ -3799,43 +3790,6 @@ def is_valid_keyword_var_arg(self, typ: Type) -> bool: [self.named_type('builtins.unicode'), AnyType(TypeOfAny.special_form)]))) - def has_member(self, typ: Type, member: str) -> bool: - """Does type have member with the given name?""" - # TODO: refactor this to use checkmember.analyze_member_access, otherwise - # these two should be carefully kept in sync. - typ = get_proper_type(typ) - - if isinstance(typ, TypeVarType): - typ = get_proper_type(typ.upper_bound) - if isinstance(typ, TupleType): - typ = tuple_fallback(typ) - if isinstance(typ, LiteralType): - typ = typ.fallback - if isinstance(typ, Instance): - return typ.type.has_readable_member(member) - if isinstance(typ, CallableType) and typ.is_type_obj(): - return typ.fallback.type.has_readable_member(member) - elif isinstance(typ, AnyType): - return True - elif isinstance(typ, UnionType): - result = all(self.has_member(x, member) for x in typ.relevant_items()) - return result - elif isinstance(typ, TypeType): - # Type[Union[X, ...]] is always normalized to Union[Type[X], ...], - # so we don't need to care about unions here. - item = typ.item - if isinstance(item, TypeVarType): - item = get_proper_type(item.upper_bound) - if isinstance(item, TupleType): - item = tuple_fallback(item) - if isinstance(item, Instance) and item.type.metaclass_type is not None: - return self.has_member(item.type.metaclass_type, member) - if isinstance(item, AnyType): - return True - return False - else: - return False - def not_ready_callback(self, name: str, context: Context) -> None: """Called when we can't infer the type of a variable because it's not ready yet. diff --git a/mypy/typeops.py b/mypy/typeops.py index 828791333f364..d143588aada3f 100644 --- a/mypy/typeops.py +++ b/mypy/typeops.py @@ -719,5 +719,5 @@ def custom_special_method(typ: Type, name: str, check_all: bool = False) -> bool if isinstance(typ, AnyType): # Avoid false positives in uncertain cases. return True - # TODO: support other types (see ExpressionChecker.has_member())? + # TODO: support other types (see analyze_member_access)? return False diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index ed547510b46c3..e924402c8614e 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -6650,7 +6650,7 @@ reveal_type(0.5 + C) # N: Revealed type is 'Any' reveal_type(0.5 + D()) # N: Revealed type is 'Any' reveal_type(D() + 0.5) # N: Revealed type is 'Any' -reveal_type("str" + D()) # N: Revealed type is 'builtins.str' +reveal_type("str" + D()) # N: Revealed type is 'Any' reveal_type(D() + "str") # N: Revealed type is 'Any'