You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Callables like operator.call produce arg-type error with generic or overloaded functions #14337
operator.call and similarly-typed callables produce an arg-type error when used with many generic functions.
Additionally, if the arg-type error is # type: ignore'd, the inferred type is a TypeVar (removed from its scope!) rather than Any.
To Reproduce
importoperatorfromcollections.abcimportCallablefromtypingimportTypeVarfromtypingimportassert_typefromtypingimportreveal_typeT=TypeVar("T")
T0=TypeVar("T0")
U=TypeVar("U") # this is redundant, but it helps understand mypy's outputdefcall2(cb: Callable[[T0], T], arg0: T0, /) ->T:
# similar to operator.call, but only takes one posarg (doesn't use ParamSpec)returncb(arg0)
defident(x: U) ->U:
returnxassert_type(operator.call(ident, "foo"), str)
# error: Expression is of type "U", not "str" [assert-type]# error: Argument 2 to "call" has incompatible type "str"; expected "U" [arg-type]assert_type(call2(ident, "foo"), str)
# error: Expression is of type "U", not "str" [assert-type]# error: Argument 1 to "call" has incompatible type "Callable[[U], U]"; expected "Callable[[str], U]" [arg-type]x=operator.call(ident, "foo") # type: ignore[arg-type]reveal_type(x) # should be inferred as Any# note: Revealed type is "U`-1"
The inferred type of operator.call(ident, "foo") should match the inferred type of ident("foo"). (Aside: should this be str or Literal["foo"]?)
Comparing to other type checkers, call2(ident, "foo") works with pyre (inferred as Literal["foo"]), sort-of-works with pyright (inferred as U@ident | str), and doesn't work with pytype (inferred as Any).
Also, if # type: ignore[arg-type] is used on the arg-type error, the inferred type should by Any, not a TypeVar removed from its scope.
Actual Behavior
See comments in the reproducer above.
Your Environment
Mypy version used: 0.991 (compiled) and latest master (uncompiled)
Mypy command-line flags: none required to reproduce
Mypy configuration options from mypy.ini (and other config files): none required to reproduce
yeah, the problem seems to be that Mypy isn't binding TypeVars of generic functions when they are callback functions (rather than being the function being called).
changed the title [-]Callables like `operator.call` produce `arg-type` error with generic functions[/-][+]Callables like `operator.call` produce `arg-type` error with generic or overloaded functions[/+]on Mar 22, 2023
The original example (with generics) passes on current master with --new-type-inference. The other example from comments (with overloads) still fails some calls, with errors like:
test.py:24: error: Argument 1 to "call" has incompatible type overloaded function; expected "Callable[[bool], None]" [arg-type]
test.py:27: error: Argument 1 to "call" has incompatible type overloaded function; expected "Callable[[bool], None]" [arg-type]
test.py:30: error: Argument 1 to "call" has incompatible type overloaded function; expected "Callable[[bool, int], None]" [arg-type]
One can argue that mypy is overly strict here (the error goes away if you use regular position-or-name arguments in definition of foo()). But handling argument kinds is tricky with ParamSpec (unless we admit some loss of type safety in similar but incorrect examples).
I recommend opening a specific separate issue about this remaining edge case if you think it is important. (cc @JukkaL this is precisely the corner case I mentioned in #15896)
Activity
tmke8 commentedon Dec 22, 2022
It works when the definition of
call2only takes a singleTypeVar:So, I guess mypy has trouble realizing it should assign
Uto bothT0andTin your example?gschaffner commentedon Mar 22, 2023
yeah, the problem seems to be that Mypy isn't binding
TypeVars of generic functions when they are callback functions (rather than being the function being called).gschaffner commentedon Mar 22, 2023
overloads aren't getting resolved either:
(https://mypy-play.net/?mypy=1.1.1&python=3.11&gist=590d1fbbfdc8afd03a82d7877bbea61b)
[-]Callables like `operator.call` produce `arg-type` error with generic functions[/-][+]Callables like `operator.call` produce `arg-type` error with generic or overloaded functions[/+]ilevkivskyi commentedon Aug 26, 2023
The original example (with generics) passes on current master with
--new-type-inference. The other example from comments (with overloads) still fails some calls, with errors like:One can argue that mypy is overly strict here (the error goes away if you use regular position-or-name arguments in definition of
foo()). But handling argument kinds is tricky withParamSpec(unless we admit some loss of type safety in similar but incorrect examples).I recommend opening a specific separate issue about this remaining edge case if you think it is important. (cc @JukkaL this is precisely the corner case I mentioned in #15896)