@@ -229,45 +229,15 @@ Supported Left-Hand Operands
229229-----------------------------
230230
231231The ``@ `` operator is implemented by adding ``nb_matrix_multiply `` to the
232- metatype (``type ``) and to several typing-related types. The operator is
232+ metatype (``type ``) and to several types used in type hinting (including
233+ ``NoneType ``). The operator is
233234supported for any left-hand operand that currently supports the ``| ``
234- operator for making a union.
235+ operator for making a union (including ``type(None) ``, which acts as the
236+ canonical equivalent to ``None `` in type hints).
235237
236238For all other left-hand operands, the operator returns ``NotImplemented ``,
237239allowing normal ``__matmul__ `` dispatch to proceed.
238240
239- Parsing and Grammar
240- ===================
241-
242- This proposal requires no changes to the Python grammar. Because ``@ `` is
243- already a valid operator, it is natively parsed as a binary operation. The
244- shorthand is resolved during semantic analysis, entirely bypassing the need
245- to patch grammar files or update the parser.
246-
247- How to Teach This
248- =================
249-
250- In Python, the ``@ `` symbol already has an established association with
251- metadata through decorators. The annotation shorthand extends this
252- intuition to the type system: ``int @ Field(gt=0) `` reads as "``int ``,
253- decorated with ``Field(gt=0) ``."
254-
255- For beginners, the key rule is simple: **in a type annotation, ``@`` means
256- "with this metadata." ** The full ``Annotated[int, Field(gt=0)] `` syntax
257- remains available and is entirely equivalent for those who find it clearer.
258-
259- For experienced developers, the precedence rules follow standard Python
260- operator precedence (``@ `` binds tighter than ``| ``), and chaining
261- ``T @ m1 @ m2 `` flattens exactly as nested ``Annotated `` does.
262-
263- Documentation and teaching materials should introduce the shorthand alongside
264- ``Annotated ``, not as a replacement. The longhand form is still preferred in
265- contexts where multiple metadata items are passed as a group and chaining
266- would be unwieldy.
267-
268- Backwards Compatibility
269- =======================
270-
271241Forward References and Deferred Evaluation
272242-------------------------------------------
273243
@@ -277,8 +247,9 @@ module provides several formats for retrieving annotations:
277247- ``Format.VALUE ``: Fully evaluates the annotation. Raises ``NameError ``
278248 if any name is unresolvable.
279249- ``Format.FORWARDREF ``: Wraps unresolvable names in ``ForwardRef `` objects.
280- However, compound expressions using operators (``@ ``, ``| ``) produce an
281- opaque ``ForwardRef `` string containing the entire expression.
250+ However, when operators like ``@ `` or ``| `` fail to evaluate because of an
251+ unresolvable name, this format falls back to returning the entire expression
252+ as an opaque string wrapped in a single ``ForwardRef `` object.
282253- ``Format.STRING ``: Returns the raw source text with no evaluation.
283254
284255For the ``@ `` operator, ``Format.FORWARDREF `` is insufficient. Consider::
@@ -293,8 +264,8 @@ forward reference is resolved. This is a blocking issue for libraries like
293264Pydantic and FastAPI, which inspect metadata at class-definition time.
294265
295266This proposal introduces a new format, ``Format.FORWARDREF_STRUCTURAL ``.
296- This format assumes typing semantics and evaluates compound type expressions
297- **structurally **. It always returns an ``AnnotatedType `` for ``@ ``, a union
267+ This format assumes typing semantics and evaluates type expressions involving
268+ operators (like `` @ `` and `` | ``) **structurally **. It always returns an ``AnnotatedType `` for ``@ ``, a union
298269for ``| ``, and a ``GenericAlias `` for subscripting. When a name cannot be
299270resolved, only that name is wrapped in ``ForwardRef ``; the surrounding
300271operators are still evaluated. The example above produces::
@@ -304,7 +275,10 @@ operators are still evaluated. The example above produces::
304275The metadata is immediately accessible. This format also resolves the
305276pre-existing issue with ``| `` unions, where ``"Foo" | int `` under
306277``Format.FORWARDREF `` produces ``ForwardRef('Foo | int') `` instead of the
307- structural ``ForwardRef('Foo') | int ``.
278+ structural ``ForwardRef('Foo') | int ``. Notably, if ``FORWARDREF_STRUCTURAL ``
279+ becomes the default evaluation strategy for type hints, it could eventually
280+ reduce or eliminate the need for runtime type objects to implement
281+ ``__matmul__ ``.
308282
309283Interaction with PEP 563
310284^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -321,6 +295,38 @@ coarser than from :pep:`749` thunks. When a name is unresolvable, the
321295rather than just a name. :pep: `749 ` provides a strictly better experience and
322296is the recommended path forward.
323297
298+ Parsing and Grammar
299+ ===================
300+
301+ This proposal requires no changes to the Python grammar. Because ``@ `` is
302+ already a valid operator, it is natively parsed as a binary operation. The
303+ shorthand is resolved during semantic analysis, entirely bypassing the need
304+ to patch grammar files or update the parser.
305+
306+ How to Teach This
307+ =================
308+
309+ In Python, the ``@ `` symbol already has an established association with
310+ metadata through decorators. The annotation shorthand extends this
311+ intuition to the type system: ``int @ Field(gt=0) `` reads as "``int ``,
312+ decorated with ``Field(gt=0) ``."
313+
314+ For beginners, the key rule is simple: **in a type annotation, ``@`` means
315+ "with this metadata." ** The full ``Annotated[int, Field(gt=0)] `` syntax
316+ remains available and is entirely equivalent for those who find it clearer.
317+
318+ For experienced developers, the precedence rules follow standard Python
319+ operator precedence (``@ `` binds tighter than ``| ``), and chaining
320+ ``T @ m1 @ m2 `` flattens exactly as nested ``Annotated `` does.
321+
322+ Documentation and teaching materials should introduce the shorthand alongside
323+ ``Annotated ``, not as a replacement. The longhand form is still preferred in
324+ contexts where multiple metadata items are passed as a group and chaining
325+ would be unwieldy.
326+
327+ Backwards Compatibility
328+ =======================
329+
324330Operator Overloading
325331--------------------
326332
@@ -354,7 +360,8 @@ metaclass.
354360The private ``typing._AnnotatedAlias `` class is retained as a deprecated
355361compatibility shim. Code using ``isinstance(x, typing._AnnotatedAlias) ``
356362will continue to work but emit a ``DeprecationWarning ``. The shim is
357- scheduled for removal in Python 3.18.
363+ scheduled for removal in Python 3.21 (following the standard 5-year deprecation
364+ policy outlined in :pep: `387 `).
358365
359366Code that should be updated:
360367
0 commit comments