From 855355aebae84f85e94dbb6308fc8a04831ae4b7 Mon Sep 17 00:00:00 2001 From: Aayush Yash Date: Mon, 2 Nov 2026 00:54:48 +0530 Subject: [PATCH 1/2] test: cover missing-super-call for abstract and protocol child methods --- pyrefly/lib/test/class_overrides.rs | 51 +++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/pyrefly/lib/test/class_overrides.rs b/pyrefly/lib/test/class_overrides.rs index 136509d48a..1a1c05362c 100644 --- a/pyrefly/lib/test/class_overrides.rs +++ b/pyrefly/lib/test/class_overrides.rs @@ -2449,6 +2449,57 @@ 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): + x: int + def __init__(self, x: int) -> None: + self.x = x + +class SubProto(ParentProto, Protocol): + def __init__(self, x: int, y: int) -> None: + ... + +registry: list[type] = [] + +class Registered(Protocol): + def __init_subclass__(cls) -> None: + super().__init_subclass__() + registry.append(cls) + +class SubProtoInitSubclass(Registered, Protocol): + def __init_subclass__(cls) -> None: # E: Method `SubProtoInitSubclass.__init_subclass__` does not call the method of the same name in a parent class + ... + +class Impl(SubProtoInitSubclass): + pass + "#, +); + testcase!( test_override_descriptor_method, r#" From 5840c383e263bec2fcf1959537239b132852ac73 Mon Sep 17 00:00:00 2001 From: Aayush Yash Date: Mon, 2 Nov 2026 00:54:58 +0530 Subject: [PATCH 2/2] fix: skip missing-super-call for abstract or protocol method overrides --- pyrefly/lib/alt/class/class_field.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pyrefly/lib/alt/class/class_field.rs b/pyrefly/lib/alt/class/class_field.rs index bcaf7d18c2..a118ab1528 100644 --- a/pyrefly/lib/alt/class/class_field.rs +++ b/pyrefly/lib/alt/class/class_field.rs @@ -4235,6 +4235,20 @@ impl<'ctx, 'answer, Ans: LookupAnswer> AnswersSolver<'ctx, 'answer, Ans> { { return; } + if field_name != &dunder::INIT_SUBCLASS + && (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.