Skip to content

Commit da0d594

Browse files
authored
PEP 827: Produce errors for invalid type operations (#4914)
* PEP 827: Produce errors for invalid type operations Currently the PEP calls for returning `Never`. * a bit more explicit discussion
1 parent 4e806c4 commit da0d594

1 file changed

Lines changed: 37 additions & 14 deletions

File tree

peps/pep-0827.rst

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,9 @@ which produce aliases that have some dunder methods overloaded for
588588
Many of the operators specified have type bounds listed for some of
589589
their operands. These should be interpreted more as documentation than
590590
as exact type bounds. Trying to evaluate operators with invalid
591-
arguments will produce ``Never`` as the return. (There is some
591+
arguments will produce an error. When this happens, the value of the
592+
failed operator is ``Any``, so that downstream evaluation does not
593+
cascade further errors. (There is some
592594
discussion of potential alternatives :ref:`below <pep827-strict-kinds>`.)
593595

594596
Note that in some of these bounds below we write things like
@@ -622,10 +624,13 @@ Basic operators
622624
'''''''''''''''
623625

624626
* ``GetArg[T, Base, Idx: Literal[int]]``: returns the type argument
625-
number ``Idx`` to ``T`` when interpreted as ``Base``, or ``Never``
626-
if it cannot be. (That is, if we have ``class A(B[C]): ...``, then
627+
number ``Idx`` to ``T`` when interpreted as ``Base``, or generates a type
628+
error if it cannot be or if the index is invalid.
629+
(That is, if we have ``class A(B[C]): ...``, then
627630
``GetArg[A, B, Literal[0]] == C``
628-
while ``GetArg[A, A, Literal[0]] == Never``).
631+
while ``GetArg[A, A, Literal[0]]`` is a type error).
632+
633+
If ``T`` is ``Any``, the result is ``Any``.
629634

630635
Negative indexes work in the usual way.
631636

@@ -640,15 +645,19 @@ Basic operators
640645
``Param`` types.
641646

642647
* ``GetArgs[T, Base]``: returns a tuple containing all of the type
643-
arguments of ``T`` when interpreted as ``Base``, or ``Never`` if it
648+
arguments of ``T`` when interpreted as ``Base``, or an error if it
644649
cannot be.
645650

651+
If ``T`` is ``Any``, the result is ``Any``.
652+
646653
* ``Length[T: tuple]`` - Gets the length of a tuple as an int literal
647654
(or ``Literal[None]`` if it is unbounded)
648655

649656
* ``Slice[S: tuple, Start: Literal[int | None], End: Literal[int | None]]``:
650657
Slices a tuple type.
651658

659+
If ``S`` is ``Any``, the result is ``Any``.
660+
652661
* ``GetSpecialAttr[T, Attr: Literal[str]]``: Extracts the value
653662
of the special attribute named ``Attr`` from the class ``T``. Valid
654663
attributes are ``__name__``, ``__module__``, and ``__qualname__``.
@@ -688,11 +697,15 @@ Object inspection
688697
methods).
689698

690699
* ``GetMember[T, S: Literal[str]]``: Produces a ``Member`` type for the
691-
member named ``S`` from the class ``T``, or ``Never`` if it does not exist.
700+
member named ``S`` from the class ``T``, or an error if it does not exist.
701+
702+
If ``T`` is ``Any``, the result is ``Any``.
692703

693704
* ``GetMemberType[T, S: Literal[str]]``: Extract the type of the
694705
member named ``S`` from the class ``T``, or ``Never`` if it does not exist.
695706

707+
If ``T`` is ``Any``, the result is ``Any``.
708+
696709
* ``Member[N: Literal[str], T, Q: MemberQuals, Init, D]``: ``Member``,
697710
is a simple type, not an operator, that is used to describe members
698711
of classes. Its type parameters encode the information about each
@@ -1736,18 +1749,30 @@ This proposal is less "strictly-typed" than TypeScript
17361749

17371750
TypeScript has better typechecking at the alias definition site:
17381751
For ``P[K]``, ``K`` needs to have ``keyof P``. The ``extends``
1739-
conditional type operator narrows the type to help spuport this.
1752+
conditional type operator narrows the type to help support this.
1753+
1754+
It's not possible to define a type alias in TypeScript that fails at
1755+
expansion time, but it *is* possible to do so in this system.
17401756

1741-
We could do potentially better but it would require quite a bit more
1742-
machinery.
1757+
We could potentially also make this impossible but it would require
1758+
quite a bit more machinery.
17431759

17441760
* ``KeyOf[T]`` - literal keys of ``T``
17451761
* ``Member[T]``, when statically checking a type alias, could be
17461762
treated as having some type like ``tuple[Member[KeyOf[T], object,
17471763
str, ..., ...], ...]``
1748-
* ``GetMemberType[T, S: KeyOf[T]]`` - but this isn't supported yet.
1749-
TypeScript supports it.
1750-
* We would also need to do context sensitive type bound inference
1764+
* ``GetMemberType[T, S: KeyOf[T]]`` - Make ``GetMember`` have a bound
1765+
requiring the index be a key... but this kind of dependent bound
1766+
isn't supported currently. (TypeScript supports it.)
1767+
* We would also need to do context sensitive type bound
1768+
inference. This is subtle but obviously this sort of thing is done
1769+
at term level.
1770+
1771+
We think that this isn't worth the complexity, and is also not even
1772+
obviously better. TypeScript commonly requires doing many conditionals where
1773+
often it is always intended that they take the true branch--typically
1774+
the false branch returns ``never``, and these can be quite difficult
1775+
to track down.
17511776

17521777

17531778
Potential Future Extensions
@@ -1838,8 +1863,6 @@ simulated in other ways.
18381863
Open Issues
18391864
===========
18401865

1841-
* What invalid operations should be errors and what should return ``Never``?
1842-
18431866
* :ref:`Unpack of typevars for **kwargs <pep827-unpack-kwargs>`: Should
18441867
whether we try to infer literal types for extra arguments be
18451868
configurable in the ``TypedDict`` serving as the bound somehow? If

0 commit comments

Comments
 (0)