From 0d92942a42bf6ec1ed29bfe9a66485737cc208d0 Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Wed, 11 Sep 2024 14:30:16 -0700 Subject: [PATCH] Fixed bug that results in incorrect type narrowing for sequence patterns in the negative (fall-through) case when the subject is a tuple with an unbounded entry. This addresses #8967. (#8968) --- .../src/analyzer/patternMatching.ts | 5 ++++- .../src/tests/samples/matchSequence1.py | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/pyright-internal/src/analyzer/patternMatching.ts b/packages/pyright-internal/src/analyzer/patternMatching.ts index c86f7cd7140e..55ae16160e1c 100644 --- a/packages/pyright-internal/src/analyzer/patternMatching.ts +++ b/packages/pyright-internal/src/analyzer/patternMatching.ts @@ -109,6 +109,7 @@ interface SequencePatternInfo { entryTypes: Type[]; isIndeterminateLength?: boolean; isTuple?: boolean; + isUnboundedTuple?: boolean; } interface MappingPatternInfo { @@ -225,7 +226,7 @@ function narrowTypeBasedOnSequencePattern( // contains indeterminate-length entries or the tuple is of indeterminate // length. if (!isPositiveTest) { - if (entry.isIndeterminateLength) { + if (entry.isIndeterminateLength || entry.isUnboundedTuple) { canNarrowTuple = false; } @@ -1436,6 +1437,7 @@ function getSequencePatternInfo( entryTypes: isDefiniteNoMatch ? [] : typeArgs.map((t) => t.type), isIndeterminateLength: false, isTuple: true, + isUnboundedTuple: tupleIndeterminateIndex >= 0, isDefiniteNoMatch, isPotentialNoMatch, }); @@ -1488,6 +1490,7 @@ function getSequencePatternInfo( entryTypes: isDefiniteNoMatch ? [] : typeArgs.map((t) => t.type), isIndeterminateLength: false, isTuple: true, + isUnboundedTuple: tupleIndeterminateIndex >= 0, isDefiniteNoMatch, }); return; diff --git a/packages/pyright-internal/src/tests/samples/matchSequence1.py b/packages/pyright-internal/src/tests/samples/matchSequence1.py index 13ebdcc2b3fd..6a2d3b57255b 100644 --- a/packages/pyright-internal/src/tests/samples/matchSequence1.py +++ b/packages/pyright-internal/src/tests/samples/matchSequence1.py @@ -608,6 +608,24 @@ def test_unbounded_tuple_5(subj: tuple[int, Unpack[tuple[str, ...]]]): reveal_type(x, expected_text="Never") +def test_unbounded_tuple_6(subj: tuple[str, ...]): + match subj: + case ("a", b, _, _): + reveal_type(b, expected_text="str") + + case ("a", b, _, _, _): + reveal_type(b, expected_text="str") + + case (_, b, _, _): + reveal_type(b, expected_text="str") + + case (_, b, _, _, _): + reveal_type(b, expected_text="str") + + case r: + reveal_type(r, expected_text="tuple[str, ...]") + + def test_variadic_tuple(subj: tuple[int, Unpack[Ts]]) -> tuple[Unpack[Ts]]: match subj: case _, *rest: