Skip to content

Aliases for generic class applications get type Any #2349

Closed

Description

@rwbarton

As of #2302 mypy accepts use of a type application of a generic class as an expression anywhere. Previously, such applications were only allowed in type aliases (i.e., on the RHS of a simple assignment). But there is still special logic for such aliases, and it creates unexpected Any types. (They were there before too, but now there's clearly no reason for them.)

from typing import TypeVar, Generic
T = TypeVar('T')
class C(Generic[T]): pass

reveal_type(C[int]())
  # before 2302: Generic type is prohibited as a runtime expression (use a type alias or '# type:' comment)
  #            : Revealed type is 'Any'
  #  after 2302: Revealed type is 'index.C[builtins.int*]'

c = C[int]
x = c()
reveal_type(x)
  # both before and after 2302: Revealed type is 'Any'
  # (Even c has type Any.)

Activity

  1. gvanrossum commented on Oct 27, 2016

    @gvanrossum
    Member

    Ouch!

  2. added this to the milestone on Oct 27, 2016
  3. rwbarton commented on Oct 27, 2016

    @rwbarton
    ContributorAuthor

    It would be worth investigating whether special type checking of aliases can be removed completely. Special processing is still needed in semantic analysis so that the alias can be used in a type annotation, but I'm not aware of a situation where the type checker still needs to treat the type alias definition specially.

  4. ilevkivskyi commented on Nov 8, 2016

    @ilevkivskyi
    Member

    @gvanrossum @rwbarton This issue could be closed now. It was fixed by #2378

  5. ilevkivskyi commented on Nov 8, 2016

    @ilevkivskyi
    Member

    Concerning whether we need special treatment: It looks like the way they are treated now is left from times when there was no Type[...] i.e. TypeType in mypy terminology. I think we could use this now to treat type alias nodes on common ground with other expressions. But I could say that this would be a somewhat significant refactoring.

  6. rwbarton commented on Nov 8, 2016

    @rwbarton
    ContributorAuthor

    It's still not obvious to me why any special logic is required at all. (Even before Type[C], since we already had a special Callable type with is_type_obj=True for the type of a bare class like C, which is still the inferred type anyways.)

    Consider these three program fragments, where C is a generic class:

    x = C[int]()
    reveal_type(x)
    c = C[int]
    x = c()
    reveal_type(x)
    (c,) = (C[int],)
    x = c()
    reveal_type(x)

    The first produces C[builtins.int*] of course. The second produces C[builtins.int*], but only after your commit 57ff82b. But the third always produced C[builtins.int*], just by side-stepping the type alias logic. Mypy is not smart enough to recognize the (c,) = (C[int],) form as a type alias, but it is smart enough to understand how to type check it. In fact, the reason that the third program succeeds is exactly the same as the reason the first program succeeds.

    So, at least in this case, the logic added in 57ff82b seems to be somehow redundant, in the sense that if the type checker did not treat type alias definition RHSs specially at all, it would have already gotten the correct result.

  7. ilevkivskyi commented on Nov 8, 2016

    @ilevkivskyi
    Member

    @rwbarton Concerning the third example, I am not sure what do you mean by "always". Before #2302 generic type application was prohibited in runtime context (this has nothing to do with aliases), so that first example and most probably two other would simply give you an error and x would be Any.

    Probably you wanted to say that c = C[int] always worked in type context like x: c or x = None # type: c. However, this is a simple example, it required some effort to allow Vec = Iterable[Tuple[T, T]] etc. (see http://mypy.readthedocs.io/en/latest/kinds_of_types.html#type-aliases) and cover many corner cases.

    Anyway, my first attempt to allow generic type aliases was actually exactly like you suggested: just re-using type application (this is the thing that makes mypy "smart enough to understand how to type check it"), but I didn't manage to do this. I have nothing against someone refactoring type aliases either using TypeType or TypeApplicationExpr, I am rather in favour of this. I just wanted to say that this will require some time and effort.

  8. rwbarton commented on Nov 8, 2016

    @rwbarton
    ContributorAuthor

    I'm not sure exactly when the third fragment started working, but it was many commits before 57ff82b. I am quite sure that I am talking about these three program fragments, and not any other.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrong

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions