diff --git a/mypy/stubtest.py b/mypy/stubtest.py index 43da0518b3f9..f560049f2ec8 100644 --- a/mypy/stubtest.py +++ b/mypy/stubtest.py @@ -510,7 +510,9 @@ def _verify_disjoint_base( if stub.is_final: return is_disjoint_runtime = _is_disjoint_base(runtime) - if is_disjoint_runtime and not stub.is_disjoint_base: + # Don't complain about missing @disjoint_base if there are __slots__, because + # in that case we can infer that it's a disjoint base. + if is_disjoint_runtime and not stub.is_disjoint_base and not runtime.__dict__.get("__slots__"): yield Error( object_path, "is a disjoint base at runtime, but isn't marked with @disjoint_base in the stub", diff --git a/mypy/test/teststubtest.py b/mypy/test/teststubtest.py index 69e2abe62f85..e6bc2c818164 100644 --- a/mypy/test/teststubtest.py +++ b/mypy/test/teststubtest.py @@ -1430,6 +1430,31 @@ class BytesEnum(bytes, enum.Enum): """, error=None, ) + yield Case( + stub=""" + class HasSlotsAndNothingElse: + __slots__ = ("x",) + x: int + + class HasInheritedSlots(HasSlotsAndNothingElse): + pass + + class HasEmptySlots: + __slots__ = () + """, + runtime=""" + class HasSlotsAndNothingElse: + __slots__ = ("x",) + x: int + + class HasInheritedSlots(HasSlotsAndNothingElse): + pass + + class HasEmptySlots: + __slots__ = () + """, + error=None, + ) @collect_cases def test_decorator(self) -> Iterator[Case]: