Skip to content

Commit

Permalink
Fix crash on TypedDict unpacking for ParamSpec (#17358)
Browse files Browse the repository at this point in the history
Fixes #17345
Fixes #17112
Fixes #16616

Oh well, I clearly remember I have put those lines before `if` only
because otherwise the line would be 101 chars long, and I didn't want to
wrap arguments. Now I see it was a bad idea, LOL.

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
ilevkivskyi and pre-commit-ci[bot] committed Jun 10, 2024
1 parent 4fa4657 commit 317533c
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 3 deletions.
9 changes: 6 additions & 3 deletions mypy/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,6 @@ def infer_constraints_for_callable(
if actual_arg_type is None:
continue

actual_type = mapper.expand_actual_type(
actual_arg_type, arg_kinds[actual], callee.arg_names[i], callee.arg_kinds[i]
)
if param_spec and callee.arg_kinds[i] in (ARG_STAR, ARG_STAR2):
# If actual arguments are mapped to ParamSpec type, we can't infer individual
# constraints, instead store them and infer single constraint at the end.
Expand All @@ -243,6 +240,12 @@ def infer_constraints_for_callable(
)
param_spec_arg_names.append(arg_names[actual] if arg_names else None)
else:
actual_type = mapper.expand_actual_type(
actual_arg_type,
arg_kinds[actual],
callee.arg_names[i],
callee.arg_kinds[i],
)
c = infer_constraints(callee.arg_types[i], actual_type, SUPERTYPE_OF)
constraints.extend(c)
if (
Expand Down
25 changes: 25 additions & 0 deletions test-data/unit/check-typeddict.test
Original file line number Diff line number Diff line change
Expand Up @@ -3525,3 +3525,28 @@ class B(A):
reveal_type(B.f) # N: Revealed type is "def (self: __main__.B, **kwargs: Unpack[TypedDict('__main__.TD', {'x'?: builtins.int, 'y'?: builtins.str})])"
B().f(x=1.0) # E: Argument "x" to "f" of "B" has incompatible type "float"; expected "int"
[builtins fixtures/primitives.pyi]

[case testTypedDictUnpackWithParamSpecInference]
from typing import TypeVar, ParamSpec, Callable
from typing_extensions import TypedDict, Unpack

P = ParamSpec("P")
R = TypeVar("R")

def run(func: Callable[P, R], *args: P.args, **kwargs: P.kwargs) -> R: ...

class Params(TypedDict):
temperature: float

def test(temperature: int) -> None: ...
def test2(temperature: float, other: str) -> None: ...

class Test:
def f(self, c: Callable[..., None], **params: Unpack[Params]) -> None:
run(c, **params)
def g(self, **params: Unpack[Params]) -> None:
run(test, **params) # E: Argument "temperature" to "run" has incompatible type "float"; expected "int"
def h(self, **params: Unpack[Params]) -> None:
run(test2, other="yes", **params)
run(test2, other=0, **params) # E: Argument "other" to "run" has incompatible type "int"; expected "str"
[builtins fixtures/tuple.pyi]

0 comments on commit 317533c

Please sign in to comment.