Description
from typing import Optional, List, Tuple, Dict, Callable
def foo(x: int) -> None: pass
def bar(x: int) -> None: pass
funcs = [foo, bar]
reveal_type(funcs)
def oops(x: List[Callable[[int], None]]) -> None:
reveal_type(x)
oops(funcs)
produces the error message
Argument 1 to "oops" has incompatible type "List[Callable[[int], None]]"; expected "List[Callable[[int], None]]"
, followed by some advice about covariance. The astute observer will note that those types are exactly the same.
Digging a bit deeper with reveal_type
, though, gives us that funcs
actually has the more precise type
builtins.list[def (x: builtins.int)]
, which includes the argument name.
So what is happening here is that we are inferring the type of the list of functions to include the name of the function argument, which then produces an error when passed to oops
because List
is invariant. It is perhaps debatable whether we want to be inferring a type like that in this situation. We definitely want to produce a better error message when we do.