diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index faba362405fc..f54703997b53 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -2071,6 +2071,8 @@ def has_member(self, typ: Type, member: str) -> bool: # TODO TupleType => also consider tuple attributes 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): diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 3c8bb8e62a03..7f5b60f59b6c 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -2831,3 +2831,16 @@ class M(Tuple[int]): pass class C(metaclass=M): pass # E: Invalid metaclass 'M' [builtins fixtures/tuple.pyi] + +[case testMetaclassOperatorBeforeReversed] +class X: + def __radd__(self, x: int) -> int: ... + +class Meta(type): + def __add__(cls, x: X) -> str: ... + +class Concrete(metaclass=Meta): + pass + +reveal_type(Concrete + X()) # E: Revealed type is 'builtins.str' +Concrete + "hello" # E: Unsupported operand types for + ("Meta" and "str")