From 2edcdb335c8d92db75a65204c58843c9111fca5a Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Fri, 14 Feb 2025 17:16:22 -0800 Subject: [PATCH] Fixed bug that results in a spurious "overlapping overload" error if the second both overloads have an `*args` but the first has one or more additional positional parameters. This addresses #9916. --- .../pyright-internal/src/analyzer/typeEvaluator.ts | 10 ++++++++++ .../src/tests/samples/overloadOverlap1.py | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/packages/pyright-internal/src/analyzer/typeEvaluator.ts b/packages/pyright-internal/src/analyzer/typeEvaluator.ts index 921fd743c782..933e343f9f4a 100644 --- a/packages/pyright-internal/src/analyzer/typeEvaluator.ts +++ b/packages/pyright-internal/src/analyzer/typeEvaluator.ts @@ -26182,6 +26182,7 @@ export function createTypeEvaluator( const destPositionalCount = destParamDetails.firstKeywordOnlyIndex ?? destParamDetails.params.length; const srcPositionalCount = srcParamDetails.firstKeywordOnlyIndex ?? srcParamDetails.params.length; const positionalsToMatch = Math.min(destPositionalCount, srcPositionalCount); + const skippedPosParamIndices: number[] = []; // Match positional parameters. for (let paramIndex = 0; paramIndex < positionalsToMatch; paramIndex++) { @@ -26197,6 +26198,9 @@ export function createTypeEvaluator( // Skip over the *args parameter since it's handled separately below. if (paramIndex === destParamDetails.argsIndex) { + if (!isUnpackedTypeVarTuple(destParamDetails.params[destParamDetails.argsIndex].type)) { + skippedPosParamIndices.push(paramIndex); + } continue; } @@ -26329,7 +26333,13 @@ export function createTypeEvaluator( } if (destPositionalCount < srcPositionalCount && !targetIncludesParamSpec) { + // Add any remaining positional parameter indices to the list that + // need to be validated. for (let i = destPositionalCount; i < srcPositionalCount; i++) { + skippedPosParamIndices.push(i); + } + + for (const i of skippedPosParamIndices) { // If the dest has an *args parameter, make sure it can accept the remaining // positional arguments in the source. if (destParamDetails.argsIndex !== undefined) { diff --git a/packages/pyright-internal/src/tests/samples/overloadOverlap1.py b/packages/pyright-internal/src/tests/samples/overloadOverlap1.py index 3025bdcc8491..91e6110f6c0a 100644 --- a/packages/pyright-internal/src/tests/samples/overloadOverlap1.py +++ b/packages/pyright-internal/src/tests/samples/overloadOverlap1.py @@ -499,3 +499,14 @@ def func32(n: list[NestedList[Any]]) -> list[Any]: ... def func32(n: Any) -> Any: ... + + +@overload +def func33(a: int, /, *args: str) -> None: ... + + +@overload +def func33(*args: str) -> None: ... + + +def func33(*args: int | str) -> None: ...