diff --git a/pyrefly/lib/alt/class/class_field.rs b/pyrefly/lib/alt/class/class_field.rs index 6c28350e13..88fb40971f 100644 --- a/pyrefly/lib/alt/class/class_field.rs +++ b/pyrefly/lib/alt/class/class_field.rs @@ -4224,6 +4224,19 @@ impl<'ctx, 'answer, Ans: LookupAnswer> AnswersSolver<'ctx, 'answer, Ans> { { return; } + if (class_field.is_abstract() || self.get_metadata_for_class(cls).is_protocol()) + && class_field + .ty() + .toplevel_func_metadata() + .is_some_and(|meta| { + matches!( + meta.flags.body_kind, + BodyKind::Ellipsis | BodyKind::Trivial | BodyKind::RaiseNotImplementedError + ) + }) + { + return; + } // If any base derives from `Any`, we can't reliably tell whether the method // overrides a concrete parent method, so suppress the check. Gather this // across all bases first so the decision is independent of base order. diff --git a/pyrefly/lib/test/class_overrides.rs b/pyrefly/lib/test/class_overrides.rs index 136509d48a..7a6b98d2a9 100644 --- a/pyrefly/lib/test/class_overrides.rs +++ b/pyrefly/lib/test/class_overrides.rs @@ -2449,6 +2449,42 @@ class MultipleInheritance(AbstractBase, ConcreteBase): "#, ); +testcase!( + test_missing_super_call_abstract_or_protocol_child, + TestEnv::new().enable_missing_super_call_error(), + r#" +from abc import ABC, abstractmethod +from typing import Protocol + +class Base: + def __init__(self, x: int) -> None: + self.x = x + +class AbstractChildEllipsis(Base, ABC): + @abstractmethod + def __init__(self, x: int, y: int) -> None: + ... + +class AbstractChildPass(Base, ABC): + @abstractmethod + def __init__(self, x: int, y: int) -> None: + pass + +class AbstractChildRaise(Base, ABC): + @abstractmethod + def __init__(self, x: int, y: int) -> None: + raise NotImplementedError + +class ParentProto(Protocol): + def __init__(self, x: int) -> None: + pass + +class SubProto(ParentProto, Protocol): + def __init__(self, x: int, y: int) -> None: + ... + "#, +); + testcase!( test_override_descriptor_method, r#"