Skip to content

Incremental mode bug for nested ParamSpecs #14322

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

Open
ringohoffman opened this issue Dec 20, 2022 · 1 comment
Open

Incremental mode bug for nested ParamSpecs #14322

ringohoffman opened this issue Dec 20, 2022 · 1 comment
Labels
bug mypy got something wrong topic-incremental topic-paramspec PEP 612, ParamSpec, Concatenate

Comments

@ringohoffman
Copy link

Bug Report

This bug only occurs on the second run when using incremental mode. When using nested ParamSpecs, the outer ParamSpec (M below) is erroneously equal to the inner ParamSpec (P below).

Notably, pyright handles this correctly.

To Reproduce

from __future__ import annotations

from typing import Callable, Concatenate, Generic, ParamSpec, TypeVar


class ABase:
    ...


class ADerived(ABase):
    def __init__(self, a_param_1: float) -> None:
        super().__init__()
        self.a_1 = a_param_1


M = ParamSpec("M")
P = ParamSpec("P")
R = TypeVar("R", bound=ABase)


class B(Generic[P, R]):
    def __init__(
        self,
        a_class: Callable[P, R],
        b_param_1: str,
        *args: P.args,
        **kwargs: P.kwargs,
    ) -> None:
        self.a = a_class(*args, **kwargs)
        self.b_1 = b_param_1

    @classmethod
    def build(
        cls: Callable[Concatenate[Callable[P, R], M], B[P, R]], 
        a_class: Callable[P, R]
    ) -> Callable[M, B[P, R]]:

        def new_constructor(
            *args: M.args,
            **kwargs: M.kwargs,
        ) -> B[P, R]:
            return cls(a_class, *args, **kwargs)

        return new_constructor


BADerived = B.build(ADerived)

reveal_type(BADerived)  # note): Revealed type is "def (a_param_1: builtins.float) -> B[[a_param_1: builtins.float], ADerived]"

b_a_derived_1 = B(ADerived, "my_str", 1.0)  # OK
b_a_derived_2 = BADerived(  # [call-arg] error: Too many arguments
    "my_str", 1.0  # [arg-type] error: Argument 1 has incompatible type "str"; expected "float"
)

Expected Behavior

I expect the signature of BADerived to include b_param_1, like this:

mypy_nested_paramspec.py:49: note: Revealed type is "def (b_param_1: builtins.str, a_param_1: builtins.float) -> mypy_nested_paramspec.B[[a_param_1: builtins.float], ADerived]"

I also expect that calls to BADerived with the correct parameter count and types do not raise any errors.

Actual Behavior

mypy_nested_paramspec.py:49: note: Revealed type is "def (a_param_1: builtins.float) -> mypy_nested_paramspec.B[[a_param_1: builtins.float], mypy_nested_paramspec.ADerived]"
mypy_nested_paramspec.py:52: error: Too many arguments  [call-arg]
mypy_nested_paramspec.py:53: error: Argument 1 has incompatible type "str"; expected "float"  [arg-type]

Your Environment

  • Mypy version used: mypy 0.991 (compiled: yes)
  • Python version used: 3.10.6
@ringohoffman ringohoffman added the bug mypy got something wrong label Dec 20, 2022
@ringohoffman
Copy link
Author

BTW if anyone can advise ... I am also at a loss to annotate BADerived and solve my var-annotated error:

main.py:53: error: Need type annotation for "BADerived"  [var-annotated]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-incremental topic-paramspec PEP 612, ParamSpec, Concatenate
Projects
None yet
Development

No branches or pull requests

2 participants