From b5a4d7d2ddb8e442676e583ab76fe6b318695c00 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sun, 13 Aug 2023 13:53:08 -0700 Subject: [PATCH 1/4] 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/4] 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" ) From 2610a3dcb1d6a307e93e6bf14e0182f7299974a4 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Fri, 6 Nov 2026 22:47:20 -0800 Subject: [PATCH 3/4] Add an error code for the overload overlap check limit --- docs/source/error_code_list.rst | 11 +++++++++++ mypy/errorcodes.py | 4 ++++ mypy/message_registry.py | 3 ++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/source/error_code_list.rst b/docs/source/error_code_list.rst index 034c795e7120..c80504169a16 100644 --- a/docs/source/error_code_list.rst +++ b/docs/source/error_code_list.rst @@ -1386,6 +1386,17 @@ to the line with the string literal: dict_of_typx = {'str_or_none': TypeForm(str | None)} list_of_typx: list[TypeForm] = [dict_of_typx['str_or_none']] # type: ignore[maybe-unrecognized-str-typeform] +.. _code-performance-limit: + +Checks skipped for performance reasons [performance-limit] +--------------------------------------------------------- + +Mypy reports this error when it limits or skip checks to avoid excessive type +checking time. As a result, some errors may go undetected. + +For example, when a function has 50 or more ``@overload`` variants, mypy limits +the number of variants it compares for overlap. + .. _code-misc: Miscellaneous checks [misc] diff --git a/mypy/errorcodes.py b/mypy/errorcodes.py index 06e716372f24..c64ce8d131a8 100644 --- a/mypy/errorcodes.py +++ b/mypy/errorcodes.py @@ -284,6 +284,10 @@ def __hash__(self) -> int: # Syntax errors are often blocking. SYNTAX: Final = ErrorCode("syntax", "Report syntax errors", "General") +PERFORMANCE_LIMIT: Final = ErrorCode( + "performance-limit", "Warn about checks skipped for performance reasons", "General" +) + # This is a catch-all for remaining uncategorized errors. MISC: Final = ErrorCode("misc", "Miscellaneous other checks", "General") diff --git a/mypy/message_registry.py b/mypy/message_registry.py index de494fb7c110..7c11e5eeff18 100644 --- a/mypy/message_registry.py +++ b/mypy/message_registry.py @@ -108,7 +108,8 @@ def with_additional_msg(self, info: str) -> ErrorMessage: ) 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" + "Not all overload combinations were checked for overlap because there were too many", + codes.PERFORMANCE_LIMIT, ) READ_ONLY_PROPERTY_OVERRIDES_READ_WRITE: Final = ErrorMessage( "Read-only property cannot override read-write property" From 40541fef44a1ecfd05fb0c82e2dc533413674cc3 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Fri, 6 Nov 2026 23:11:45 -0800 Subject: [PATCH 4/4] fix --- docs/source/error_code_list.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/error_code_list.rst b/docs/source/error_code_list.rst index c80504169a16..b39ef8242670 100644 --- a/docs/source/error_code_list.rst +++ b/docs/source/error_code_list.rst @@ -1389,7 +1389,7 @@ to the line with the string literal: .. _code-performance-limit: Checks skipped for performance reasons [performance-limit] ---------------------------------------------------------- +---------------------------------------------------------- Mypy reports this error when it limits or skip checks to avoid excessive type checking time. As a result, some errors may go undetected.