From 4c1eb615afd0ae92538203f116426ef26763687f Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Sun, 28 Apr 2024 18:44:26 -0700 Subject: [PATCH] Fixed a bug that results in a false positive error when `Callable()` is used as a class pattern and the subject type is `Any` or `Unknown`. This addresses #7794. (#7796) --- .../src/analyzer/patternMatching.ts | 16 ++++++++++++++++ .../src/tests/samples/matchClass6.py | 16 +++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/packages/pyright-internal/src/analyzer/patternMatching.ts b/packages/pyright-internal/src/analyzer/patternMatching.ts index b96df17b7..67a91d71b 100644 --- a/packages/pyright-internal/src/analyzer/patternMatching.ts +++ b/packages/pyright-internal/src/analyzer/patternMatching.ts @@ -43,6 +43,8 @@ import { AnyType, ClassType, combineTypes, + FunctionType, + FunctionTypeFlags, isAnyOrUnknown, isClass, isClassInstance, @@ -816,6 +818,20 @@ function narrowTypeBasedOnClassPattern( return evaluator.mapSubtypesExpandTypeVars(type, /* options */ undefined, (subjectSubtypeExpanded) => { if (isAnyOrUnknown(subjectSubtypeExpanded)) { + if (isInstantiableClass(expandedSubtype) && ClassType.isBuiltIn(expandedSubtype, 'Callable')) { + // Convert to an unknown callable type. + const unknownCallable = FunctionType.createSynthesizedInstance( + '', + FunctionTypeFlags.SkipArgsKwargsCompatibilityCheck + ); + FunctionType.addDefaultParameters( + unknownCallable, + /* useUnknown */ isUnknown(subjectSubtypeExpanded) + ); + unknownCallable.details.declaredReturnType = subjectSubtypeExpanded; + return unknownCallable; + } + return convertToInstance(unexpandedSubtype); } diff --git a/packages/pyright-internal/src/tests/samples/matchClass6.py b/packages/pyright-internal/src/tests/samples/matchClass6.py index 582335de5..bd351df0e 100644 --- a/packages/pyright-internal/src/tests/samples/matchClass6.py +++ b/packages/pyright-internal/src/tests/samples/matchClass6.py @@ -1,7 +1,7 @@ # This sample tests the case where `Callable()` is used as a class pattern. from collections.abc import Callable -from typing import TypeVar +from typing import Any, TypeVar T = TypeVar("T") @@ -24,3 +24,17 @@ def func3(obj: type[int] | Callable[..., str]) -> int | str | None: case Callable(): reveal_type(obj, expected_text="type[int] | ((...) -> str)") return obj() + + +def func4(obj): + match obj: + case Callable(): + reveal_type(obj, expected_text="(...) -> Unknown") + return obj() + + +def func5(obj: Any): + match obj: + case Callable(): + reveal_type(obj, expected_text="(...) -> Any") + return obj()