From 79d91e29d0641cbf8f5de7f077a856cd74a1df17 Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Wed, 12 Feb 2025 13:09:31 -0800 Subject: [PATCH] Updated draft PEP 747 to fix a few bugs found by reviewers and to reflect the majority consensus on assignability of `type[T]` to `TypeForm[T]`. --- peps/pep-0747.rst | 53 +++++++++++++++++------------------------------ 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/peps/pep-0747.rst b/peps/pep-0747.rst index d056db8ca89..13af0f3dc87 100644 --- a/peps/pep-0747.rst +++ b/peps/pep-0747.rst @@ -200,12 +200,17 @@ that represent a type assignable to ``str | None``:: err1: TypeForm[str | None] = str | int # Error err2: TypeForm[str | None] = list[str | None] # Error -By this same definition, ``TypeForm[Any]`` describes a type form object -that represents the type ``Any`` or any type that is assignable to ``Any``. -Since all types in the Python type system are assignable to ``Any``, -``TypeForm[Any]`` describes the set of all type form objects +By this same definition, ``TypeForm[object]`` describes a type form object +that represents the type ``object`` or any type that is assignable to ``object``. +Since all types in the Python type system are assignable to ``object``, +``TypeForm[object]`` describes the set of all type form objects evaluated from all valid type expressions. +``TypeForm[Any]`` describes a ``TypeForm`` type whose type argument is not +statically known but is a valid type form object. It is thus assignable both +to and from any other ``TypeForm`` type (because ``Any`` is assignable both +to and from any type). + The type expression ``TypeForm``, with no type argument provided, is equivalent to ``TypeForm[Any]``. @@ -289,9 +294,9 @@ This explicit syntax serves two purposes. First, it documents the developer's intent to use the value as a type form object. Second, static type checkers validate that all rules for type expressions are followed:: - x4 = type(int) # No error, evaluates to "type[int]" + x4 = type(1) # No error, evaluates to "type[int]" - x5 = TypeForm(type(int)) # Error: call not allowed in type expression + x5 = TypeForm(type(1)) # Error: call not allowed in type expression Assignability @@ -306,6 +311,14 @@ Assignability t1: TypeForm[int | str] = get_type_form() # OK t2: TypeForm[str] = get_type_form() # Error +``type[T]`` is a subtype of ``TypeForm[T]``, which means that ``type[B]`` is +assignable to ``TypeForm[A]`` if ``B`` is assignable to ``A``:: + + def get_type() -> type[int]: ... + + t3: TypeForm[int | str] = get_type() # OK + t4: TypeForm[str] = get_type() # Error + ``TypeForm`` is a subtype of ``object`` and is assumed to have all of the attributes and methods of ``object``. @@ -530,34 +543,6 @@ of ``type``. .. _designed: https://mail.python.org/archives/list/typing-sig@python.org/message/D5FHORQVPHX3BHUDGF3A3TBZURBXLPHD/ -Treat ``type[T]`` as a subtype of ``TypeForm[T]`` -------------------------------------------------- - -It was suggested that type ``type[T]`` should be considered a subtype -of ``TypeForm[T]``. This was ultimately rejected because there are ways to -create an object of type ``type[T]`` that does not encode a valid type expression. -For example, the expression ``type[1]`` is not a valid type expression. Likewise, -the expression ``type[S]`` is not a valid type expression if ``S`` is an -out-of-scope type variable. This same argument applies to other special forms -like objects of type ``UnionType``, which may or may not encode a valid type -expression. Rather than carving out a special case for ``type[T]`` that would -allow for potential unsoundness, it was decided to treat all type forms -consistently. Therefore, ``type[T]`` is not considered a subtype of ``TypeForm[T]``. - -It was also pointed out that the expression ``C | C`` (where ``C`` is a class -object) is a valid type expression - and therefore a valid ``TypeForm``, -but its runtime type form encoding is an instance of ``UnionType`` and -therefore is not compatible with ``type[C]``. - -If a function wishes to indicate that it accepts values of type ``TypeForm[T]`` -_and_ ``type[T]``, the parameter can simply be annotated with a union of these -two types. - -:: - - def func[T](t: TypeForm[T] | type[T]) -> None: ... - - Accept arbitrary annotation expressions ---------------------------------------