mirror of
https://github.com/microsoft/pyright.git
synced 2024-09-11 07:55:56 +03:00
Fixed a bug that results in a false negative when a generic function returns a Callable type that is specialized to include a live (in-scope) type variable. This addresses #7542. (#7634)
This commit is contained in:
parent
3b70417dd5
commit
e65ac3854d
@ -11541,9 +11541,11 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
|
||||
}
|
||||
}
|
||||
|
||||
const liveTypeVarScopes = ParseTreeUtils.getTypeVarScopesForNode(errorNode);
|
||||
specializedReturnType = adjustCallableReturnType(
|
||||
type,
|
||||
specializedReturnType,
|
||||
liveTypeVarScopes,
|
||||
signatureTracker.getTrackedSignatures()
|
||||
);
|
||||
|
||||
@ -11612,10 +11614,14 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
|
||||
function adjustCallableReturnType(
|
||||
callableType: FunctionType,
|
||||
returnType: Type,
|
||||
liveTypeVarScopes: TypeVarScopeId[],
|
||||
trackedSignatures?: SignatureWithOffsets[]
|
||||
): Type {
|
||||
if (isFunction(returnType) && !returnType.details.name && callableType.details.typeVarScopeId) {
|
||||
const typeVarsInReturnType = getTypeVarArgumentsRecursive(returnType);
|
||||
// What type variables are referenced in the callable return type? Do not include any live type variables.
|
||||
const typeVarsInReturnType = getTypeVarArgumentsRecursive(returnType).filter(
|
||||
(t) => !liveTypeVarScopes.some((scopeId) => t.scopeId === scopeId)
|
||||
);
|
||||
|
||||
// If there are no unsolved type variables, we're done. If there are
|
||||
// unsolved type variables, treat them as though they are rescoped
|
||||
@ -21727,7 +21733,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
|
||||
) {
|
||||
const specializedReturnType = FunctionType.getSpecializedReturnType(type, /* includeInferred */ false);
|
||||
if (specializedReturnType && !isUnknown(specializedReturnType)) {
|
||||
return adjustCallableReturnType(type, specializedReturnType, /* trackedSignatures */ undefined);
|
||||
return adjustCallableReturnType(type, specializedReturnType, /* liveTypeVarScopes */ []);
|
||||
}
|
||||
|
||||
if (inferTypeIfNeeded) {
|
||||
|
@ -17,9 +17,9 @@ def extend_if(xs: list[_T], ys: list[tuple[_T, bool]]) -> list[_T]:
|
||||
extend_if(["foo"], [("bar", True), ("baz", True)])
|
||||
|
||||
|
||||
def Return(value: _T) -> Callable[[_T], None]:
|
||||
def func1(value: _T) -> Callable[[_T], None]:
|
||||
...
|
||||
|
||||
|
||||
def func1() -> Callable[[bool], None]:
|
||||
return Return(True)
|
||||
def func2() -> Callable[[bool], None]:
|
||||
return func1(True)
|
||||
|
21
packages/pyright-internal/src/tests/samples/solver34.py
Normal file
21
packages/pyright-internal/src/tests/samples/solver34.py
Normal file
@ -0,0 +1,21 @@
|
||||
# This sample tests the case where a generic function returns a Callable type
|
||||
# that is specialized with unsolved type variables.
|
||||
|
||||
from collections.abc import Container
|
||||
from typing import TypeVar, Callable
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
VT = TypeVar("VT")
|
||||
|
||||
|
||||
def func1(container: Container[T]) -> Callable[[T], bool]: ...
|
||||
|
||||
|
||||
def func2(a: T, b: Container[VT]) -> T:
|
||||
cmp = func1(b)
|
||||
|
||||
# This should generate an error.
|
||||
cmp(a)
|
||||
|
||||
return a
|
@ -747,6 +747,12 @@ test('Solver33', () => {
|
||||
TestUtils.validateResults(analysisResults, 0);
|
||||
});
|
||||
|
||||
test('Solver34', () => {
|
||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['solver34.py']);
|
||||
|
||||
TestUtils.validateResults(analysisResults, 1);
|
||||
});
|
||||
|
||||
test('SolverScoring1', () => {
|
||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['solverScoring1.py']);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user