From 0d75f621c85f1f00a68033b12524dc190b294c15 Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Wed, 31 Jan 2024 20:30:41 -0800 Subject: [PATCH] Fixed a bug that results in a false negative when a `None` type is included in an unpacked argument within a function call. This addresses #7175. --- .../src/analyzer/typeEvaluator.ts | 22 ++++++------ .../src/tests/samples/call6.py | 35 +++++++++++++------ .../src/tests/typeEvaluator1.test.ts | 2 +- 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/packages/pyright-internal/src/analyzer/typeEvaluator.ts b/packages/pyright-internal/src/analyzer/typeEvaluator.ts index 9c1b921eaf23..8a3ce52215a9 100644 --- a/packages/pyright-internal/src/analyzer/typeEvaluator.ts +++ b/packages/pyright-internal/src/analyzer/typeEvaluator.ts @@ -2695,8 +2695,8 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions let type = transformPossibleRecursiveTypeAlias(typeResult.type); type = makeTopLevelTypeVarsConcrete(type); - if (isOptionalType(type)) { - if (!typeResult.isIncomplete && emitNotIterableError) { + if (isOptionalType(type) && emitNotIterableError) { + if (!typeResult.isIncomplete) { addDiagnostic(DiagnosticRule.reportOptionalIterable, LocMessage.noneNotIterable(), errorNode); } type = removeNoneFromUnion(type); @@ -10205,13 +10205,12 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions } else if (isParamSpec(argType) && argType.paramSpecAccess === 'args') { listElementType = undefined; } else { - listElementType = - getTypeOfIterator( - { type: argType, isIncomplete: argTypeResult.isIncomplete }, - /* isAsync */ false, - errorNode, - /* emitNotIterableError */ false - )?.type ?? UnknownType.create(); + listElementType = getTypeOfIterator( + { type: argType, isIncomplete: argTypeResult.isIncomplete }, + /* isAsync */ false, + errorNode, + /* emitNotIterableError */ false + )?.type; if (paramDetails.params[paramIndex].param.category !== ParameterCategory.ArgsList) { matchedUnpackedListOfUnknownLength = true; @@ -10223,8 +10222,9 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions argumentCategory: ArgumentCategory.Simple, typeResult: { type: listElementType, isIncomplete: argTypeResult.isIncomplete }, } - : undefined; - if (funcArg && argTypeResult.isIncomplete) { + : { ...argList[argIndex] }; + + if (argTypeResult.isIncomplete) { isTypeIncomplete = true; } diff --git a/packages/pyright-internal/src/tests/samples/call6.py b/packages/pyright-internal/src/tests/samples/call6.py index f907cf41af13..958e9adede0b 100644 --- a/packages/pyright-internal/src/tests/samples/call6.py +++ b/packages/pyright-internal/src/tests/samples/call6.py @@ -3,35 +3,48 @@ # tuples and *args parameters. -def foo1(a: int, b: int): +def func1(a: int, b: int): pass -def foo2(*args: int): +def func2(*args: int): pass fixed_tuple_0 = () -foo1(*fixed_tuple_0, 2, 3) -foo2(*fixed_tuple_0, 2) +func1(*fixed_tuple_0, 2, 3) +func2(*fixed_tuple_0, 2) fixed_tuple_1 = (1,) # This should generate an error because there # are too many parameters. -foo1(*fixed_tuple_1, 2, 3) +func1(*fixed_tuple_1, 2, 3) -foo2(*fixed_tuple_1, 2, *fixed_tuple_0) +func2(*fixed_tuple_1, 2, *fixed_tuple_0) fixed_tuple_3 = (1, 3, 5) # This should generate an error because there # are too many parameters. -foo1(*fixed_tuple_3, 2) +func1(*fixed_tuple_3, 2) -foo2(*fixed_tuple_3, 2, *fixed_tuple_0) +func2(*fixed_tuple_3, 2, *fixed_tuple_0) -homogen_tuple: tuple[int, ...] = (1, 5, 3) +unbounded_tuple: tuple[int, ...] = (1, 5, 3) -foo2(*homogen_tuple) -foo2(*homogen_tuple, 2) +func2(*unbounded_tuple) +func2(*unbounded_tuple, 2) + + +def func3(*args: str): ... + + +def func4(v1: list[str] | None, v2: None, v3: list[str]): + # This should generate an error. + func3(*v1) + + # This should generate an error. + func3(*v2) + + func3(*v3) diff --git a/packages/pyright-internal/src/tests/typeEvaluator1.test.ts b/packages/pyright-internal/src/tests/typeEvaluator1.test.ts index 2eb0209eb898..6d06ea4b5f8f 100644 --- a/packages/pyright-internal/src/tests/typeEvaluator1.test.ts +++ b/packages/pyright-internal/src/tests/typeEvaluator1.test.ts @@ -789,7 +789,7 @@ test('Call5', () => { test('Call6', () => { const analysisResults = TestUtils.typeAnalyzeSampleFiles(['call6.py']); - TestUtils.validateResults(analysisResults, 2); + TestUtils.validateResults(analysisResults, 4); }); test('Call7', () => {