bpo-46491: Allow Annotated on outside of Final/ClassVar (GH-30864)


We treat Annotated type arg as class-level annotation. This exempts it from checks against Final and ClassVar in order to allow using them in any nesting order.

Automerge-Triggered-By: GH:gvanrossum
(cherry picked from commit e1abffca45b60729c460e3e2ad50c8c1946cfd4e)

Co-authored-by: Gregory Beauregard <greg@greg.red>
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index acad35d..a840ffe 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -4582,6 +4582,14 @@ class C:
         A.x = 5
         self.assertEqual(C.x, 5)
 
+    def test_special_form_containment(self):
+        class C:
+            classvar: Annotated[ClassVar[int], "a decoration"] = 4
+            const: Annotated[Final[int], "Const"] = 4
+
+        self.assertEqual(get_type_hints(C, globals())['classvar'], ClassVar[int])
+        self.assertEqual(get_type_hints(C, globals())['const'], Final[int])
+
     def test_hash_eq(self):
         self.assertEqual(len({Annotated[int, 4, 5], Annotated[int, 4, 5]}), 1)
         self.assertNotEqual(Annotated[int, 4, 5], Annotated[int, 5, 4])
diff --git a/Lib/typing.py b/Lib/typing.py
index 2522547..705331a 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -143,7 +143,7 @@ def _type_convert(arg, module=None):
     return arg
 
 
-def _type_check(arg, msg, is_argument=True, module=None, *, is_class=False):
+def _type_check(arg, msg, is_argument=True, module=None, *, allow_special_forms=False):
     """Check that the argument is a type, and return it (internal helper).
 
     As a special case, accept None and return type(None) instead. Also wrap strings
@@ -156,7 +156,7 @@ def _type_check(arg, msg, is_argument=True, module=None, *, is_class=False):
     We append the repr() of the actual value (truncated to 100 chars).
     """
     invalid_generic_forms = (Generic, Protocol)
-    if not is_class:
+    if not allow_special_forms:
         invalid_generic_forms += (ClassVar,)
         if is_argument:
             invalid_generic_forms += (Final,)
@@ -691,7 +691,7 @@ def _evaluate(self, globalns, localns, recursive_guard):
                 eval(self.__forward_code__, globalns, localns),
                 "Forward references must evaluate to types.",
                 is_argument=self.__forward_is_argument__,
-                is_class=self.__forward_is_class__,
+                allow_special_forms=self.__forward_is_class__,
             )
             self.__forward_value__ = _eval_type(
                 type_, globalns, localns, recursive_guard | {self.__forward_arg__}
@@ -1677,7 +1677,7 @@ def __class_getitem__(cls, params):
                             "with at least two arguments (a type and an "
                             "annotation).")
         msg = "Annotated[t, ...]: t must be a type."
-        origin = _type_check(params[0], msg)
+        origin = _type_check(params[0], msg, allow_special_forms=True)
         metadata = tuple(params[1:])
         return _AnnotatedAlias(origin, metadata)