]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-119180: Add evaluate functions for type params and type aliases (#122212)
authorJelle Zijlstra <jelle.zijlstra@gmail.com>
Sat, 27 Jul 2024 17:24:10 +0000 (10:24 -0700)
committerGitHub <noreply@github.com>
Sat, 27 Jul 2024 17:24:10 +0000 (17:24 +0000)
Include/internal/pycore_global_objects.h
Include/internal/pycore_typevarobject.h
Lib/annotationlib.py
Lib/test/test_annotationlib.py
Lib/test/test_type_params.py
Misc/NEWS.d/next/Library/2024-07-23-22-26-00.gh-issue-119180.B2IVT8.rst [new file with mode: 0644]
Objects/genericaliasobject.c
Objects/typevarobject.c
Objects/unionobject.c
Python/compile.c
Python/symtable.c

index 327fcc24cb29f11a66f77af0918af127691eb78d..913dce6f1ec0fe37d0f5f4aa9a444db87dfed46f 100644 (file)
@@ -81,6 +81,7 @@ struct _Py_interp_cached_objects {
     PyTypeObject *paramspec_type;
     PyTypeObject *paramspecargs_type;
     PyTypeObject *paramspeckwargs_type;
+    PyTypeObject *constevaluator_type;
 };
 
 #define _Py_INTERP_STATIC_OBJECT(interp, NAME) \
index a368edebd622a163b3bc9de07bff1e219fd85d29..4d7556e68cdaeedafd18e0a64ae0ba3e03efb37d 100644 (file)
@@ -16,6 +16,7 @@ extern PyObject *_Py_subscript_generic(PyThreadState *, PyObject *);
 extern PyObject *_Py_set_typeparam_default(PyThreadState *, PyObject *, PyObject *);
 extern int _Py_initialize_generic(PyInterpreterState *);
 extern void _Py_clear_generic_types(PyInterpreterState *);
+extern int _Py_typing_type_repr(PyUnicodeWriter *, PyObject *);
 
 extern PyTypeObject _PyTypeAlias_Type;
 extern PyTypeObject _PyNoDefault_Type;
index eea24232f9f0d0ab06f87fc5a04076c6cc3c1791..141e31bbf910e3247b2a46c8091fa998db858379 100644 (file)
@@ -413,7 +413,16 @@ class _StringifierDict(dict):
         return fwdref
 
 
-def call_annotate_function(annotate, format, owner=None):
+def call_evaluate_function(evaluate, format, *, owner=None):
+    """Call an evaluate function. Evaluate functions are normally generated for
+    the value of type aliases and the bounds, constraints, and defaults of
+    type parameter objects.
+    """
+    return call_annotate_function(evaluate, format, owner=owner, _is_evaluate=True)
+
+
+def call_annotate_function(annotate, format, *, owner=None,
+                           _is_evaluate=False):
     """Call an __annotate__ function. __annotate__ functions are normally
     generated by the compiler to defer the evaluation of annotations. They
     can be called with any of the format arguments in the Format enum, but
@@ -459,8 +468,11 @@ def call_annotate_function(annotate, format, owner=None):
             closure = tuple(new_closure)
         else:
             closure = None
-        func = types.FunctionType(annotate.__code__, globals, closure=closure)
+        func = types.FunctionType(annotate.__code__, globals, closure=closure,
+                                  argdefs=annotate.__defaults__, kwdefaults=annotate.__kwdefaults__)
         annos = func(Format.VALUE)
+        if _is_evaluate:
+            return annos if isinstance(annos, str) else repr(annos)
         return {
             key: val if isinstance(val, str) else repr(val)
             for key, val in annos.items()
@@ -511,7 +523,8 @@ def call_annotate_function(annotate, format, owner=None):
             closure = tuple(new_closure)
         else:
             closure = None
-        func = types.FunctionType(annotate.__code__, globals, closure=closure)
+        func = types.FunctionType(annotate.__code__, globals, closure=closure,
+                                  argdefs=annotate.__defaults__, kwdefaults=annotate.__kwdefaults__)
         result = func(Format.VALUE)
         for obj in globals.stringifiers:
             obj.__class__ = ForwardRef
index e459d27d3c4b3836d39c5ffc8e485edbc5610c77..e4dcdb6b58d009999a15f27cadb2dcb1face8455 100644 (file)
@@ -773,6 +773,25 @@ class TestGetAnnotations(unittest.TestCase):
         )
 
 
+class TestCallEvaluateFunction(unittest.TestCase):
+    def test_evaluation(self):
+        def evaluate(format, exc=NotImplementedError):
+            if format != 1:
+                raise exc
+            return undefined
+
+        with self.assertRaises(NameError):
+            annotationlib.call_evaluate_function(evaluate, annotationlib.Format.VALUE)
+        self.assertEqual(
+            annotationlib.call_evaluate_function(evaluate, annotationlib.Format.FORWARDREF),
+            annotationlib.ForwardRef("undefined"),
+        )
+        self.assertEqual(
+            annotationlib.call_evaluate_function(evaluate, annotationlib.Format.SOURCE),
+            "undefined",
+        )
+
+
 class MetaclassTests(unittest.TestCase):
     def test_annotated_meta(self):
         class Meta(type):
index bf1a34b9fc82b35cdf505d7eae0e77c28ddc5feb..d9c9ec4eddc368201c25f36fe11ce303cfb50ac8 100644 (file)
@@ -1,3 +1,4 @@
+import annotationlib
 import asyncio
 import textwrap
 import types
@@ -6,7 +7,7 @@ import pickle
 import weakref
 from test.support import requires_working_socket, check_syntax_error, run_code
 
-from typing import Generic, NoDefault, Sequence, TypeVar, TypeVarTuple, ParamSpec, get_args
+from typing import Generic, NoDefault, Sequence, TypeAliasType, TypeVar, TypeVarTuple, ParamSpec, get_args
 
 
 class TypeParamsInvalidTest(unittest.TestCase):
@@ -1394,3 +1395,43 @@ class DefaultsTest(unittest.TestCase):
 
         self.assertEqual(ns["X1"].__type_params__[0].__default__, "A")
         self.assertEqual(ns["X2"].__type_params__[0].__default__, "B")
+
+
+class TestEvaluateFunctions(unittest.TestCase):
+    def test_general(self):
+        type Alias = int
+        Alias2 = TypeAliasType("Alias2", int)
+        def f[T: int = int, **P = int, *Ts = int](): pass
+        T, P, Ts = f.__type_params__
+        T2 = TypeVar("T2", bound=int, default=int)
+        P2 = ParamSpec("P2", default=int)
+        Ts2 = TypeVarTuple("Ts2", default=int)
+        cases = [
+            Alias.evaluate_value,
+            Alias2.evaluate_value,
+            T.evaluate_bound,
+            T.evaluate_default,
+            P.evaluate_default,
+            Ts.evaluate_default,
+            T2.evaluate_bound,
+            T2.evaluate_default,
+            P2.evaluate_default,
+            Ts2.evaluate_default,
+        ]
+        for case in cases:
+            with self.subTest(case=case):
+                self.assertIs(case(1), int)
+                self.assertIs(annotationlib.call_evaluate_function(case, annotationlib.Format.VALUE), int)
+                self.assertIs(annotationlib.call_evaluate_function(case, annotationlib.Format.FORWARDREF), int)
+                self.assertEqual(annotationlib.call_evaluate_function(case, annotationlib.Format.SOURCE), 'int')
+
+    def test_constraints(self):
+        def f[T: (int, str)](): pass
+        T, = f.__type_params__
+        T2 = TypeVar("T2", int, str)
+        for case in [T, T2]:
+            with self.subTest(case=case):
+                self.assertEqual(case.evaluate_constraints(1), (int, str))
+                self.assertEqual(annotationlib.call_evaluate_function(case.evaluate_constraints, annotationlib.Format.VALUE), (int, str))
+                self.assertEqual(annotationlib.call_evaluate_function(case.evaluate_constraints, annotationlib.Format.FORWARDREF), (int, str))
+                self.assertEqual(annotationlib.call_evaluate_function(case.evaluate_constraints, annotationlib.Format.SOURCE), '(int, str)')
diff --git a/Misc/NEWS.d/next/Library/2024-07-23-22-26-00.gh-issue-119180.B2IVT8.rst b/Misc/NEWS.d/next/Library/2024-07-23-22-26-00.gh-issue-119180.B2IVT8.rst
new file mode 100644 (file)
index 0000000..13f51e4
--- /dev/null
@@ -0,0 +1,7 @@
+As part of :pep:`749`, add the following attributes for customizing
+evaluation of annotation scopes:
+
+* ``evaluate_value`` on :class:`typing.TypeAliasType`
+* ``evaluate_bound``, ``evaluate_constraints``, and ``evaluate_default`` on :class:`typing.TypeVar`
+* ``evaluate_default`` on :class:`typing.ParamSpec`
+* ``evaluate_default`` on :class:`typing.TypeVarTuple`
index 96c96491501a2cb0a518244fb0b961dc08c8167d..64b4e2645cbaeee1f746f8550776773052e4160c 100644 (file)
@@ -4,6 +4,7 @@
 #include "pycore_ceval.h"         // _PyEval_GetBuiltin()
 #include "pycore_modsupport.h"    // _PyArg_NoKeywords()
 #include "pycore_object.h"
+#include "pycore_typevarobject.h" // _Py_typing_type_repr
 #include "pycore_unionobject.h"   // _Py_union_type_or, _PyGenericAlias_Check
 
 
@@ -50,69 +51,6 @@ ga_traverse(PyObject *self, visitproc visit, void *arg)
     return 0;
 }
 
-static int
-ga_repr_item(PyUnicodeWriter *writer, PyObject *p)
-{
-    PyObject *qualname = NULL;
-    PyObject *module = NULL;
-    int rc;
-
-    if (p == Py_Ellipsis) {
-        // The Ellipsis object
-        rc = PyUnicodeWriter_WriteUTF8(writer, "...", 3);
-        goto done;
-    }
-
-    if ((rc = PyObject_HasAttrWithError(p, &_Py_ID(__origin__))) > 0 &&
-        (rc = PyObject_HasAttrWithError(p, &_Py_ID(__args__))) > 0)
-    {
-        // It looks like a GenericAlias
-        goto use_repr;
-    }
-    if (rc < 0) {
-        goto error;
-    }
-
-    if (PyObject_GetOptionalAttr(p, &_Py_ID(__qualname__), &qualname) < 0) {
-        goto error;
-    }
-    if (qualname == NULL) {
-        goto use_repr;
-    }
-    if (PyObject_GetOptionalAttr(p, &_Py_ID(__module__), &module) < 0) {
-        goto error;
-    }
-    if (module == NULL || module == Py_None) {
-        goto use_repr;
-    }
-
-    // Looks like a class
-    if (PyUnicode_Check(module) &&
-        _PyUnicode_EqualToASCIIString(module, "builtins"))
-    {
-        // builtins don't need a module name
-        rc = PyUnicodeWriter_WriteStr(writer, qualname);
-        goto done;
-    }
-    else {
-        rc = PyUnicodeWriter_Format(writer, "%S.%S", module, qualname);
-        goto done;
-    }
-
-error:
-    rc = -1;
-    goto done;
-
-use_repr:
-    rc = PyUnicodeWriter_WriteRepr(writer, p);
-    goto done;
-
-done:
-    Py_XDECREF(qualname);
-    Py_XDECREF(module);
-    return rc;
-}
-
 static int
 ga_repr_items_list(PyUnicodeWriter *writer, PyObject *p)
 {
@@ -131,7 +69,7 @@ ga_repr_items_list(PyUnicodeWriter *writer, PyObject *p)
             }
         }
         PyObject *item = PyList_GET_ITEM(p, i);
-        if (ga_repr_item(writer, item) < 0) {
+        if (_Py_typing_type_repr(writer, item) < 0) {
             return -1;
         }
     }
@@ -162,7 +100,7 @@ ga_repr(PyObject *self)
             goto error;
         }
     }
-    if (ga_repr_item(writer, alias->origin) < 0) {
+    if (_Py_typing_type_repr(writer, alias->origin) < 0) {
         goto error;
     }
     if (PyUnicodeWriter_WriteChar(writer, '[') < 0) {
@@ -181,7 +119,7 @@ ga_repr(PyObject *self)
                 goto error;
             }
         }
-        else if (ga_repr_item(writer, p) < 0) {
+        else if (_Py_typing_type_repr(writer, p) < 0) {
             goto error;
         }
     }
index c8ab14053de4183ea1fdaf97136e9c323a375849..fb1f260571b5823567f1f1e2b571a8006d830910 100644 (file)
@@ -116,6 +116,201 @@ PyTypeObject _PyNoDefault_Type = {
 
 PyObject _Py_NoDefaultStruct = _PyObject_HEAD_INIT(&_PyNoDefault_Type);
 
+typedef struct {
+    PyObject_HEAD
+    PyObject *value;
+} constevaluatorobject;
+
+static void
+constevaluator_dealloc(PyObject *self)
+{
+    PyTypeObject *tp = Py_TYPE(self);
+    constevaluatorobject *ce = (constevaluatorobject *)self;
+
+    _PyObject_GC_UNTRACK(self);
+
+    Py_XDECREF(ce->value);
+
+    Py_TYPE(self)->tp_free(self);
+    Py_DECREF(tp);
+}
+
+static int
+constevaluator_traverse(PyObject *self, visitproc visit, void *arg)
+{
+    constevaluatorobject *ce = (constevaluatorobject *)self;
+    Py_VISIT(ce->value);
+    return 0;
+}
+
+static int
+constevaluator_clear(PyObject *self)
+{
+    Py_CLEAR(((constevaluatorobject *)self)->value);
+    return 0;
+}
+
+static PyObject *
+constevaluator_repr(PyObject *self, PyObject *repr)
+{
+    PyObject *value = ((constevaluatorobject *)self)->value;
+    return PyUnicode_FromFormat("<constevaluator %R>", value);
+}
+
+static PyObject *
+constevaluator_call(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+    if (!_PyArg_NoKeywords("constevaluator.__call__", kwargs)) {
+        return NULL;
+    }
+    int format;
+    if (!PyArg_ParseTuple(args, "i:constevaluator.__call__", &format)) {
+        return NULL;
+    }
+    PyObject *value = ((constevaluatorobject *)self)->value;
+    if (format == 3) { // SOURCE
+        _PyUnicodeWriter writer;
+        _PyUnicodeWriter_Init(&writer);
+        if (PyTuple_Check(value)) {
+            if (_PyUnicodeWriter_WriteASCIIString(&writer, "(", 1) < 0) {
+                _PyUnicodeWriter_Dealloc(&writer);
+                return NULL;
+            }
+            for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(value); i++) {
+                PyObject *item = PyTuple_GET_ITEM(value, i);
+                if (i > 0) {
+                    if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) {
+                        _PyUnicodeWriter_Dealloc(&writer);
+                        return NULL;
+                    }
+                }
+                if (_Py_typing_type_repr(&writer, item) < 0) {
+                    _PyUnicodeWriter_Dealloc(&writer);
+                    return NULL;
+                }
+            }
+            if (_PyUnicodeWriter_WriteASCIIString(&writer, ")", 1) < 0) {
+                _PyUnicodeWriter_Dealloc(&writer);
+                return NULL;
+            }
+        }
+        else {
+            if (_Py_typing_type_repr(&writer, value) < 0) {
+                _PyUnicodeWriter_Dealloc(&writer);
+                return NULL;
+            }
+        }
+        return _PyUnicodeWriter_Finish(&writer);
+    }
+    return Py_NewRef(value);
+}
+
+static PyObject *
+constevaluator_alloc(PyObject *value)
+{
+    PyTypeObject *tp = _PyInterpreterState_GET()->cached_objects.constevaluator_type;
+    assert(tp != NULL);
+    constevaluatorobject *ce = PyObject_GC_New(constevaluatorobject, tp);
+    if (ce == NULL) {
+        return NULL;
+    }
+    ce->value = Py_NewRef(value);
+    _PyObject_GC_TRACK(ce);
+    return (PyObject *)ce;
+
+}
+
+PyDoc_STRVAR(constevaluator_doc,
+"_ConstEvaluator()\n"
+"--\n\n"
+"Internal type for implementing evaluation functions.");
+
+static PyType_Slot constevaluator_slots[] = {
+    {Py_tp_doc, (void *)constevaluator_doc},
+    {Py_tp_dealloc, constevaluator_dealloc},
+    {Py_tp_traverse, constevaluator_traverse},
+    {Py_tp_clear, constevaluator_clear},
+    {Py_tp_repr, constevaluator_repr},
+    {Py_tp_call, constevaluator_call},
+    {Py_tp_alloc, PyType_GenericAlloc},
+    {Py_tp_free, PyObject_GC_Del},
+    {0, NULL},
+};
+
+PyType_Spec constevaluator_spec = {
+    .name = "_typing._ConstEvaluator",
+    .basicsize = sizeof(constevaluatorobject),
+    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE,
+    .slots = constevaluator_slots,
+};
+
+int
+_Py_typing_type_repr(PyUnicodeWriter *writer, PyObject *p)
+{
+    PyObject *qualname = NULL;
+    PyObject *module = NULL;
+    PyObject *r = NULL;
+    int rc;
+
+    if (p == Py_Ellipsis) {
+        // The Ellipsis object
+        r = PyUnicode_FromString("...");
+        goto exit;
+    }
+
+    if (p == (PyObject *)&_PyNone_Type) {
+        return _PyUnicodeWriter_WriteASCIIString(writer, "None", 4);
+    }
+
+    if ((rc = PyObject_HasAttrWithError(p, &_Py_ID(__origin__))) > 0 &&
+        (rc = PyObject_HasAttrWithError(p, &_Py_ID(__args__))) > 0)
+    {
+        // It looks like a GenericAlias
+        goto use_repr;
+    }
+    if (rc < 0) {
+        goto exit;
+    }
+
+    if (PyObject_GetOptionalAttr(p, &_Py_ID(__qualname__), &qualname) < 0) {
+        goto exit;
+    }
+    if (qualname == NULL) {
+        goto use_repr;
+    }
+    if (PyObject_GetOptionalAttr(p, &_Py_ID(__module__), &module) < 0) {
+        goto exit;
+    }
+    if (module == NULL || module == Py_None) {
+        goto use_repr;
+    }
+
+    // Looks like a class
+    if (PyUnicode_Check(module) &&
+        _PyUnicode_EqualToASCIIString(module, "builtins"))
+    {
+        // builtins don't need a module name
+        r = PyObject_Str(qualname);
+        goto exit;
+    }
+    else {
+        r = PyUnicode_FromFormat("%S.%S", module, qualname);
+        goto exit;
+    }
+
+use_repr:
+    r = PyObject_Repr(p);
+exit:
+    Py_XDECREF(qualname);
+    Py_XDECREF(module);
+    if (r == NULL) {
+        return -1;
+    }
+    rc = _PyUnicodeWriter_WriteStr(writer, r);
+    Py_DECREF(r);
+    return rc;
+}
+
 
 static PyObject *
 call_typing_func_object(const char *name, PyObject **args, size_t nargs)
@@ -364,10 +559,49 @@ typevar_constraints(typevarobject *self, void *Py_UNUSED(ignored))
     return constraints;
 }
 
+static PyObject *
+typevar_evaluate_bound(typevarobject *self, void *Py_UNUSED(ignored))
+{
+    if (self->evaluate_bound != NULL) {
+        return Py_NewRef(self->evaluate_bound);
+    }
+    if (self->bound != NULL) {
+        return constevaluator_alloc(self->bound);
+    }
+    Py_RETURN_NONE;
+}
+
+static PyObject *
+typevar_evaluate_constraints(typevarobject *self, void *Py_UNUSED(ignored))
+{
+    if (self->evaluate_constraints != NULL) {
+        return Py_NewRef(self->evaluate_constraints);
+    }
+    if (self->constraints != NULL) {
+        return constevaluator_alloc(self->constraints);
+    }
+    Py_RETURN_NONE;
+}
+
+static PyObject *
+typevar_evaluate_default(typevarobject *self, void *Py_UNUSED(ignored))
+{
+    if (self->evaluate_default != NULL) {
+        return Py_NewRef(self->evaluate_default);
+    }
+    if (self->default_value != NULL) {
+        return constevaluator_alloc(self->default_value);
+    }
+    Py_RETURN_NONE;
+}
+
 static PyGetSetDef typevar_getset[] = {
     {"__bound__", (getter)typevar_bound, NULL, NULL, NULL},
     {"__constraints__", (getter)typevar_constraints, NULL, NULL, NULL},
     {"__default__", (getter)typevar_default, NULL, NULL, NULL},
+    {"evaluate_bound", (getter)typevar_evaluate_bound, NULL, NULL, NULL},
+    {"evaluate_constraints", (getter)typevar_evaluate_constraints, NULL, NULL, NULL},
+    {"evaluate_default", (getter)typevar_evaluate_default, NULL, NULL, NULL},
     {0}
 };
 
@@ -995,10 +1229,23 @@ paramspec_default(paramspecobject *self, void *unused)
     return default_value;
 }
 
+static PyObject *
+paramspec_evaluate_default(paramspecobject *self, void *unused)
+{
+    if (self->evaluate_default != NULL) {
+        return Py_NewRef(self->evaluate_default);
+    }
+    if (self->default_value != NULL) {
+        return constevaluator_alloc(self->default_value);
+    }
+    Py_RETURN_NONE;
+}
+
 static PyGetSetDef paramspec_getset[] = {
     {"args", (getter)paramspec_args, NULL, PyDoc_STR("Represents positional arguments."), NULL},
     {"kwargs", (getter)paramspec_kwargs, NULL, PyDoc_STR("Represents keyword arguments."), NULL},
     {"__default__", (getter)paramspec_default, NULL, "The default value for this ParamSpec.", NULL},
+    {"evaluate_default", (getter)paramspec_evaluate_default, NULL, NULL, NULL},
     {0},
 };
 
@@ -1437,8 +1684,21 @@ typevartuple_default(typevartupleobject *self, void *unused)
     return default_value;
 }
 
+static PyObject *
+typevartuple_evaluate_default(typevartupleobject *self, void *unused)
+{
+    if (self->evaluate_default != NULL) {
+        return Py_NewRef(self->evaluate_default);
+    }
+    if (self->default_value != NULL) {
+        return constevaluator_alloc(self->default_value);
+    }
+    Py_RETURN_NONE;
+}
+
 static PyGetSetDef typevartuple_getset[] = {
     {"__default__", (getter)typevartuple_default, NULL, "The default value for this TypeVarTuple.", NULL},
+    {"evaluate_default", (getter)typevartuple_evaluate_default, NULL, NULL, NULL},
     {0},
 };
 
@@ -1584,6 +1844,17 @@ typealias_value(PyObject *self, void *unused)
     return typealias_get_value(ta);
 }
 
+static PyObject *
+typealias_evaluate_value(PyObject *self, void *unused)
+{
+    typealiasobject *ta = (typealiasobject *)self;
+    if (ta->compute_value != NULL) {
+        return Py_NewRef(ta->compute_value);
+    }
+    assert(ta->value != NULL);
+    return constevaluator_alloc(ta->value);
+}
+
 static PyObject *
 typealias_parameters(PyObject *self, void *unused)
 {
@@ -1627,6 +1898,7 @@ static PyGetSetDef typealias_getset[] = {
     {"__parameters__", typealias_parameters, (setter)NULL, NULL, NULL},
     {"__type_params__", typealias_type_params, (setter)NULL, NULL, NULL},
     {"__value__", typealias_value, (setter)NULL, NULL, NULL},
+    {"evaluate_value", typealias_evaluate_value, (setter)NULL, NULL, NULL},
     {"__module__", typealias_module, (setter)NULL, NULL, NULL},
     {0}
 };
@@ -1952,6 +2224,7 @@ int _Py_initialize_generic(PyInterpreterState *interp)
     MAKE_TYPE(paramspec);
     MAKE_TYPE(paramspecargs);
     MAKE_TYPE(paramspeckwargs);
+    MAKE_TYPE(constevaluator);
 #undef MAKE_TYPE
     return 0;
 }
@@ -1964,6 +2237,7 @@ void _Py_clear_generic_types(PyInterpreterState *interp)
     Py_CLEAR(interp->cached_objects.paramspec_type);
     Py_CLEAR(interp->cached_objects.paramspecargs_type);
     Py_CLEAR(interp->cached_objects.paramspeckwargs_type);
+    Py_CLEAR(interp->cached_objects.constevaluator_type);
 }
 
 PyObject *
index 7931f4345f7fdde309f4604cb972ed2e5da4ad83..6e65a653a95c46dfff039eba09c0477d4596a6d1 100644 (file)
@@ -1,11 +1,10 @@
 // types.UnionType -- used to represent e.g. Union[int, str], int | str
 #include "Python.h"
 #include "pycore_object.h"  // _PyObject_GC_TRACK/UNTRACK
-#include "pycore_typevarobject.h"  // _PyTypeAlias_Type
+#include "pycore_typevarobject.h"  // _PyTypeAlias_Type, _Py_typing_type_repr
 #include "pycore_unionobject.h"
 
 
-
 static PyObject *make_union(PyObject *);
 
 
@@ -181,67 +180,6 @@ _Py_union_type_or(PyObject* self, PyObject* other)
     return new_union;
 }
 
-static int
-union_repr_item(PyUnicodeWriter *writer, PyObject *p)
-{
-    PyObject *qualname = NULL;
-    PyObject *module = NULL;
-    int rc;
-
-    if (p == (PyObject *)&_PyNone_Type) {
-        return PyUnicodeWriter_WriteUTF8(writer, "None", 4);
-    }
-
-    if ((rc = PyObject_HasAttrWithError(p, &_Py_ID(__origin__))) > 0 &&
-        (rc = PyObject_HasAttrWithError(p, &_Py_ID(__args__))) > 0)
-    {
-        // It looks like a GenericAlias
-        goto use_repr;
-    }
-    if (rc < 0) {
-        goto error;
-    }
-
-    if (PyObject_GetOptionalAttr(p, &_Py_ID(__qualname__), &qualname) < 0) {
-        goto error;
-    }
-    if (qualname == NULL) {
-        goto use_repr;
-    }
-    if (PyObject_GetOptionalAttr(p, &_Py_ID(__module__), &module) < 0) {
-        goto error;
-    }
-    if (module == NULL || module == Py_None) {
-        goto use_repr;
-    }
-
-    // Looks like a class
-    if (PyUnicode_Check(module) &&
-        _PyUnicode_EqualToASCIIString(module, "builtins"))
-    {
-        // builtins don't need a module name
-        rc = PyUnicodeWriter_WriteStr(writer, qualname);
-        goto done;
-    }
-    else {
-        rc = PyUnicodeWriter_Format(writer, "%S.%S", module, qualname);
-        goto done;
-    }
-
-error:
-    rc = -1;
-    goto done;
-
-use_repr:
-    rc = PyUnicodeWriter_WriteRepr(writer, p);
-    goto done;
-
-done:
-    Py_XDECREF(qualname);
-    Py_XDECREF(module);
-    return rc;
-}
-
 static PyObject *
 union_repr(PyObject *self)
 {
@@ -260,7 +198,7 @@ union_repr(PyObject *self)
             goto error;
         }
         PyObject *p = PyTuple_GET_ITEM(alias->args, i);
-        if (union_repr_item(writer, p) < 0) {
+        if (_Py_typing_type_repr(writer, p) < 0) {
             goto error;
         }
     }
index d07a435bdf8dacd8c4918b36ce8f7964250ffc4a..02b5345cedd0a38abf55d64cbd05d283f1a654b7 100644 (file)
@@ -1978,8 +1978,9 @@ compiler_type_param_bound_or_default(struct compiler *c, expr_ty e,
                                      identifier name, void *key,
                                      bool allow_starred)
 {
-    if (compiler_enter_scope(c, name, COMPILER_SCOPE_ANNOTATIONS,
-                             key, e->lineno, NULL) == -1) {
+    PyObject *defaults = PyTuple_Pack(1, _PyLong_GetOne());
+    ADDOP_LOAD_CONST_NEW(c, LOC(e), defaults);
+    if (compiler_setup_annotations_scope(c, LOC(e), key, name) == -1) {
         return ERROR;
     }
     if (allow_starred && e->kind == Starred_kind) {
@@ -1995,7 +1996,7 @@ compiler_type_param_bound_or_default(struct compiler *c, expr_ty e,
     if (co == NULL) {
         return ERROR;
     }
-    if (compiler_make_closure(c, LOC(e), co, 0) < 0) {
+    if (compiler_make_closure(c, LOC(e), co, MAKE_FUNCTION_DEFAULTS) < 0) {
         Py_DECREF(co);
         return ERROR;
     }
@@ -2566,8 +2567,10 @@ compiler_typealias_body(struct compiler *c, stmt_ty s)
 {
     location loc = LOC(s);
     PyObject *name = s->v.TypeAlias.name->v.Name.id;
+    PyObject *defaults = PyTuple_Pack(1, _PyLong_GetOne());
+    ADDOP_LOAD_CONST_NEW(c, loc, defaults);
     RETURN_IF_ERROR(
-        compiler_enter_scope(c, name, COMPILER_SCOPE_FUNCTION, s, loc.lineno, NULL));
+        compiler_setup_annotations_scope(c, LOC(s), s, name));
     /* Make None the first constant, so the evaluate function can't have a
         docstring. */
     RETURN_IF_ERROR(compiler_add_const(c, Py_None));
@@ -2578,7 +2581,7 @@ compiler_typealias_body(struct compiler *c, stmt_ty s)
     if (co == NULL) {
         return ERROR;
     }
-    if (compiler_make_closure(c, loc, co, 0) < 0) {
+    if (compiler_make_closure(c, loc, co, MAKE_FUNCTION_DEFAULTS) < 0) {
         Py_DECREF(co);
         return ERROR;
     }
index a5fa7588785d8b67720be1e93cc681b37e472a54..88af37198bfba5e0a253f36642d103bde534518a 100644 (file)
@@ -260,6 +260,7 @@ static int symtable_visit_pattern(struct symtable *st, pattern_ty s);
 static int symtable_raise_if_annotation_block(struct symtable *st, const char *, expr_ty);
 static int symtable_raise_if_not_coroutine(struct symtable *st, const char *msg, _Py_SourceLocation loc);
 static int symtable_raise_if_comprehension_block(struct symtable *st, expr_ty);
+static int symtable_add_def(struct symtable *st, PyObject *name, int flag, _Py_SourceLocation loc);
 
 /* For debugging purposes only */
 #if _PY_DUMP_SYMTABLE
@@ -1388,6 +1389,16 @@ symtable_enter_block(struct symtable *st, identifier name, _Py_block_ty block,
         return 0;
     int result = symtable_enter_existing_block(st, ste);
     Py_DECREF(ste);
+    if (block == AnnotationBlock || block == TypeVariableBlock || block == TypeAliasBlock) {
+        _Py_DECLARE_STR(format, ".format");
+        // We need to insert code that reads this "parameter" to the function.
+        if (!symtable_add_def(st, &_Py_STR(format), DEF_PARAM, loc)) {
+            return 0;
+        }
+        if (!symtable_add_def(st, &_Py_STR(format), USE, loc)) {
+            return 0;
+        }
+    }
     return result;
 }
 
@@ -2630,18 +2641,6 @@ symtable_visit_annotation(struct symtable *st, expr_ty annotation, void *key)
                 return 0;
             }
         }
-
-        _Py_DECLARE_STR(format, ".format");
-        // The generated __annotate__ function takes a single parameter with the
-        // internal name ".format".
-        if (!symtable_add_def(st, &_Py_STR(format), DEF_PARAM,
-                                LOCATION(annotation))) {
-            return 0;
-        }
-        if (!symtable_add_def(st, &_Py_STR(format), USE,
-                                LOCATION(annotation))) {
-            return 0;
-        }
     }
     else {
         if (!symtable_enter_existing_block(st, parent_ste->ste_annotation_block)) {
@@ -2690,14 +2689,6 @@ symtable_visit_annotations(struct symtable *st, stmt_ty o, arguments_ty a, expr_
             return 0;
         }
     }
-    _Py_DECLARE_STR(format, ".format");
-    // We need to insert code that reads this "parameter" to the function.
-    if (!symtable_add_def(st, &_Py_STR(format), DEF_PARAM, LOCATION(o))) {
-        return 0;
-    }
-    if (!symtable_add_def(st, &_Py_STR(format), USE, LOCATION(o))) {
-        return 0;
-    }
     if (a->posonlyargs && !symtable_visit_argannotations(st, a->posonlyargs))
         return 0;
     if (a->args && !symtable_visit_argannotations(st, a->args))