From b5a4d7d2ddb8e442676e583ab76fe6b318695c00 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sun, 13 Aug 2023 13:53:08 -0700 Subject: [PATCH 1/2] Skip overlapping overload check at large overload counts Fixes #10004 --- mypy/checker.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mypy/checker.py b/mypy/checker.py index b786155079e5..bff2f70c7654 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -668,6 +668,11 @@ def check_overlapping_overloads(self, defn: OverloadedFuncDef) -> None: # useful for stubs! return + if len(defn.items) >= 100: + # Skip this check for large numbers of overloads, since the following is quadratic. + # This constant matches the threshold at which pyright similarly skips this check. + return + # Compute some info about the implementation (if it exists) for use below impl_type: CallableType | None = None if defn.impl: From f47a4554f28c87c09f476976c25cdcc185671e4d Mon Sep 17 00:00:00 2001 From: Shantanu Jain Date: Sun, 14 Dec 2025 16:35:14 -0800 Subject: [PATCH 2/2] restrict --- mypy/checker.py | 12 ++++++++---- mypy/message_registry.py | 3 +++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index e8f0e15cc662..dfc3e8238a87 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -892,10 +892,10 @@ def check_overlapping_overloads(self, defn: OverloadedFuncDef) -> None: # useful for stubs! return - if len(defn.items) >= 100: - # Skip this check for large numbers of overloads, since the following is quadratic. - # This constant matches the threshold at which pyright similarly skips this check. - return + max_overload_count = 50 + if len(defn.items) >= max_overload_count: + # Since the following is quadratic, we limit the size of the inner loop + self.fail(message_registry.TOO_MANY_OVERLOADS, defn) # Compute some info about the implementation (if it exists) for use below impl_type: CallableType | None = None @@ -919,6 +919,10 @@ def check_overlapping_overloads(self, defn: OverloadedFuncDef) -> None: continue for j, item2 in enumerate(defn.items[i + 1 :]): + if j >= max_overload_count: + # Avoid quadratic blowup for large numbers of overloads. + break + assert isinstance(item2, Decorator) sig2 = self.extract_callable_type(item2.var.type, item2) if sig2 is None: diff --git a/mypy/message_registry.py b/mypy/message_registry.py index b0f9ed1b0dfe..958e7e5f8900 100644 --- a/mypy/message_registry.py +++ b/mypy/message_registry.py @@ -106,6 +106,9 @@ def with_additional_msg(self, info: str) -> ErrorMessage: "Overloaded method has both abstract and non-abstract variants" ) MULTIPLE_OVERLOADS_REQUIRED: Final = ErrorMessage("Single overload definition, multiple required") +TOO_MANY_OVERLOADS: Final = ErrorMessage( + "Not all overload combinations were checked for overlap because there were too many" +) READ_ONLY_PROPERTY_OVERRIDES_READ_WRITE: Final = ErrorMessage( "Read-only property cannot override read-write property" )