summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorJelle Zijlstra <jelle.zijlstra@gmail.com>2024-07-27 17:24:10 (GMT)
committerGitHub <noreply@github.com>2024-07-27 17:24:10 (GMT)
commitae192262ad1cffb6ece9d16e67804386c382be0c (patch)
tree301564405a80de59fd6b04e508166a759ff434d0 /Objects
parentcbac8a3888411587beb026e246889154fbdd49a3 (diff)
downloadcpython-ae192262ad1cffb6ece9d16e67804386c382be0c.zip
cpython-ae192262ad1cffb6ece9d16e67804386c382be0c.tar.gz
cpython-ae192262ad1cffb6ece9d16e67804386c382be0c.tar.bz2
gh-119180: Add evaluate functions for type params and type aliases (#122212)
Diffstat (limited to 'Objects')
-rw-r--r--Objects/genericaliasobject.c70
-rw-r--r--Objects/typevarobject.c274
-rw-r--r--Objects/unionobject.c66
3 files changed, 280 insertions, 130 deletions
diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c
index 96c9649..64b4e26 100644
--- a/Objects/genericaliasobject.c
+++ b/Objects/genericaliasobject.c
@@ -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
@@ -51,69 +52,6 @@ ga_traverse(PyObject *self, visitproc visit, void *arg)
}
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)
{
assert(PyList_CheckExact(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;
}
}
diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c
index c8ab140..fb1f260 100644
--- a/Objects/typevarobject.c
+++ b/Objects/typevarobject.c
@@ -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},
};
@@ -1585,6 +1845,17 @@ typealias_value(PyObject *self, void *unused)
}
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)
{
typealiasobject *ta = (typealiasobject *)self;
@@ -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 *
diff --git a/Objects/unionobject.c b/Objects/unionobject.c
index 7931f43..6e65a65 100644
--- a/Objects/unionobject.c
+++ b/Objects/unionobject.c
@@ -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;
}
}