mypy icon indicating copy to clipboard operation
mypy copied to clipboard

Type alias over generic parameter in generic class produces an error

Open Dunes opened this issue 1 year ago • 2 comments

Bug Report

Given a class context (eg. class class Foo[T]), mypy fails to infer the generic parameter when used as part of a type alias that is declared in the class context.

Using type aliases within a class can help avoid repetition when complex generics are used throughout the class.

To Reproduce

class X[Y]:
    type Z = list[Y] # produces: error: All type parameters should be declared ("Y" not declared)  [valid-type]
    
    def __init__(self, val: Y) -> None:
        self.val = val

    def make_list(self) -> Z:
        return [self.val]

reveal_type(X(123).make_list())  # Revealed type *expected* to be "builtins.list[builtins.int]"
                                 # is instead "builtins.list[Any]"

https://mypy-play.net/?mypy=latest&python=3.12&gist=845d9b12620d3febc625406e2a093ca2

Expected Behavior

The generic parameter Y should be inferred from the context of the class where it was specified.

It should be noted that pyright is able to deduce Y and therefore Z. See https://pyright-play.net/?code=MYGwhgzhAEAaDaBNAugLgFDS9ALgTwAcBTaALWgF5oQBLCHJZTbZrAEyIDNoB9HmgHY0cfABQQiITgBpoANzAhU0RAEpoAWgB80AHIB7AUQzZT0CVIB0CkJXmL0raB24BbMAGsiPWvXGTOdW0yEzMsACciHABXcIFoeAtOa0UmdEi5IkUefGJRWFEARgAmAGZVS3cvHzocUVVVIA

Actual Behavior

mytypes.py:2: error: All type parameters should be declared ("Y" not declared)  [valid-type]
mytypes.py:10: note: Revealed type is "builtins.list[Any]"
Found 1 error in 1 file (checked 1 source file)

Your Environment

  • Mypy version used: 1.12
  • Mypy command-line flags: --strict
  • Mypy configuration options from mypy.ini (and other config files): none
  • Python version used: 3.12

Dunes avatar Oct 15 '24 08:10 Dunes

Hm, FWIW such use case is explicitly prohibited for old-style type alias syntax (because in old syntax the intent was ambiguous). With new-style syntax this may be OK. In the meantime you can use an easy workaround:

class Gen[T]:
    type Alias[S] = Some[Complex[Type[Gen[S]]]]
    var: Alias[T]  # OK

cc @JukkaL

ilevkivskyi avatar Oct 15 '24 21:10 ilevkivskyi

@ilevkivskyi Thanks, that was really helpful.

It should be noted that pyright is able to infer the types of Y and therefore Z. See https://pyright-play.net/?code=MYGwhgzhAEAaDaBNAugLgFDS9ALgTwAcBTaALWgF5oQBLCHJZTbZrAEyIDNoB9HmgHY0cfABQQiITgBpoANzAhU0RAEpoAWgB80AHIB7AUQzZT0CVIB0CkJXmL0raB24BbMAGsiPWvXGTOdW0yEzMsACciHABXcIFoeAtOa0UmdEi5IkUefGJRWFEARgAmAGZVS3cvHzocUVVVIA

Dunes avatar Oct 15 '24 22:10 Dunes

Am I doing the workaround wrong? It does not work as I understand it.

If I want to do

class A[T]:
    type elems = list[T]

which works in e.g. pyright. To make it work in mypy with the workaround it would be

class A[T]:
    type helper[S] = list[S]
    elems: helper[T]
    
mylist: A[float].elems = [1]

reveal_type(mylist)

Produces

main.py:5: error: Invalid type comment or annotation  [valid-type]
main.py:7: note: Revealed type is "Any"         <------ I expect list[float]
Found 1 error in 1 file (checked 1 source file)

Playground: https://mypy-play.net/?mypy=latest&python=3.12&gist=12d802b27914bef54ccb3f7721909d5b

rsdenijs avatar Aug 22 '25 15:08 rsdenijs