Skip to content
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

Pep 613 / Pep 484 - specify scope restrictions and inference rules for type alias vs variables #2158

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions pep-0484.txt
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,37 @@ This is equivalent to::
return ((x * scale, y * scale) for x, y in v)
vec = [] # type: Iterable[Tuple[float, float]]

Simple variable assignments may be either type aliases or variables. PEP 613
provides a way to explicitly annotate a type alias. Otherwise, the type checker
should infer a type alias if all of the following conditions apply.

- There is no type annotation provided
- The LHS is a simple identifier symbol
- There is only one assignment to the LHS symbol
- The expression on the RHS of the assignment does not contain any syntactic form that would be considered illegal for a type annotation (call expressions, lambdas, comprehensions, etc.)
- The type evaluation of the RHS evaluates to an instantiable type or a union of instantiable types

Type Alias vs Variable Examples::

class Foo:
pass

F1: TypeAlias = Foo # explicit PEP 613 type alias
F2: Type[Foo] = Foo # explicit variable
F3 = Foo # inferred as type alias

F4 = None
F4 = Foo # inferred as variable

F5 = x() # inferred as variable
F6 = Union[Foo, str] # inferred as type alias

class Bar:
F7 = Foo # inferred as type alias
def __init__(self):
F8 = Foo # inferred as type alias
self.F9 = Foo # inferred as variable


Callable
--------
Expand Down Expand Up @@ -2494,6 +2525,14 @@ References
https://docs.python.org/3/reference/import.html#submodules


Version History
===============

* 2021-11-23

* Specify Type Alias vs Variable inference rules


Copyright
=========

Expand Down
52 changes: 32 additions & 20 deletions pep-0613.rst
Original file line number Diff line number Diff line change
Expand Up @@ -92,34 +92,38 @@ and ``InvalidType`` are not valid types. When the value expression is no longer
evaluated as a global value, unactionable type errors on all usages of ``MyType``
across the codebase can be suppressed.

Scope Restrictions:
*******************
Scoping:
********

Implicit and explicit type aliases can be made at any scope as long as they obey
the Type Alias vs Variable inference rules specified in PEP 484

::

x = ClassName
def foo() -> None:
x = ClassName
class Foo:
pass

The outer ``x`` is a valid type alias, but type checkers must error if the
inner ``x`` is ever used as a type because type aliases cannot be defined
inside a nested scope.
This is confusing because the alias declaration rule is not explicit, and because
a type error will not be thrown on the location of the inner type alias declaration
but rather on every one of its subsequent use cases.
F1 = Foo
class Bar:
F2 = Foo
F3: TypeAlias = Foo

On explicit type aliases made on assignments that break the inference rules specified
in PEP 484, type checkers should raise a clear error, communicating to the author
why the TypeAlias is invalid.

::

x: TypeAlias = ClassName
def foo() -> None:
x = ClassName
def bar() -> None:
x: TypeAlias = ClassName
class Foo:
pass

F1: TypeAlias = [f for f in Foo] # RHS not a valid type
F2: TypeAlias = Foo # Multiple assignments to F2
F2 = None

With explicit aliases, the outer assignment is still a valid type variable,
and the inner assignment can either be a valid local variable or a clear error,
communicating to the author that type aliases cannot be defined inside a nested
scope.
class Bar:
def __init__(self):
self.F2: TypeAlias = Foo # LHS not a simple identifier


Specification
Expand Down Expand Up @@ -200,6 +204,14 @@ appealing because it still sticks with the ``MyType = int`` assignment
syntax, and adds some information for the type checker purely as an annotation.


Version History
===============

* 2021-11-16

* Allow TypeAlias inside class/function scope


Copyright
=========

Expand Down