Skip to content

Bug - Type aliases in closure does not work #8273

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
rmorshea opened this issue Jan 11, 2020 · 4 comments
Closed

Bug - Type aliases in closure does not work #8273

rmorshea opened this issue Jan 11, 2020 · 4 comments
Labels
bug mypy got something wrong priority-1-normal topic-calls Function calls, *args, **kwargs, defaults topic-type-alias TypeAlias and other type alias issues topic-type-variables

Comments

@rmorshea
Copy link

rmorshea commented Jan 11, 2020

This may be a known limitation of the type system, but it would be nice if it were possible to write the following without the commented error:

from typing import Any, Callable, Type, TypeVar
from threading import Lock

F = TypeVar("F", bound=Callable[..., Any])
Decorator = Callable[[F], F]  # <--- the problem type alias

def with_lock(lock: Lock) -> Decorator[F]:
    def decorator(function: F) -> F:
        def wrapper(*args, **kwargs) -> Any:
            with lock:
                return function(*args, **kwargs)
        return wrapper  # type: ignore
    return decorator

l = Lock()

reveal_type(with_lock(l))  # note: Revealed type is 'def (<nothing>) -> <nothing>'

@with_lock(l)  # error: Argument 1 has incompatible type "Callable[[Any], None]"; expected <nothing>
def use_resource(resource: Any) -> None:
    ...

In order for this to work correctly I have to replace the type alias Decorator with the explicit Callable[[F], F]. This is trivial to change in this case, but for more complex types this would inhibit readability greatly.

Details:

What version of MyPy: 0.761
Have you tried on master: no
Are there any flags engaged: no

@rmorshea rmorshea changed the title Feature - Type aliases in closures don't work Bug - Type aliases in closures don't work Jan 11, 2020
@rmorshea rmorshea changed the title Bug - Type aliases in closures don't work Bug - Type aliases in closure does not work Jan 11, 2020
@JukkaL
Copy link
Collaborator

JukkaL commented Jan 13, 2020

Here is a simplified example that shows the root cause of the unexpected behavior:

from typing import TypeVar, Callable

T = TypeVar('T')

F = Callable[[T], T]

def f() -> F[T]: ...
def g() -> Callable[[T], T]: ...

reveal_type(f)  # def [T] () -> def (T`-1) -> T`-1
reveal_type(g)  # def () -> def [T] (T`-1) -> T`-1

The scope (?) of the type variable is wrong when using a type alias. The type of f should be the same as the type of g.

@TH3CHARLie
Copy link
Collaborator

I've investigated this for a little while. For case like

from typing import TypeVar, Sequence
T = TypeVar('T')
S = Sequence[T]
def f() -> S[T]: ...
def g() -> Sequence[T]: ...

T gets bound to the function after semanal/analyze_func_def: update_function_type_variables, and then when S[T] get analyzed, T will get a binding from the function scope. Therefore, in this issue, the type variable is bound to the function instead of the aliased callable. To proper fix this issue involves at least two major steps:

  1. Update semanal/update_function_type_variables to explicitly handle TypeAlias when its target is a callable. Currently, I modify typeanal/visit_unbound_type and mimic the behavior when encountering a callable. This part seems OK.
  2. Analyze function signature, bind T. However, Callable[[T], T] is specially handled while TypeAlias go through a more generic expanding approach.

That's all I've gone so far and some insights, either high-level abstraction or low-level details would help a lot on fixing this @JukkaL

@rmorshea
Copy link
Author

rmorshea commented Aug 29, 2020

Definitely been feeling the pain of this one lately. Long type annotations (that could otherwise be broken up type aliases) are really inhibiting code readability. Anyone know of good workarounds for this?

@AlexWaygood AlexWaygood added topic-type-alias TypeAlias and other type alias issues topic-calls Function calls, *args, **kwargs, defaults labels Apr 4, 2022
@AlexWaygood
Copy link
Member

Closing as a duplicate of #3924

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong priority-1-normal topic-calls Function calls, *args, **kwargs, defaults topic-type-alias TypeAlias and other type alias issues topic-type-variables
Projects
None yet
Development

No branches or pull requests

4 participants