mirror of
https://github.com/microsoft/pyright.git
synced 2024-10-03 19:37:39 +03:00
Fixed bug that results in a false negative when passing an extra keyword argument to a callable that is parameterized with a ParamSpec. This addresses #8294. (#8299)
This commit is contained in:
parent
280ed52e8c
commit
8a766d59a4
@ -10867,25 +10867,36 @@ export function createTypeEvaluator(
|
|||||||
paramSpecArgList.push(argList[argIndex]);
|
paramSpecArgList.push(argList[argIndex]);
|
||||||
} else if (paramDetails.kwargsIndex !== undefined) {
|
} else if (paramDetails.kwargsIndex !== undefined) {
|
||||||
const paramType = paramDetails.params[paramDetails.kwargsIndex].type;
|
const paramType = paramDetails.params[paramDetails.kwargsIndex].type;
|
||||||
validateArgTypeParams.push({
|
if (isParamSpec(paramType)) {
|
||||||
paramCategory: ParameterCategory.KwargsDict,
|
if (!canSkipDiagnosticForNode(errorNode) && !isTypeIncomplete) {
|
||||||
paramType,
|
addDiagnostic(
|
||||||
requiresTypeVarMatching: requiresSpecialization(paramType),
|
DiagnosticRule.reportCallIssue,
|
||||||
argument: argList[argIndex],
|
LocMessage.paramNameMissing().format({ name: paramName.value }),
|
||||||
errorNode: argList[argIndex].valueExpression ?? errorNode,
|
paramName
|
||||||
paramName: paramNameValue,
|
);
|
||||||
});
|
}
|
||||||
|
reportedArgError = true;
|
||||||
|
} else {
|
||||||
|
validateArgTypeParams.push({
|
||||||
|
paramCategory: ParameterCategory.KwargsDict,
|
||||||
|
paramType,
|
||||||
|
requiresTypeVarMatching: requiresSpecialization(paramType),
|
||||||
|
argument: argList[argIndex],
|
||||||
|
errorNode: argList[argIndex].valueExpression ?? errorNode,
|
||||||
|
paramName: paramNameValue,
|
||||||
|
});
|
||||||
|
|
||||||
// Remember that this parameter has already received a value.
|
// Remember that this parameter has already received a value.
|
||||||
paramMap.set(paramNameValue, {
|
paramMap.set(paramNameValue, {
|
||||||
argsNeeded: 1,
|
argsNeeded: 1,
|
||||||
argsReceived: 1,
|
argsReceived: 1,
|
||||||
isPositionalOnly: false,
|
isPositionalOnly: false,
|
||||||
});
|
});
|
||||||
assert(
|
assert(
|
||||||
paramDetails.params[paramDetails.kwargsIndex],
|
paramDetails.params[paramDetails.kwargsIndex],
|
||||||
'paramDetails.kwargsIndex params entry is undefined'
|
'paramDetails.kwargsIndex params entry is undefined'
|
||||||
);
|
);
|
||||||
|
}
|
||||||
trySetActive(argList[argIndex], paramDetails.params[paramDetails.kwargsIndex].param);
|
trySetActive(argList[argIndex], paramDetails.params[paramDetails.kwargsIndex].param);
|
||||||
} else {
|
} else {
|
||||||
if (!canSkipDiagnosticForNode(errorNode) && !isTypeIncomplete) {
|
if (!canSkipDiagnosticForNode(errorNode) && !isTypeIncomplete) {
|
||||||
|
@ -35,11 +35,13 @@ async def func2():
|
|||||||
|
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def func3(x: int) -> None: ...
|
def func3(x: int) -> None:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def func3(x: str) -> str: ...
|
def func3(x: str) -> str:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
def func3(x: int | str) -> str | None:
|
def func3(x: int | str) -> str | None:
|
||||||
@ -73,7 +75,8 @@ def decorator2(f: Callable[P, R]) -> Callable[P, R]:
|
|||||||
|
|
||||||
|
|
||||||
def func5(f: Callable[[], list[T1]]) -> Callable[[list[T2]], list[T1 | T2]]:
|
def func5(f: Callable[[], list[T1]]) -> Callable[[list[T2]], list[T1 | T2]]:
|
||||||
def inner(res: list[T2], /) -> list[T1 | T2]: ...
|
def inner(res: list[T2], /) -> list[T1 | T2]:
|
||||||
|
...
|
||||||
|
|
||||||
return decorator2(inner)
|
return decorator2(inner)
|
||||||
|
|
||||||
@ -87,18 +90,22 @@ def func6(x: Iterable[Callable[P, None]]) -> Callable[P, None]:
|
|||||||
|
|
||||||
|
|
||||||
class Callback1:
|
class Callback1:
|
||||||
def __call__(self, x: int | str, y: int = 3) -> None: ...
|
def __call__(self, x: int | str, y: int = 3) -> None:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
class Callback2:
|
class Callback2:
|
||||||
def __call__(self, x: int, /) -> None: ...
|
def __call__(self, x: int, /) -> None:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
class Callback3:
|
class Callback3:
|
||||||
def __call__(self, *args, **kwargs) -> None: ...
|
def __call__(self, *args, **kwargs) -> None:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
def func7(f1: Callable[P, R], f2: Callable[P, R]) -> Callable[P, R]: ...
|
def func7(f1: Callable[P, R], f2: Callable[P, R]) -> Callable[P, R]:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
def func8(cb1: Callback1, cb2: Callback2, cb3: Callback3):
|
def func8(cb1: Callback1, cb2: Callback2, cb3: Callback3):
|
||||||
@ -107,3 +114,8 @@ def func8(cb1: Callback1, cb2: Callback2, cb3: Callback3):
|
|||||||
|
|
||||||
v2 = func7(cb1, cb3)
|
v2 = func7(cb1, cb3)
|
||||||
reveal_type(v2, expected_text="(x: int | str, y: int = 3) -> None")
|
reveal_type(v2, expected_text="(x: int | str, y: int = 3) -> None")
|
||||||
|
|
||||||
|
|
||||||
|
def func9(f: Callable[P, object], *args: P.args, **kwargs: P.kwargs) -> object:
|
||||||
|
# This should generate an error because "name" doesn't exist.
|
||||||
|
return f(*args, **kwargs, name="")
|
||||||
|
@ -558,7 +558,7 @@ test('ParamSpec2', () => {
|
|||||||
|
|
||||||
test('ParamSpec3', () => {
|
test('ParamSpec3', () => {
|
||||||
const results = TestUtils.typeAnalyzeSampleFiles(['paramSpec3.py']);
|
const results = TestUtils.typeAnalyzeSampleFiles(['paramSpec3.py']);
|
||||||
TestUtils.validateResults(results, 1);
|
TestUtils.validateResults(results, 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ParamSpec4', () => {
|
test('ParamSpec4', () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user