blob: d3a0bba20a711c7f3861f1bf54f19cfa3f332344 [file] [log] [blame]
<
/* Type object implementation */
#include "Python.h"
#include "pycore_call.h"
#include "pycore_compile.h" // _Py_Mangle()
#include "pycore_initconfig.h"
#include "pycore_moduleobject.h" // _PyModule_GetDef()
#include "pycore_object.h"
#include "pycore_pyerrors.h"
#include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_unionobject.h" // _Py_union_type_or
#include "frameobject.h"
#include "structmember.h" // PyMemberDef
#include <ctype.h>
/*[clinic input]
class type "PyTypeObject *" "&PyType_Type"
class object "PyObject *" "&PyBaseObject_Type"
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=4b94608d231c434b]*/
#include "clinic/typeobject.c.h"
/* Support type attribute lookup cache */
/* The cache can keep references to the names alive for longer than
they normally would. This is why the maximum size is limited to
MCACHE_MAX_ATTR_SIZE, since it might be a problem if very large
strings are used as attribute names. */
#define MCACHE_MAX_ATTR_SIZE 100
#define MCACHE_HASH(version, name_hash) \
(((unsigned int)(version) ^ (unsigned int)(name_hash)) \
& ((1 << MCACHE_SIZE_EXP) - 1))
#define MCACHE_HASH_METHOD(type, name) \
MCACHE_HASH((type)->tp_version_tag, ((Py_ssize_t)(name)) >> 3)
#define MCACHE_CACHEABLE_NAME(name) \
PyUnicode_CheckExact(name) && \
PyUnicode_IS_READY(name) && \
(PyUnicode_GET_LENGTH(name) <= MCACHE_MAX_ATTR_SIZE)
// bpo-42745: next_version_tag remains shared by all interpreters because of static types
// Used to set PyTypeObject.tp_version_tag
static unsigned int next_version_tag = 0;
typedef struct PySlot_Offset {
short subslot_offset;
short slot_offset;
} PySlot_Offset;
/* bpo-40521: Interned strings are shared by all subinterpreters */
#ifndef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
# define INTERN_NAME_STRINGS
#endif
/* alphabetical order */
_Py_IDENTIFIER(__abstractmethods__);
_Py_IDENTIFIER(__annotations__);
_Py_IDENTIFIER(__class__);
_Py_IDENTIFIER(__class_getitem__);
_Py_IDENTIFIER(__classcell__);
_Py_IDENTIFIER(__delitem__);
_Py_IDENTIFIER(__dict__);
_Py_IDENTIFIER(__doc__);
_Py_IDENTIFIER(__getattribute__);
_Py_IDENTIFIER(__getitem__);
_Py_IDENTIFIER(__hash__);
_Py_IDENTIFIER(__init_subclass__);
_Py_IDENTIFIER(__len__);
_Py_IDENTIFIER(__module__);
_Py_IDENTIFIER(__name__);
_Py_IDENTIFIER(__new__);
_Py_IDENTIFIER(__qualname__);
_Py_IDENTIFIER(__set_name__);
_Py_IDENTIFIER(__setitem__);
_Py_IDENTIFIER(__weakref__);
_Py_IDENTIFIER(builtins);
_Py_IDENTIFIER(mro);
static PyObject *
slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
static void
clear_slotdefs(void);
static PyObject *
lookup_maybe_method(PyObject *self, _Py_Identifier *attrid, int *unbound);
static int
slot_tp_setattro(PyObject *self, PyObject *name, PyObject *value);
/*
* finds the beginning of the docstring's introspection signature.
* if present, returns a pointer pointing to the first '('.
* otherwise returns NULL.
*
* doesn't guarantee that the signature is valid, only that it
* has a valid prefix. (the signature must also pass skip_signature.)
*/
static const char *
find_signature(const char *name, const char *doc)
{
const char *dot;
size_t length;
if (!doc)
return NULL;
assert(name != NULL);
/* for dotted names like classes, only use the last component */
dot = strrchr(name, '.');
if (dot)
name = dot + 1;
length = strlen(name);
if (strncmp(doc, name, length))
return NULL;
doc += length;
if (*doc != '(')
return NULL;
return doc;
}
#define SIGNATURE_END_MARKER ")\n--\n\n"
#define SIGNATURE_END_MARKER_LENGTH 6
/*
* skips past the end of the docstring's introspection signature.
* (assumes doc starts with a valid signature prefix.)
*/
static const char *
skip_signature(const char *doc)
{
while (*doc) {
if ((*doc == *SIGNATURE_END_MARKER) &&
!strncmp(doc, SIGNATURE_END_MARKER, SIGNATURE_END_MARKER_LENGTH))
return doc + SIGNATURE_END_MARKER_LENGTH;
if ((*doc == '\n') && (doc[1] == '\n'))
return NULL;
doc++;
}
return NULL;
}
int
_PyType_CheckConsistency(PyTypeObject *type)
{
#define CHECK(expr) \
do { if (!(expr)) { _PyObject_ASSERT_FAILED_MSG((PyObject *)type, Py_STRINGIFY(expr)); } } while (0)
CHECK(!_PyObject_IsFreed((PyObject *)type));
if (!(type->tp_flags & Py_TPFLAGS_READY)) {
/* don't check static types before PyType_Ready() */
return 1;
}
CHECK(Py_REFCNT(type) >= 1);
CHECK(PyType_Check(type));
CHECK(!(type->tp_flags & Py_TPFLAGS_READYING));
CHECK(type->tp_dict != NULL);
if (type->tp_flags & Py_TPFLAGS_DISALLOW_INSTANTIATION) {
CHECK(type->tp_new == NULL);
CHECK(_PyDict_ContainsId(type->tp_dict, &PyId___new__) == 0);
}
return 1;
#undef CHECK
}
static const char *
_PyType_DocWithoutSignature(const char *name, const char *internal_doc)
{
const char *doc = find_signature(name, internal_doc);
if (doc) {
doc = skip_signature(doc);
if (doc)
return doc;
}
return internal_doc;
}
PyObject *
_PyType_GetDocFromInternalDoc(const char *name, const char *internal_doc)
{
const char *doc = _PyType_DocWithoutSignature(name, internal_doc);
if (!doc || *doc == '\0') {
Py_RETURN_NONE;
}
return PyUnicode_FromString(doc);
}
PyObject *
_PyType_GetTextSignatureFromInternalDoc(const char *name, const char *internal_doc)
{
const char *start = find_signature(name, internal_doc);
const char *end;
if (start)
end = skip_signature(start);
else
end = NULL;
if (!end) {
Py_RETURN_NONE;
}
/* back "end" up until it points just past the final ')' */
end -= SIGNATURE_END_MARKER_LENGTH - 1;
assert((end - start) >= 2); /* should be "()" at least */
assert(end[-1] == ')');
assert(end[0] == '\n');
return PyUnicode_FromStringAndSize(start, end - start);
}
static struct type_cache*
get_type_cache(void)
{
PyInterpreterState *interp = _PyInterpreterState_GET();
return &interp->type_cache;
}
static void
type_cache_clear(struct type_cache *cache, int use_none)
{
for (Py_ssize_t i = 0; i < (1 << MCACHE_SIZE_EXP); i++) {
struct type_cache_entry *entry = &cache->hashtable[i];
entry->version = 0;
if (use_none) {
// Set to None so _PyType_Lookup() can use Py_SETREF(),
// rather than using slower Py_XSETREF().
Py_XSETREF(entry->name, Py_NewRef(Py_None));
}
else {
Py_CLEAR(entry->name);
}
entry->value = NULL;
}
// Mark all version tags as invalid
PyType_Modified(&PyBaseObject_Type);
}
void
_PyType_InitCache(PyInterpreterState *interp)
{
struct type_cache *cache = &interp->type_cache;
for (Py_ssize_t i = 0; i < (1 << MCACHE_SIZE_EXP); i++) {
struct type_cache_entry *entry = &cache->hashtable[i];
assert(entry->name == NULL);
entry->version = 0;
// Set to None so _PyType_Lookup() can use Py_SETREF(),
// rather than using slower Py_XSETREF().
entry->name = Py_NewRef(Py_None);
entry->value = NULL;
}
}
static unsigned int
_PyType_ClearCache(PyInterpreterState *interp)
{
struct type_cache *cache = &interp->type_cache;
#if MCACHE_STATS
size_t total = cache->hits + cache->collisions + cache->misses;
fprintf(stderr, "-- Method cache hits = %zd (%d%%)\n",
cache->hits, (int) (100.0 * cache->hits / total));
fprintf(stderr, "-- Method cache true misses = %zd (%d%%)\n",
cache->misses, (int) (100.0 * cache->misses / total));
fprintf(stderr, "-- Method cache collisions = %zd (%d%%)\n",
cache->collisions, (int) (100.0 * cache->collisions / total));
fprintf(stderr, "-- Method cache size = %zd KiB\n",
sizeof(cache->hashtable) / 1024);
#endif
unsigned int cur_version_tag = next_version_tag - 1;
if (_Py_IsMainInterpreter(interp)) {
next_version_tag = 0;
}
type_cache_clear(cache, 0);
return cur_version_tag;
}
unsigned int
PyType_ClearCache(void)
{
PyInterpreterState *interp = _PyInterpreterState_GET();
return _PyType_ClearCache(interp);
}
void
_PyType_Fini(PyInterpreterState *interp)
{
_PyType_ClearCache(interp);
if (_Py_IsMainInterpreter(interp)) {
clear_slotdefs();
}
}
void
PyType_Modified(PyTypeObject *type)
{
/* Invalidate any cached data for the specified type and all
subclasses. This function is called after the base
classes, mro, or attributes of the type are altered.
Invariants:
- before Py_TPFLAGS_VALID_VERSION_TAG can be set on a type,
it must first be set on all super types.
This function clears the Py_TPFLAGS_VALID_VERSION_TAG of a
type (so it must first clear it on all subclasses). The
tp_version_tag value is meaningless unless this flag is set.
We don't assign new version tags eagerly, but only as
needed.
*/
PyObject *raw, *ref;
Py_ssize_t i;
if (!_PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG))
return;
raw = type->tp_subclasses;
if (raw != NULL) {
assert(PyDict_CheckExact(raw));
i = 0;
while (PyDict_Next(raw, &i, NULL, &ref)) {
assert(PyWeakref_CheckRef(ref));
ref = PyWeakref_GET_OBJECT(ref);
if (ref != Py_None) {
PyType_Modified((PyTypeObject *)ref);
}
}
}
type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG;
type->tp_version_tag = 0; /* 0 is not a valid version tag */
}
static void
type_mro_modified(PyTypeObject *type, PyObject *bases) {
/*
Check that all base classes or elements of the MRO of type are
able to be cached. This function is called after the base
classes or mro of the type are altered.
Unset HAVE_VERSION_TAG and VALID_VERSION_TAG if the type
has a custom MRO that includes a type which is not officially
super type, or if the type implements its own mro() method.
Called from mro_internal, which will subsequently be called on
each subclass when their mro is recursively updated.
*/
Py_ssize_t i, n;
int custom = !Py_IS_TYPE(type, &PyType_Type);
int unbound;
if (custom) {
PyObject *mro_meth, *type_mro_meth;
mro_meth = lookup_maybe_method(
(PyObject *)type, &PyId_mro, &unbound);
if (mro_meth == NULL) {
goto clear;
}
type_mro_meth = lookup_maybe_method(
(PyObject *)&PyType_Type, &PyId_mro, &unbound);
if (type_mro_meth == NULL) {
Py_DECREF(mro_meth);
goto clear;
}
int custom_mro = (mro_meth != type_mro_meth);
Py_DECREF(mro_meth);
Py_DECREF(type_mro_meth);
if (custom_mro) {
goto clear;
}
}
n = PyTuple_GET_SIZE(bases);
for (i = 0; i < n; i++) {
PyObject *b = PyTuple_GET_ITEM(bases, i);
PyTypeObject *cls;
assert(PyType_Check(b));
cls = (PyTypeObject *)b;
if (!PyType_IsSubtype(type, cls)) {
goto clear;
}
}
return;
clear:
type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG;
type->tp_version_tag = 0; /* 0 is not a valid version tag */
}
static int
assign_version_tag(struct type_cache *cache, PyTypeObject *type)
{
/* Ensure that the tp_version_tag is valid and set
Py_TPFLAGS_VALID_VERSION_TAG. To respect the invariant, this
must first be done on all super classes. Return 0 if this
cannot be done, 1 if Py_TPFLAGS_VALID_VERSION_TAG.
*/
Py_ssize_t i, n;
PyObject *bases;
if (_PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG))
return 1;
if (!_PyType_HasFeature(type, Py_TPFLAGS_READY))
return 0;
type->tp_version_tag = next_version_tag++;
/* for stress-testing: next_version_tag &= 0xFF; */
if (type->tp_version_tag == 0) {
// Wrap-around or just starting Python - clear the whole cache
type_cache_clear(cache, 1);
return 0;
}
bases = type->tp_bases;
n = PyTuple_GET_SIZE(bases);
for (i = 0; i < n; i++) {
PyObject *b = PyTuple_GET_ITEM(bases, i);
assert(PyType_Check(b));
if (!assign_version_tag(cache, (PyTypeObject *)b))
return 0;
}
type->tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG;
return 1;
}
static PyMemberDef type_members[] = {
{"__basicsize__", T_PYSSIZET, offsetof(PyTypeObject,tp_basicsize),READONLY},
{"__itemsize__", T_PYSSIZET, offsetof(PyTypeObject, tp_itemsize), READONLY},
{"__flags__", T_ULONG, offsetof(PyTypeObject, tp_flags), READONLY},
{"__weakrefoffset__", T_PYSSIZET,
offsetof(PyTypeObject, tp_weaklistoffset), READONLY},
{"__base__", T_OBJECT, offsetof(PyTypeObject, tp_base), READONLY},
{"__dictoffset__", T_PYSSIZET,
offsetof(PyTypeObject, tp_dictoffset), READONLY},
{"__mro__", T_OBJECT, offsetof(PyTypeObject, tp_mro), READONLY},
{0}
};
static int
check_set_special_type_attr(PyTypeObject *type, PyObject *value, const char *name)
{
if (_PyType_HasFeature(type, Py_TPFLAGS_IMMUTABLETYPE)) {
PyErr_Format(PyExc_TypeError,
"cannot set '%s' attribute of immutable type '%s'",
name, type->tp_name);
return 0;
}
if (!value) {
PyErr_Format(PyExc_TypeError,
"cannot delete '%s' attribute of immutable type '%s'",
name, type->tp_name);
return 0;
}
if (PySys_Audit("object.__setattr__", "OsO",
type, name, value) < 0) {
return 0;
}
return 1;
}
const char *
_PyType_Name(PyTypeObject *type)
{
assert(type->tp_name != NULL);
const char *s = strrchr(type->tp_name, '.');
if (s == NULL) {
s = type->tp_name;
}
else {
s++;
}
return s;
}
static PyObject *
type_name(PyTypeObject *type, void *context)
{
if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) {
PyHeapTypeObject* et = (PyHeapTypeObject*)type;
Py_INCREF(et->ht_name);
return et->ht_name;
}
else {
return PyUnicode_FromString(_PyType_Name(type));
}
}
static PyObject *
type_qualname(PyTypeObject *type, void *context)
{
if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) {
PyHeapTypeObject* et = (PyHeapTypeObject*)type;
Py_INCREF(et->ht_qualname);
return et->ht_qualname;
}
else {
return PyUnicode_FromString(_PyType_Name(type));
}
}
static int
type_set_name(PyTypeObject *type, PyObject *value, void *context)
{
const char *tp_name;
Py_ssize_t name_size;
if (!check_set_special_type_attr(type, value, "__name__"))
return -1;
if (!PyUnicode_Check(value)) {
PyErr_Format(PyExc_TypeError,
"can only assign string to %s.__name__, not '%s'",
type->tp_name, Py_TYPE(value)->tp_name);
return -1;
}
tp_name = PyUnicode_AsUTF8AndSize(value, &name_size);
if (tp_name == NULL)
return -1;
if (strlen(tp_name) != (size_t)name_size) {
PyErr_SetString(PyExc_ValueError,
"type name must not contain null characters");
return -1;
}
type->tp_name = tp_name;
Py_INCREF(value);
Py_SETREF(((PyHeapTypeObject*)type)->ht_name, value);
return 0;
}
static int
type_set_qualname(PyTypeObject *type, PyObject *value, void *context)
{
PyHeapTypeObject* et;
if (!check_set_special_type_attr(type, value, "__qualname__"))
return -1;
if (!PyUnicode_Check(value)) {
PyErr_Format(PyExc_TypeError,
"can only assign string to %s.__qualname__, not '%s'",
type->tp_name, Py_TYPE(value)->tp_name);
return -1;
}
et = (PyHeapTypeObject*)type;
Py_INCREF(value);
Py_SETREF(et->ht_qualname, value);
return 0;
}
static PyObject *
type_module(PyTypeObject *type, void *context)
{
PyObject *mod;
if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) {
mod = _PyDict_GetItemIdWithError(type->tp_dict, &PyId___module__);
if (mod == NULL) {
if (!PyErr_Occurred()) {
PyErr_Format(PyExc_AttributeError, "__module__");
}
return NULL;
}
Py_INCREF(mod);
}
else {
const char *s = strrchr(type->tp_name, '.');
if (s != NULL) {
mod = PyUnicode_FromStringAndSize(
type->tp_name, (Py_ssize_t)(s - type->tp_name));
if (mod != NULL)
PyUnicode_InternInPlace(&mod);
}
else {
mod = _PyUnicode_FromId(&PyId_builtins);
Py_XINCREF(mod);
}
}
return mod;
}
static int
type_set_module(PyTypeObject *type, PyObject *value, void *context)
{
if (!check_set_special_type_attr(type, value, "__module__"))
return -1;
PyType_Modified(type);
return _PyDict_SetItemId(type->tp_dict, &PyId___module__, value);
}
static PyObject *
type_abstractmethods(PyTypeObject *type, void *context)
{
PyObject *mod = NULL;
/* type itself has an __abstractmethods__ descriptor (this). Don't return
that. */
if (type != &PyType_Type)
mod = _PyDict_GetItemIdWithError(type->tp_dict, &PyId___abstractmethods__);
if (!mod) {
if (!PyErr_Occurred()) {
PyObject *message = _PyUnicode_FromId(&PyId___abstractmethods__);
if (message)
PyErr_SetObject(PyExc_AttributeError, message);
}
return NULL;
}
Py_INCREF(mod);
return mod;
}
static int
type_set_abstractmethods(PyTypeObject *type, PyObject *value, void *context)
{
/* __abstractmethods__ should only be set once on a type, in
abc.ABCMeta.__new__, so this function doesn't do anything
special to update subclasses.
*/
int abstract, res;
if (value != NULL) {
abstract = PyObject_IsTrue(value);
if (abstract < 0)
return -1;
res = _PyDict_SetItemId(type->tp_dict, &PyId___abstractmethods__, value);
}
else {
abstract = 0;
res = _PyDict_DelItemId(type->tp_dict, &PyId___abstractmethods__);
if (res && PyErr_ExceptionMatches(PyExc_KeyError)) {
PyObject *message = _PyUnicode_FromId(&PyId___abstractmethods__);
if (message)
PyErr_SetObject(PyExc_AttributeError, message);
return -1;
}
}
if (res == 0) {
PyType_Modified(type);
if (abstract)
type->tp_flags |= Py_TPFLAGS_IS_ABSTRACT;
else
type->tp_flags &= ~Py_TPFLAGS_IS_ABSTRACT;
}
return res;
}
static PyObject *
type_get_bases(PyTypeObject *type, void *context)
{
Py_INCREF(type->tp_bases);
return type->tp_bases;
}
static PyTypeObject *best_base(PyObject *);
static int mro_internal(PyTypeObject *, PyObject **);
static int type_is_subtype_base_chain(PyTypeObject *, PyTypeObject *);
static int compatible_for_assignment(PyTypeObject *, PyTypeObject *, const char *);
static int add_subclass(PyTypeObject*, PyTypeObject*);
static int add_all_subclasses(PyTypeObject *type, PyObject *bases);
static void remove_subclass(PyTypeObject *, PyTypeObject *);
static void remove_all_subclasses(PyTypeObject *type, PyObject *bases);
static void update_all_slots(PyTypeObject *);
typedef int (*update_callback)(PyTypeObject *, void *);
static int update_subclasses(PyTypeObject *type, PyObject *name,
update_callback callback, void *data);
static int recurse_down_subclasses(PyTypeObject *type, PyObject *name,
update_callback callback, void *data);
static int
mro_hierarchy(PyTypeObject *type, PyObject *temp)
{
int res;
PyObject *new_mro, *old_mro;
PyObject *tuple;
PyObject *subclasses;
Py_ssize_t i, n;
res = mro_internal(type, &old_mro);
if (res <= 0)
/* error / reentrance */
return res;
new_mro = type->tp_mro;
if (old_mro != NULL)
tuple = PyTuple_Pack(3, type, new_mro, old_mro);
else
tuple = PyTuple_Pack(2, type, new_mro);
if (tuple != NULL)
res = PyList_Append(temp, tuple);
else
res = -1;
Py_XDECREF(tuple);
if (res < 0) {
type->tp_mro = old_mro;
Py_DECREF(new_mro);
return -1;
}
Py_XDECREF(old_mro);
/* Obtain a copy of subclasses list to iterate over.
Otherwise type->tp_subclasses might be altered
in the middle of the loop, for example, through a custom mro(),
by invoking type_set_bases on some subclass of the type
which in turn calls remove_subclass/add_subclass on this type.
Finally, this makes things simple avoiding the need to deal
with dictionary iterators and weak references.
*/
subclasses = type___subclasses___impl(type);
if (subclasses == NULL)
return -1;
n = PyList_GET_SIZE(subclasses);
for (i = 0; i < n; i++) {
PyTypeObject *subclass;
subclass = (PyTypeObject *)PyList_GET_ITEM(subclasses, i);
res = mro_hierarchy(subclass, temp);
if (res < 0)
break;
}
Py_DECREF(subclasses);
return res;
}
static int
type_set_bases(PyTypeObject *type, PyObject *new_bases, void *context)
{
int res = 0;
PyObject *temp;
PyObject *old_bases;
PyTypeObject *new_base, *old_base;
Py_ssize_t i;
if (!check_set_special_type_attr(type, new_bases, "__bases__"))
return -1;
if (!PyTuple_Check(new_bases)) {
PyErr_Format(PyExc_TypeError,
"can only assign tuple to %s.__bases__, not %s",
type->tp_name, Py_TYPE(new_bases)->tp_name);
return -1;
}
if (PyTuple_GET_SIZE(new_bases) == 0) {
PyErr_Format(PyExc_TypeError,
"can only assign non-empty tuple to %s.__bases__, not ()",
type->tp_name);
return -1;
}
for (i = 0; i < PyTuple_GET_SIZE(new_bases); i++) {
PyObject *ob;
PyTypeObject *base;
ob = PyTuple_GET_ITEM(new_bases, i);
if (!PyType_Check(ob)) {
PyErr_Format(PyExc_TypeError,
"%s.__bases__ must be tuple of classes, not '%s'",
type->tp_name, Py_TYPE(ob)->tp_name);
return -1;
}
base = (PyTypeObject*)ob;
if (PyType_IsSubtype(base, type) ||
/* In case of reentering here again through a custom mro()
the above check is not enough since it relies on
base->tp_mro which would gonna be updated inside
mro_internal only upon returning from the mro().
However, base->tp_base has already been assigned (see
below), which in turn may cause an inheritance cycle
through tp_base chain. And this is definitely
not what you want to ever happen. */
(base->tp_mro != NULL && type_is_subtype_base_chain(base, type))) {
PyErr_SetString(PyExc_TypeError,
"a __bases__ item causes an inheritance cycle");
return -1;
}
}
new_base = best_base(new_bases);
if (new_base == NULL)
return -1;
if (!compatible_for_assignment(type->tp_base, new_base, "__bases__"))
return -1;
Py_INCREF(new_bases);
Py_INCREF(new_base);
old_bases = type->tp_bases;
old_base = type->tp_base;
type->tp_bases = new_bases;
type->tp_base = new_base;
temp = PyList_New(0);
if (temp == NULL)
goto bail;
if (mro_hierarchy(type, temp) < 0)
goto undo;
Py_DECREF(temp);
/* Take no action in case if type->tp_bases has been replaced
through reentrance. */
if (type->tp_bases == new_bases) {
/* any base that was in __bases__ but now isn't, we
need to remove |type| from its tp_subclasses.
conversely, any class now in __bases__ that wasn't
needs to have |type| added to its subclasses. */
/* for now, sod that: just remove from all old_bases,
add to all new_bases */
remove_all_subclasses(type, old_bases);
res = add_all_subclasses(type, new_bases);
update_all_slots(type);
}
Py_DECREF(old_bases);
Py_DECREF(old_base);
assert(_PyType_CheckConsistency(type));
return res;
undo:
for (i = PyList_GET_SIZE(temp) - 1; i >= 0; i--) {
PyTypeObject *cls;
PyObject *new_mro, *old_mro = NULL;
PyArg_UnpackTuple(PyList_GET_ITEM(temp, i),
"", 2, 3, &cls, &new_mro, &old_mro);
/* Do not rollback if cls has a newer version of MRO. */
if (cls->tp_mro == new_mro) {
Py_XINCREF(old_mro);
cls->tp_mro = old_mro;
Py_DECREF(new_mro);
}
}
Py_DECREF(temp);
bail:
if (type->tp_bases == new_bases) {
assert(type->tp_base == new_base);
type->tp_bases = old_bases;
type->tp_base = old_base;
Py_DECREF(new_bases);
Py_DECREF(new_base);
}
else {
Py_DECREF(old_bases);
Py_DECREF(old_base);
}
assert(_PyType_CheckConsistency(type));
return -1;
}
static PyObject *
type_dict(PyTypeObject *type, void *context)
{
if (type->tp_dict == NULL) {
Py_RETURN_NONE;
}
return PyDictProxy_New(type->tp_dict);
}
static PyObject *
type_get_doc(PyTypeObject *type, void *context)
{
PyObject *result;
if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE) && type->tp_doc != NULL) {
return _PyType_GetDocFromInternalDoc(type->tp_name, type->tp_doc);
}
result = _PyDict_GetItemIdWithError(type->tp_dict, &PyId___doc__);
if (result == NULL) {
if (!PyErr_Occurred()) {
result = Py_None;
Py_INCREF(result);
}
}
else if (Py_TYPE(result)->tp_descr_get) {
result = Py_TYPE(result)->tp_descr_get(result, NULL,
(PyObject *)type);
}
else {
Py_INCREF(result);
}
return result;
}
static PyObject *
type_get_text_signature(PyTypeObject *type, void *context)
{
return _PyType_GetTextSignatureFromInternalDoc(type->tp_name, type->tp_doc);
}
static int
type_set_doc(PyTypeObject *type, PyObject *value, void *context)
{
if (!check_set_special_type_attr(type, value, "__doc__"))
return -1;
PyType_Modified(type);
return _PyDict_SetItemId(type->tp_dict, &PyId___doc__, value);
}
static PyObject *
type_get_annotations(PyTypeObject *type, void *context)
{
if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
PyErr_Format(PyExc_AttributeError, "type object '%s' has no attribute '__annotations__'", type->tp_name);
return NULL;
}
PyObject *annotations;
/* there's no _PyDict_GetItemId without WithError, so let's LBYL. */
if (_PyDict_ContainsId(type->tp_dict, &PyId___annotations__)) {
annotations = _PyDict_GetItemIdWithError(type->tp_dict, &PyId___annotations__);
/*
** _PyDict_GetItemIdWithError could still fail,
** for instance with a well-timed Ctrl-C or a MemoryError.
** so let's be totally safe.
*/
if (annotations) {
if (Py_TYPE(annotations)->tp_descr_get) {
annotations = Py_TYPE(annotations)->tp_descr_get(annotations, NULL,
(PyObject *)type);
} else {
Py_INCREF(annotations);
}
}
} else {
annotations = PyDict_New();
if (annotations) {
int result = _PyDict_SetItemId(type->tp_dict, &PyId___annotations__, annotations);
if (result) {
Py_CLEAR(annotations);
} else {
PyType_Modified(type);
}
}
}
return annotations;
}
static int
type_set_annotations(PyTypeObject *type, PyObject *value, void *context)
{
if (_PyType_HasFeature(type, Py_TPFLAGS_IMMUTABLETYPE)) {
PyErr_Format(PyExc_TypeError,
"cannot set '__annotations__' attribute of immutable type '%s'",
type->tp_name);
return -1;
}
int result;
if (value != NULL) {
/* set */
result = _PyDict_SetItemId(type->tp_dict, &PyId___annotations__, value);
} else {
/* delete */
if (!_PyDict_ContainsId(type->tp_dict, &PyId___annotations__)) {
PyErr_Format(PyExc_AttributeError, "__annotations__");
return -1;
}
result = _PyDict_DelItemId(type->tp_dict, &PyId___annotations__);
}
if (result == 0) {
PyType_Modified(type);
}
return result;
}
/*[clinic input]
type.__instancecheck__ -> bool
instance: object
/
Check if an object is an instance.
[clinic start generated code]*/
static int
type___instancecheck___impl(PyTypeObject *self, PyObject *instance)
/*[clinic end generated code: output=08b6bf5f591c3618 input=cdbfeaee82c01a0f]*/
{
return _PyObject_RealIsInstance(instance, (PyObject *)self);
}
/*[clinic input]
type.__subclasscheck__ -> bool
subclass: object
/
Check if a class is a subclass.
[clinic start generated code]*/
static int
type___subclasscheck___impl(PyTypeObject *self, PyObject *subclass)
/*[clinic end generated code: output=97a4e51694500941 input=071b2ca9e03355f4]*/
{
return _PyObject_RealIsSubclass(subclass, (PyObject *)self);
}
static PyGetSetDef type_getsets[] = {
{"__name__", (getter)type_name, (setter)type_set_name, NULL},
{"__qualname__", (getter)type_qualname, (setter)type_set_qualname, NULL},
{"__bases__", (getter)type_get_bases, (setter)type_set_bases, NULL},
{"__module__", (getter)type_module, (setter)type_set_module, NULL},
{"__abstractmethods__", (getter)type_abstractmethods,
(setter)type_set_abstractmethods, NULL},
{"__dict__", (getter)type_dict, NULL, NULL},
{"__doc__", (getter)type_get_doc, (setter)type_set_doc, NULL},
{"__text_signature__", (getter)type_get_text_signature, NULL, NULL},
{"__annotations__", (getter)type_get_annotations, (setter)type_set_annotations, NULL},
{0}
};
static PyObject *
type_repr(PyTypeObject *type)
{
PyObject *mod, *name, *rtn;
mod = type_module(type, NULL);
if (mod == NULL)
PyErr_Clear();
else if (!PyUnicode_Check(mod)) {
Py_DECREF(mod);
mod = NULL;
}
name = type_qualname(type, NULL);
if (name == NULL) {
Py_XDECREF(mod);
return NULL;
}
if (mod != NULL && !_PyUnicode_EqualToASCIIId(mod, &PyId_builtins))
rtn = PyUnicode_FromFormat("<class '%U.%U'>", mod, name);
else
rtn = PyUnicode_FromFormat("<class '%s'>", type->tp_name);
Py_XDECREF(mod);
Py_DECREF(name);
return rtn;
}
static PyObject *
type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *obj;
PyThreadState *tstate = _PyThreadState_GET();
#ifdef Py_DEBUG
/* type_call() must not be called with an exception set,
because it can clear it (directly or indirectly) and so the
caller loses its exception */
assert(!_PyErr_Occurred(tstate));
#endif
/* Special case: type(x) should return Py_TYPE(x) */
/* We only want type itself to accept the one-argument form (#27157) */
if (type == &PyType_Type) {
assert(args != NULL && PyTuple_Check(args));
assert(kwds == NULL || PyDict_Check(kwds));
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
if (nargs == 1 && (kwds == NULL || !PyDict_GET_SIZE(kwds))) {
obj = (PyObject *) Py_TYPE(PyTuple_GET_ITEM(args, 0));
Py_INCREF(obj);
return obj;
}
/* SF bug 475327 -- if that didn't trigger, we need 3
arguments. But PyArg_ParseTuple in type_new may give
a msg saying type() needs exactly 3. */
if (nargs != 3) {
PyErr_SetString(PyExc_TypeError,
"type() takes 1 or 3 arguments");
return NULL;
}
}
if (type->tp_new == NULL) {
_PyErr_Format(tstate, PyExc_TypeError,
"cannot create '%s' instances", type->tp_name);
return NULL;
}
obj = type->tp_new(type, args, kwds);
obj = _Py_CheckFunctionResult(tstate, (PyObject*)type, obj, NULL);
if (obj == NULL)
return NULL;
/* If the returned object is not an instance of type,
it won't be initialized. */
if (!PyType_IsSubtype(Py_TYPE(obj), type))
return obj;
type = Py_TYPE(obj);
if (type->tp_init != NULL) {
int res = type->tp_init(obj, args, kwds);
if (res < 0) {
assert(_PyErr_Occurred(tstate));
Py_DECREF(obj);
obj = NULL;
}
else {
assert(!_PyErr_Occurred(tstate));
}
}
return obj;
}
PyObject *
PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)
{
PyObject *obj;
const size_t size = _PyObject_VAR_SIZE(type, nitems+1);
/* note that we need to add one, for the sentinel */
if (_PyType_IS_GC(type)) {
obj = _PyObject_GC_Malloc(size);
}
else {
obj = (PyObject *)PyObject_Malloc(size);
}
if (obj == NULL) {
return PyErr_NoMemory();
}
memset(obj, '\0', size);
if (type->tp_itemsize == 0) {
_PyObject_Init(obj, type);
}
else {
_PyObject_InitVar((PyVarObject *)obj, type, nitems);
}
if (_PyType_IS_GC(type)) {
_PyObject_GC_TRACK(obj);
}
return obj;
}
PyObject *
PyType_GenericNew(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
return type->tp_alloc(type, 0);
}
/* Helpers for subtyping */
static int
traverse_slots(PyTypeObject *type, PyObject *self, visitproc visit, void *arg)
{
Py_ssize_t i, n;
PyMemberDef *mp;
n = Py_SIZE(type);
mp = PyHeapType_GET_MEMBERS((PyHeapTypeObject *)type);
for (i = 0; i < n; i++, mp++) {
if (mp->type == T_OBJECT_EX) {
char *addr = (char *)self + mp->offset;
PyObject *obj = *(PyObject **)addr;
if (obj != NULL) {
int err = visit(obj, arg);
if (err)
return err;
}
}
}
return 0;
}
static int
subtype_traverse(PyObject *self, visitproc visit, void *arg)
{
PyTypeObject *type, *base;
traverseproc basetraverse;
/* Find the nearest base with a different tp_traverse,
and traverse slots while we're at it */
type = Py_TYPE(self);
base = type;
while ((basetraverse = base->tp_traverse) == subtype_traverse) {
if (Py_SIZE(base)) {
int err = traverse_slots(base, self, visit, arg);
if (err)
return err;
}
base = base->tp_base;
assert(base);
}
if (type->tp_dictoffset != base->tp_dictoffset) {
PyObject **dictptr = _PyObject_GetDictPtr(self);
if (dictptr && *dictptr)
Py_VISIT(*dictptr);
}
if (type->tp_flags & Py_TPFLAGS_HEAPTYPE
&& (!basetraverse || !(base->tp_flags & Py_TPFLAGS_HEAPTYPE))) {
/* For a heaptype, the instances count as references
to the type. Traverse the type so the collector
can find cycles involving this link.
Skip this visit if basetraverse belongs to a heap type: in that
case, basetraverse will visit the type when we call it later.
*/
Py_VISIT(type);
}
if (basetraverse)
return basetraverse(self, visit, arg);
return 0;
}
static void
clear_slots(PyTypeObject *type, PyObject *self)
{
Py_ssize_t i, n;
PyMemberDef *mp;
n = Py_SIZE(type);
mp = PyHeapType_GET_MEMBERS((PyHeapTypeObject *)type);
for (i = 0; i < n; i++, mp++) {
if (mp->type == T_OBJECT_EX && !(mp->flags & READONLY)) {
char *addr = (char *)self + mp->offset;
PyObject *obj = *(PyObject **)addr;
if (obj != NULL) {
*(PyObject **)addr = NULL;
Py_DECREF(obj);
}
}
}
}
static int
subtype_clear(PyObject *self)
{
PyTypeObject *type, *base;
inquiry baseclear;
/* Find the nearest base with a different tp_clear
and clear slots while we're at it */
type = Py_TYPE(self);
base = type;
while ((baseclear = base->tp_clear) == subtype_clear) {
if (Py_SIZE(base))
clear_slots(base, self);
base = base->tp_base;
assert(base);
}
/* Clear the instance dict (if any), to break cycles involving only
__dict__ slots (as in the case 'self.__dict__ is self'). */
if (type->tp_dictoffset != base->tp_dictoffset) {
PyObject **dictptr = _PyObject_GetDictPtr(self);
if (dictptr && *dictptr)
Py_CLEAR(*dictptr);
}
if (baseclear)
return baseclear(self);
return 0;
}
static void
subtype_dealloc(PyObject *self)
{
PyTypeObject *type, *base;
destructor basedealloc;
int has_finalizer;
/* Extract the type; we expect it to be a heap type */
type = Py_TYPE(self);
_PyObject_ASSERT((PyObject *)type, type->tp_flags & Py_TPFLAGS_HEAPTYPE);
/* Test whether the type has GC exactly once */
if (!_PyType_IS_GC(type)) {
/* A non GC dynamic type allows certain simplifications:
there's no need to call clear_slots(), or DECREF the dict,
or clear weakrefs. */
/* Maybe call finalizer; exit early if resurrected */
if (type->tp_finalize) {
if (PyObject_CallFinalizerFromDealloc(self) < 0)
return;
}
if (type->tp_del) {
type->tp_del(self);
if (Py_REFCNT(self) > 0) {
return;
}
}
/* Find the nearest base with a different tp_dealloc */
base = type;
while ((basedealloc = base->tp_dealloc) == subtype_dealloc) {
base = base->tp_base;
assert(base);
}
/* Extract the type again; tp_del may have changed it */
type = Py_TYPE(self);
// Don't read type memory after calling basedealloc() since basedealloc()
// can deallocate the type and free its memory.
int type_needs_decref = (type->tp_flags & Py_TPFLAGS_HEAPTYPE
&& !(base->tp_flags & Py_TPFLAGS_HEAPTYPE));
/* Call the base tp_dealloc() */
assert(basedealloc);
basedealloc(self);
/* Can't reference self beyond this point. It's possible tp_del switched
our type from a HEAPTYPE to a non-HEAPTYPE, so be careful about
reference counting. Only decref if the base type is not already a heap
allocated type. Otherwise, basedealloc should have decref'd it already */
if (type_needs_decref) {
Py_DECREF(type);
}
/* Done */
return;
}
/* We get here only if the type has GC */
/* UnTrack and re-Track around the trashcan macro, alas */
/* See explanation at end of function for full disclosure */
PyObject_GC_UnTrack(self);
Py_TRASHCAN_BEGIN(self, subtype_dealloc);
/* Find the nearest base with a different tp_dealloc */
base = type;
while ((/*basedealloc =*/ base->tp_dealloc) == subtype_dealloc) {
base = base->tp_base;
assert(base);
}
has_finalizer = type->tp_finalize || type->tp_del;
if (type->tp_finalize) {
_PyObject_GC_TRACK(self);
if (PyObject_CallFinalizerFromDealloc(self) < 0) {
/* Resurrected */
goto endlabel;
}
_PyObject_GC_UNTRACK(self);
}
/*
If we added a weaklist, we clear it. Do this *before* calling tp_del,
clearing slots, or clearing the instance dict.
GC tracking must be off at this point. weakref callbacks (if any, and
whether directly here or indirectly in something we call) may trigger GC,
and if self is tracked at that point, it will look like trash to GC and GC
will try to delete self again.
*/
if (type->tp_weaklistoffset && !base->tp_weaklistoffset)
PyObject_ClearWeakRefs(self);
if (type->tp_del) {
_PyObject_GC_TRACK(self);
type->tp_del(self);
if (Py_REFCNT(self) > 0) {
/* Resurrected */
goto endlabel;
}
_PyObject_GC_UNTRACK(self);
}
if (has_finalizer) {
/* New weakrefs could be created during the finalizer call.
If this occurs, clear them out without calling their
finalizers since they might rely on part of the object
being finalized that has already been destroyed. */
if (type->tp_weaklistoffset && !base->tp_weaklistoffset) {
/* Modeled after GET_WEAKREFS_LISTPTR() */
PyWeakReference **list = (PyWeakReference **) \
_PyObject_GET_WEAKREFS_LISTPTR(self);
while (*list)
_PyWeakref_ClearRef(*list);
}
}
/* Clear slots up to the nearest base with a different tp_dealloc */
base = type;
while ((basedealloc = base->tp_dealloc) == subtype_dealloc) {
if (Py_SIZE(base))
clear_slots(base, self);
base = base->tp_base;
assert(base);
}
/* If we added a dict, DECREF it */
if (type->tp_dictoffset && !base->tp_dictoffset) {
PyObject **dictptr = _PyObject_GetDictPtr(self);
if (dictptr != NULL) {
PyObject *dict = *dictptr;
if (dict != NULL) {
Py_DECREF(dict);
*dictptr = NULL;
}
}
}
/* Extract the type again; tp_del may have changed it */
type = Py_TYPE(self);
/* Call the base tp_dealloc(); first retrack self if
* basedealloc knows about gc.
*/
if (_PyType_IS_GC(base)) {
_PyObject_GC_TRACK(self);
}
// Don't read type memory after calling basedealloc() since basedealloc()
// can deallocate the type and free its memory.
int type_needs_decref = (type->tp_flags & Py_TPFLAGS_HEAPTYPE
&& !(base->tp_flags & Py_TPFLAGS_HEAPTYPE));
assert(basedealloc);
basedealloc(self);
/* Can't reference self beyond this point. It's possible tp_del switched
our type from a HEAPTYPE to a non-HEAPTYPE, so be careful about
reference counting. Only decref if the base type is not already a heap
allocated type. Otherwise, basedealloc should have decref'd it already */
if (type_needs_decref) {
Py_DECREF(type);
}
endlabel:
Py_TRASHCAN_END
/* Explanation of the weirdness around the trashcan macros:
Q. What do the trashcan macros do?
A. Read the comment titled "Trashcan mechanism" in object.h.
For one, this explains why there must be a call to GC-untrack
before the trashcan begin macro. Without understanding the
trashcan code, the answers to the following questions don't make
sense.
Q. Why do we GC-untrack before the trashcan and then immediately
GC-track again afterward?
A. In the case that the base class is GC-aware, the base class
probably GC-untracks the object. If it does that using the
UNTRACK macro, this will crash when the object is already
untracked. Because we don't know what the base class does, the
only safe thing is to make sure the object is tracked when we
call the base class dealloc. But... The trashcan begin macro
requires that the object is *untracked* before it is called. So
the dance becomes:
GC untrack
trashcan begin
GC track
Q. Why did the last question say "immediately GC-track again"?
It's nowhere near immediately.
A. Because the code *used* to re-track immediately. Bad Idea.
self has a refcount of 0, and if gc ever gets its hands on it
(which can happen if any weakref callback gets invoked), it
looks like trash to gc too, and gc also tries to delete self
then. But we're already deleting self. Double deallocation is
a subtle disaster.
*/
}
static PyTypeObject *solid_base(PyTypeObject *type);
/* type test with subclassing support */
static int
type_is_subtype_base_chain(PyTypeObject *a, PyTypeObject *b)
{
do {
if (a == b)
return 1;
a = a->tp_base;
} while (a != NULL);
return (b == &PyBaseObject_Type);
}
int
PyType_IsSubtype(PyTypeObject *a, PyTypeObject *b)
{
PyObject *mro;
mro = a->tp_mro;
if (mro != NULL) {
/* Deal with multiple inheritance without recursion
by walking the MRO tuple */
Py_ssize_t i, n;
assert(PyTuple_Check(mro));
n = PyTuple_GET_SIZE(mro);
for (i = 0; i < n; i++) {
if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b)
return 1;
}
return 0;
}
else
/* a is not completely initialized yet; follow tp_base */
return type_is_subtype_base_chain(a, b);
}
/* Routines to do a method lookup in the type without looking in the
instance dictionary (so we can't use PyObject_GetAttr) but still
binding it to the instance.
Variants:
- _PyObject_LookupSpecial() returns NULL without raising an exception
when the _PyType_Lookup() call fails;
- lookup_maybe_method() and lookup_method() are internal routines similar
to _PyObject_LookupSpecial(), but can return unbound PyFunction
to avoid temporary method object. Pass self as first argument when
unbound == 1.
*/
PyObject *
_PyObject_LookupSpecial(PyObject *self, _Py_Identifier *attrid)
{
PyObject *res;
res = _PyType_LookupId(Py_TYPE(self), attrid);
if (res != NULL) {
descrgetfunc f;
if ((f = Py_TYPE(res)->tp_descr_get) == NULL)
Py_INCREF(res);
else
res = f(res, self, (PyObject *)(Py_TYPE(self)));
}
return res;
}
static PyObject *
lookup_maybe_method(PyObject *self, _Py_Identifier *attrid, int *unbound)
{
PyObject *res = _PyType_LookupId(Py_TYPE(self), attrid);
if (res == NULL) {
return NULL;
}
if (_PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR)) {
/* Avoid temporary PyMethodObject */
*unbound = 1;
Py_INCREF(res);
}
else {
*unbound = 0;
descrgetfunc f = Py_TYPE(res)->tp_descr_get;
if (f == NULL) {
Py_INCREF(res);
}
else {
res = f(res, self, (PyObject *)(Py_TYPE(self)));
}
}
return res;
}
static PyObject *
lookup_method(PyObject *self, _Py_Identifier *attrid, int *unbound)
{
PyObject *res = lookup_maybe_method(self, attrid, unbound);
if (res == NULL && !PyErr_Occurred()) {
PyErr_SetObject(PyExc_AttributeError, _PyUnicode_FromId(attrid));
}
return res;
}
static inline PyObject*
vectorcall_unbound(PyThreadState *tstate, int unbound, PyObject *func,
PyObject *const *args, Py_ssize_t nargs)
{
size_t nargsf = nargs;
if (!unbound) {
/* Skip self argument, freeing up args[0] to use for
* PY_VECTORCALL_ARGUMENTS_OFFSET */
args++;
nargsf = nargsf - 1 + PY_VECTORCALL_ARGUMENTS_OFFSET;
}
return _PyObject_VectorcallTstate(tstate, func, args, nargsf, NULL);
}
static PyObject*
call_unbound_noarg(int unbound, PyObject *func, PyObject *self)
{
if (unbound) {
return PyObject_CallOneArg(func, self);
}
else {
return _PyObject_CallNoArg(func);
}
}
/* A variation of PyObject_CallMethod* that uses lookup_method()
instead of PyObject_GetAttrString().
args is an argument vector of length nargs. The first element in this
vector is the special object "self" which is used for the method lookup */
static PyObject *
vectorcall_method(_Py_Identifier *name,
PyObject *const *args, Py_ssize_t nargs)
{
assert(nargs >= 1);
PyThreadState *tstate = _PyThreadState_GET();
int unbound;
PyObject *self = args[0];
PyObject *func = lookup_method(self, name, &unbound);
if (func == NULL) {
return NULL;
}
PyObject *retval = vectorcall_unbound(tstate, unbound, func, args, nargs);
Py_DECREF(func);
return retval;
}
/* Clone of vectorcall_method() that returns NotImplemented
* when the lookup fails. */
static PyObject *
vectorcall_maybe(PyThreadState *tstate, _Py_Identifier *name,
PyObject *const *args, Py_ssize_t nargs)
{
assert(nargs >= 1);
int unbound;
PyObject *self = args[0];
PyObject *func = lookup_maybe_method(self, name, &unbound);
if (func == NULL) {
if (!PyErr_Occurred())
Py_RETURN_NOTIMPLEMENTED;
return NULL;
}
PyObject *retval = vectorcall_unbound(tstate, unbound, func, args, nargs);
Py_DECREF(func);
return retval;
}
/*
Method resolution order algorithm C3 described in
"A Monotonic Superclass Linearization for Dylan",
by Kim Barrett, Bob Cassel, Paul Haahr,
David A. Moon, Keith Playford, and P. Tucker Withington.
(OOPSLA 1996)
Some notes about the rules implied by C3:
No duplicate bases.
It isn't legal to repeat a class in a list of base classes.
The next three properties are the 3 constraints in "C3".
Local precedence order.
If A precedes B in C's MRO, then A will precede B in the MRO of all
subclasses of C.
Monotonicity.
The MRO of a class must be an extension without reordering of the
MRO of each of its superclasses.
Extended Precedence Graph (EPG).
Linearization is consistent if there is a path in the EPG from
each class to all its successors in the linearization. See
the paper for definition of EPG.
*/
static int
tail_contains(PyObject *tuple, int whence, PyObject *o)
{
Py_ssize_t j, size;
size = PyTuple_GET_SIZE(tuple);
for (j = whence+1; j < size; j++) {
if (PyTuple_GET_ITEM(tuple, j) == o)
return 1;
}
return 0;
}
static PyObject *
class_name(PyObject *cls)
{
PyObject *name;
if (_PyObject_LookupAttrId(cls, &PyId___name__, &name) == 0) {
name = PyObject_Repr(cls);
}
return name;
}
static int
check_duplicates(PyObject *tuple)
{
Py_ssize_t i, j, n;
/* Let's use a quadratic time algorithm,
assuming that the bases tuples is short.
*/
n = PyTuple_GET_SIZE(tuple);
for (i = 0; i < n; i++) {
PyObject *o = PyTuple_GET_ITEM(tuple, i);
for (j = i + 1; j < n; j++) {
if (PyTuple_GET_ITEM(tuple, j) == o) {
o = class_name(o);
if (o != NULL) {
if (PyUnicode_Check(o)) {
PyErr_Format(PyExc_TypeError,
"duplicate base class %U", o);
}
else {
PyErr_SetString(PyExc_TypeError,
"duplicate base class");
}
Py_DECREF(o);
}
return -1;
}
}
}
return 0;
}
/* Raise a TypeError for an MRO order disagreement.
It's hard to produce a good error message. In the absence of better
insight into error reporting, report the classes that were candidates
to be put next into the MRO. There is some conflict between the
order in which they should be put in the MRO, but it's hard to
diagnose what constraint can't be satisfied.
*/
static void
set_mro_error(PyObject **to_merge, Py_ssize_t to_merge_size, int *remain)
{
Py_ssize_t i, n, off;
char buf[1000];
PyObject *k, *v;
PyObject *set = PyDict_New();
if (!set) return;
for (i = 0; i < to_merge_size; i++) {
PyObject *L = to_merge[i];
if (remain[i] < PyTuple_GET_SIZE(L)) {
PyObject *c = PyTuple_GET_ITEM(L, remain[i]);
if (PyDict_SetItem(set, c, Py_None) < 0) {
Py_DECREF(set);
return;
}
}
}
n = PyDict_GET_SIZE(set);
off = PyOS_snprintf(buf, sizeof(buf), "Cannot create a \
consistent method resolution\norder (MRO) for bases");
i = 0;
while (PyDict_Next(set, &i, &k, &v) && (size_t)off < sizeof(buf)) {
PyObject *name = class_name(k);
const char *name_str = NULL;
if (name != NULL) {
if (PyUnicode_Check(name)) {
name_str = PyUnicode_AsUTF8(name);
}
else {
name_str = "?";
}
}
if (name_str == NULL) {
Py_XDECREF(name);
Py_DECREF(set);
return;
}
off += PyOS_snprintf(buf + off, sizeof(buf) - off, " %s", name_str);
Py_XDECREF(name);
if (--n && (size_t)(off+1) < sizeof(buf)) {
buf[off++] = ',';
buf[off] = '\0';
}
}
PyErr_SetString(PyExc_TypeError, buf);
Py_DECREF(set);
}
static int
pmerge(PyObject *acc, PyObject **to_merge, Py_ssize_t to_merge_size)
{
int res = 0;
Py_ssize_t i, j, empty_cnt;
int *remain;
/* remain stores an index into each sublist of to_merge.
remain[i] is the index of the next base in to_merge[i]
that is not included in acc.
*/
remain = PyMem_New(int, to_merge_size);
if (remain == NULL) {
PyErr_NoMemory();
return -1;
}
for (i = 0; i < to_merge_size; i++)
remain[i] = 0;
again:
empty_cnt = 0;
for (i = 0; i < to_merge_size; i++) {
PyObject *candidate;
PyObject *cur_tuple = to_merge[i];
if (remain[i] >= PyTuple_GET_SIZE(cur_tuple)) {
empty_cnt++;
continue;
}
/* Choose next candidate for MRO.
The input sequences alone can determine the choice.
If not, choose the class which appears in the MRO
of the earliest direct superclass of the new class.
*/
candidate = PyTuple_GET_ITEM(cur_tuple, remain[i]);
for (j = 0; j < to_merge_size; j++) {
PyObject *j_lst = to_merge[j];
if (tail_contains(j_lst, remain[j], candidate))
goto skip; /* continue outer loop */
}
res = PyList_Append(acc, candidate);
if (res < 0)
goto out;
for (j = 0; j < to_merge_size; j++) {
PyObject *j_lst = to_merge[j];
if (remain[j] < PyTuple_GET_SIZE(j_lst) &&
PyTuple_GET_ITEM(j_lst, remain[j]) == candidate) {
remain[j]++;
}
}
goto again;
skip: ;
}
if (empty_cnt != to_merge_size) {
set_mro_error(to_merge, to_merge_size, remain);
res = -1;
}
out:
PyMem_Free(remain);
return res;
}
static PyObject *
mro_implementation(PyTypeObject *type)
{
PyObject *result;
PyObject *bases;
PyObject **to_merge;
Py_ssize_t i, n;
if (!_PyType_IsReady(type)) {
if (PyType_Ready(type) < 0)
return NULL;
}
bases = type->tp_bases;
assert(PyTuple_Check(bases));
n = PyTuple_GET_SIZE(bases);
for (i = 0; i < n; i++) {
PyTypeObject *base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
if (base->tp_mro == NULL) {
PyErr_Format(PyExc_TypeError,
"Cannot extend an incomplete type '%.100s'",
base->tp_name);
return NULL;
}
assert(PyTuple_Check(base->tp_mro));
}
if (n == 1) {
/* Fast path: if there is a single base, constructing the MRO
* is trivial.
*/
PyTypeObject *base = (PyTypeObject *)PyTuple_GET_ITEM(bases, 0);
Py_ssize_t k = PyTuple_GET_SIZE(base->tp_mro);
result = PyTuple_New(k + 1);
if (result == NULL) {
return NULL;
}
Py_INCREF(type);
PyTuple_SET_ITEM(result, 0, (PyObject *) type);
for (i = 0; i < k; i++) {
PyObject *cls = PyTuple_GET_ITEM(base->tp_mro, i);
Py_INCREF(cls);
PyTuple_SET_ITEM(result, i + 1, cls);
}
return result;
}
/* This is just a basic sanity check. */
if (check_duplicates(bases) < 0) {
return NULL;
}
/* Find a superclass linearization that honors the constraints
of the explicit tuples of bases and the constraints implied by
each base class.
to_merge is an array of tuples, where each tuple is a superclass
linearization implied by a base class. The last element of
to_merge is the declared tuple of bases.
*/
to_merge = PyMem_New(PyObject *, n + 1);
if (to_merge == NULL) {
PyErr_NoMemory();
return NULL;
}
for (i = 0; i < n; i++) {
PyTypeObject *base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
to_merge[i] = base->tp_mro;
}
to_merge[n] = bases;
result = PyList_New(1);
if (result == NULL) {
PyMem_Free(to_merge);
return NULL;
}
Py_INCREF(type);
PyList_SET_ITEM(result, 0, (PyObject *)type);
if (pmerge(result, to_merge, n + 1) < 0) {
Py_CLEAR(result);
}
PyMem_Free(to_merge);
return result;
}
/*[clinic input]
type.mro
Return a type's method resolution order.
[clinic start generated code]*/
static PyObject *
type_mro_impl(PyTypeObject *self)
/*[clinic end generated code: output=bffc4a39b5b57027 input=28414f4e156db28d]*/
{
PyObject *seq;
seq = mro_implementation(self);
if (seq != NULL && !PyList_Check(seq)) {
Py_SETREF(seq, PySequence_List(seq));
}
return seq;
}
static int
mro_check(PyTypeObject *type, PyObject *mro)
{
PyTypeObject *solid;
Py_ssize_t i, n;
solid = solid_base(type);
n = PyTuple_GET_SIZE(mro);
for (i = 0; i < n; i++) {
PyTypeObject *base;
PyObject *tmp;
tmp = PyTuple_GET_ITEM(mro, i);
if (!PyType_Check(tmp)) {
PyErr_Format(
PyExc_TypeError,
"mro() returned a non-class ('%.500s')",
Py_TYPE(tmp)->tp_name);
return -1;
}
base = (PyTypeObject*)tmp;
if (!PyType_IsSubtype(solid, solid_base(base))) {
PyErr_Format(
PyExc_TypeError,
"mro() returned base with unsuitable layout ('%.500s')",
base->tp_name);
return -1;
}
}
return 0;
}
/* Lookups an mcls.mro method, invokes it and checks the result (if needed,
in case of a custom mro() implementation).
Keep in mind that during execution of this function type->tp_mro
can be replaced due to possible reentrance (for example,
through type_set_bases):
- when looking up the mcls.mro attribute (it could be
a user-provided descriptor);
- from inside a custom mro() itself;
- through a finalizer of the return value of mro().
*/
static PyObject *
mro_invoke(PyTypeObject *type)
{
PyObject *mro_result;
PyObject *new_mro;
const int custom = !Py_IS_TYPE(type, &PyType_Type);
if (custom) {
int unbound;
PyObject *mro_meth = lookup_method((PyObject *)type, &PyId_mro,
&unbound);
if (mro_meth == NULL)
return NULL;
mro_result = call_unbound_noarg(unbound, mro_meth, (PyObject *)type);
Py_DECREF(mro_meth);
}
else {
mro_result = mro_implementation(type);
}
if (mro_result == NULL)
return NULL;
new_mro = PySequence_Tuple(mro_result);
Py_DECREF(mro_result);
if (new_mro == NULL) {
return NULL;
}
if (PyTuple_GET_SIZE(new_mro) == 0) {
Py_DECREF(new_mro);
PyErr_Format(PyExc_TypeError, "type MRO must not be empty");
return NULL;
}
if (custom && mro_check(type, new_mro) < 0) {
Py_DECREF(new_mro);
return NULL;
}
return new_mro;
}
/* Calculates and assigns a new MRO to type->tp_mro.
Return values and invariants:
- Returns 1 if a new MRO value has been set to type->tp_mro due to
this call of mro_internal (no tricky reentrancy and no errors).
In case if p_old_mro argument is not NULL, a previous value
of type->tp_mro is put there, and the ownership of this
reference is transferred to a caller.
Otherwise, the previous value (if any) is decref'ed.
- Returns 0 in case when type->tp_mro gets changed because of
reentering here through a custom mro() (see a comment to mro_invoke).
In this case, a refcount of an old type->tp_mro is adjusted
somewhere deeper in the call stack (by the innermost mro_internal
or its caller) and may become zero upon returning from here.
This also implies that the whole hierarchy of subclasses of the type
has seen the new value and updated their MRO accordingly.
- Returns -1 in case of an error.
*/
static int
mro_internal(PyTypeObject *type, PyObject **p_old_mro)
{
PyObject *new_mro, *old_mro;
int reent;
/* Keep a reference to be able to do a reentrancy check below.
Don't let old_mro be GC'ed and its address be reused for
another object, like (suddenly!) a new tp_mro. */
old_mro = type->tp_mro;
Py_XINCREF(old_mro);
new_mro = mro_invoke(type); /* might cause reentrance */
reent = (type->tp_mro != old_mro);
Py_XDECREF(old_mro);
if (new_mro == NULL) {
return -1;
}
if (reent) {
Py_DECREF(new_mro);
return 0;
}
type->tp_mro = new_mro;
type_mro_modified(type, type->tp_mro);
/* corner case: the super class might have been hidden
from the custom MRO */
type_mro_modified(type, type->tp_bases);
PyType_Modified(type);
if (p_old_mro != NULL)
*p_old_mro = old_mro; /* transfer the ownership */
else
Py_XDECREF(old_mro);
return 1;
}
/* Calculate the best base amongst multiple base classes.
This is the first one that's on the path to the "solid base". */
static PyTypeObject *
best_base(PyObject *bases)
{
Py_ssize_t i, n;
PyTypeObject *base, *winner, *candidate, *base_i;
PyObject *base_proto;
assert(PyTuple_Check(bases));
n = PyTuple_GET_SIZE(bases);
assert(n > 0);
base = NULL;
winner = NULL;
for (i = 0; i < n; i++) {
base_proto = PyTuple_GET_ITEM(bases, i);
if (!PyType_Check(base_proto)) {
PyErr_SetString(
PyExc_TypeError,
"bases must be types");
return NULL;
}
base_i = (PyTypeObject *)base_proto;
if (!_PyType_IsReady(base_i)) {
if (PyType_Ready(base_i) < 0)
return NULL;
}
if (!_PyType_HasFeature(base_i, Py_TPFLAGS_BASETYPE)) {
PyErr_Format(PyExc_TypeError,
"type '%.100s' is not an acceptable base type",
base_i->tp_name);
return NULL;
}
candidate = solid_base(base_i);
if (winner == NULL) {
winner = candidate;
base = base_i;
}
else if (PyType_IsSubtype(winner, candidate))
;
else if (PyType_IsSubtype(candidate, winner)) {
winner = candidate;
base = base_i;
}
else {
PyErr_SetString(
PyExc_TypeError,
"multiple bases have "
"instance lay-out conflict");
return NULL;
}
}
assert (base != NULL);
return base;
}
static int
extra_ivars(PyTypeObject *type, PyTypeObject *base)
{
size_t t_size = type->tp_basicsize;
size_t b_size = base->tp_basicsize;
assert(t_size >= b_size); /* Else type smaller than base! */
if (type->tp_itemsize || base->tp_itemsize) {
/* If itemsize is involved, stricter rules */
return t_size != b_size ||
type->tp_itemsize != base->tp_itemsize;
}
if (type->tp_weaklistoffset && base->tp_weaklistoffset == 0 &&
type->tp_weaklistoffset + sizeof(PyObject *) == t_size &&
type->tp_flags & Py_TPFLAGS_HEAPTYPE)
t_size -= sizeof(PyObject *);
if (type->tp_dictoffset && base->tp_dictoffset == 0 &&
type->tp_dictoffset + sizeof(PyObject *) == t_size &&
type->tp_flags & Py_TPFLAGS_HEAPTYPE)
t_size -= sizeof(PyObject *);
return t_size != b_size;
}
static PyTypeObject *
solid_base(PyTypeObject *type)
{
PyTypeObject *base;
if (type->tp_base)
base = solid_base(type->tp_base);
else
base = &PyBaseObject_Type;
if (extra_ivars(type, base))
return type;
else
return base;
}
static void object_dealloc(PyObject *);
static int object_init(PyObject *, PyObject *, PyObject *);
static int update_slot(PyTypeObject *, PyObject *);
static void fixup_slot_dispatchers(PyTypeObject *);
static int type_new_set_names(PyTypeObject *);
static int type_new_init_subclass(PyTypeObject *, PyObject *);
/*
* Helpers for __dict__ descriptor. We don't want to expose the dicts
* inherited from various builtin types. The builtin base usually provides
* its own __dict__ descriptor, so we use that when we can.
*/
static PyTypeObject *
get_builtin_base_with_dict(PyTypeObject *type)
{
while (type->tp_base != NULL) {
if (type->tp_dictoffset != 0 &&
!(type->tp_flags & Py_TPFLAGS_HEAPTYPE))
return type;
type = type->tp_base;
}
return NULL;
}
static PyObject *
get_dict_descriptor(PyTypeObject *type)
{
PyObject *descr;
descr = _PyType_LookupId(type, &PyId___dict__);
if (descr == NULL || !PyDescr_IsData(descr))
return NULL;
return descr;
}
static void
raise_dict_descr_error(PyObject *obj)
{
PyErr_Format(PyExc_TypeError,
"this __dict__ descriptor does not support "
"'%.200s' objects", Py_TYPE(obj)->tp_name);
}
static PyObject *
subtype_dict(PyObject *obj, void *context)
{
PyTypeObject *base;
base = get_builtin_base_with_dict(Py_TYPE(obj));
if (base != NULL) {
descrgetfunc func;
PyObject *descr = get_dict_descriptor(base);
if (descr == NULL) {
raise_dict_descr_error(obj);
return NULL;
}
func = Py_TYPE(descr)->tp_descr_get;
if (func == NULL) {
raise_dict_descr_error(obj);
return NULL;
}
return func(descr, obj, (PyObject *)(Py_TYPE(obj)));
}
return PyObject_GenericGetDict(obj, context);
}
static int
subtype_setdict(PyObject *obj, PyObject *value, void *context)
{
PyObject **dictptr;
PyTypeObject *base;
base = get_builtin_base_with_dict(Py_TYPE(obj));
if (base != NULL) {
descrsetfunc func;
PyObject *descr = get_dict_descriptor(base);
if (descr == NULL) {
raise_dict_descr_error(obj);
return -1;
}
func = Py_TYPE(descr)->tp_descr_set;
if (func == NULL) {
raise_dict_descr_error(obj);
return -1;
}
return func(descr, obj, value);
}
/* Almost like PyObject_GenericSetDict, but allow __dict__ to be deleted. */
dictptr = _PyObject_GetDictPtr(obj);
if (dictptr == NULL) {
PyErr_SetString(PyExc_AttributeError,
"This object has no __dict__");
return -1;
}
if (value != NULL && !PyDict_Check(value)) {
PyErr_Format(PyExc_TypeError,
"__dict__ must be set to a dictionary, "
"not a '%.200s'", Py_TYPE(value)->tp_name);
return -1;
}
Py_XINCREF(value);
Py_XSETREF(*dictptr, value);
return 0;
}
static PyObject *
subtype_getweakref(PyObject *obj, void *context)
{
PyObject **weaklistptr;
PyObject *result;
PyTypeObject *type = Py_TYPE(obj);
if (type->tp_weaklistoffset == 0) {
PyErr_SetString(PyExc_AttributeError,
"This object has no __weakref__");
return NULL;
}
_PyObject_ASSERT((PyObject *)type,
type->tp_weaklistoffset > 0);
_PyObject_ASSERT((PyObject *)type,
((type->tp_weaklistoffset + sizeof(PyObject *))
<= (size_t)(type->tp_basicsize)));
weaklistptr = (PyObject **)((char *)obj + type->tp_weaklistoffset);
if (*weaklistptr == NULL)
result = Py_None;
else
result = *weaklistptr;
Py_INCREF(result);
return result;
}
/* Three variants on the subtype_getsets list. */
static PyGetSetDef subtype_getsets_full[] = {
{"__dict__", subtype_dict, subtype_setdict,
PyDoc_STR("dictionary for instance variables (if defined)")},
{"__weakref__", subtype_getweakref, NULL,
PyDoc_STR("list of weak references to the object (if defined)")},
{0}
};
static PyGetSetDef subtype_getsets_dict_only[] = {
{"__dict__", subtype_dict, subtype_setdict,
PyDoc_STR("dictionary for instance variables (if defined)")},
{0}
};
static PyGetSetDef subtype_getsets_weakref_only[] = {
{"__weakref__", subtype_getweakref, NULL,
PyDoc_STR("list of weak references to the object (if defined)")},
{0}
};
static int
valid_identifier(PyObject *s)
{
if (!PyUnicode_Check(s)) {
PyErr_Format(PyExc_TypeError,
"__slots__ items must be strings, not '%.200s'",
Py_TYPE(s)->tp_name);
return 0;
}
if (!PyUnicode_IsIdentifier(s)) {
PyErr_SetString(PyExc_TypeError,
"__slots__ must be identifiers");
return 0;
}
return 1;
}
/* Forward */
static int
object_init(PyObject *self, PyObject *args, PyObject *kwds);
static int
type_init(PyObject *cls, PyObject *args, PyObject *kwds)
{
int res;
assert(args != NULL && PyTuple_Check(args));
assert(kwds == NULL || PyDict_Check(kwds));
if (kwds != NULL && PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1 &&
PyDict_Check(kwds) && PyDict_GET_SIZE(kwds) != 0) {
PyErr_SetString(PyExc_TypeError,
"type.__init__() takes no keyword arguments");
return -1;
}
if (args != NULL && PyTuple_Check(args) &&
(PyTuple_GET_SIZE(args) != 1 && PyTuple_GET_SIZE(args) != 3)) {
PyErr_SetString(PyExc_TypeError,
"type.__init__() takes 1 or 3 arguments");
return -1;
}
/* Call object.__init__(self) now. */
/* XXX Could call super(type, cls).__init__() but what's the point? */
args = PyTuple_GetSlice(args, 0, 0);
if (args == NULL) {
return -1;
}
res = object_init(cls, args, NULL);
Py_DECREF(args);
return res;
}
unsigned long
PyType_GetFlags(PyTypeObject *type)
{
return type->tp_flags;
}
/* Determine the most derived metatype. */
PyTypeObject *
_PyType_CalculateMetaclass(PyTypeObject *metatype, PyObject *bases)
{
Py_ssize_t i, nbases;
PyTypeObject *winner;
PyObject *tmp;
PyTypeObject *tmptype;
/* Determine the proper metatype to deal with this,
and check for metatype conflicts while we're at it.
Note that if some other metatype wins to contract,
it's possible that its instances are not types. */
nbases = PyTuple_GET_SIZE(bases);
winner = metatype;
for (i = 0; i < nbases; i++) {
tmp = PyTuple_GET_ITEM(bases, i);
tmptype = Py_TYPE(tmp);
if (PyType_IsSubtype(winner, tmptype))
continue;
if (PyType_IsSubtype(tmptype, winner)) {
winner = tmptype;
continue;
}
/* else: */
PyErr_SetString(PyExc_TypeError,
"metaclass conflict: "
"the metaclass of a derived class "
"must be a (non-strict) subclass "
"of the metaclasses of all its bases");
return NULL;
}
return winner;
}
// Forward declaration
static PyObject *
type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds);
typedef struct {
PyTypeObject *metatype;
PyObject *args;
PyObject *kwds;
PyObject *orig_dict;
PyObject *name;
PyObject *bases;
PyTypeObject *base;
PyObject *slots;
Py_ssize_t nslot;
int add_dict;
int add_weak;
int may_add_dict;
int may_add_weak;
} type_new_ctx;
/* Check for valid slot names and two special cases */
static int
type_new_visit_slots(type_new_ctx *ctx)
{
PyObject *slots = ctx->slots;
Py_ssize_t nslot = ctx->nslot;
for (Py_ssize_t i = 0; i < nslot; i++) {
PyObject *name = PyTuple_GET_ITEM(slots, i);
if (!valid_identifier(name)) {
return -1;
}
assert(PyUnicode_Check(name));
if (_PyUnicode_EqualToASCIIId(name, &PyId___dict__)) {
if (!ctx->may_add_dict || ctx->add_dict != 0) {
PyErr_SetString(PyExc_TypeError,
"__dict__ slot disallowed: "
"we already got one");
return -1;
}
ctx->add_dict++;
}
if (_PyUnicode_EqualToASCIIId(name, &PyId___weakref__)) {
if (!ctx->may_add_weak || ctx->add_weak != 0) {
PyErr_SetString(PyExc_TypeError,
"__weakref__ slot disallowed: "
"either we already got one, "
"or __itemsize__ != 0");
return -1;
}
ctx->add_weak++;
}
}
return 0;
}
/* Copy slots into a list, mangle names and sort them.
Sorted names are needed for __class__ assignment.
Convert them back to tuple at the end.
*/
static PyObject*
type_new_copy_slots(type_new_ctx *ctx, PyObject *dict)
{
PyObject *slots = ctx->slots;
Py_ssize_t nslot = ctx->nslot;
Py_ssize_t new_nslot = nslot - ctx->add_dict - ctx->add_weak;
PyObject *new_slots = PyList_New(new_nslot);
if (new_slots == NULL) {
return NULL;
}
Py_ssize_t j = 0;
for (Py_ssize_t i = 0; i < nslot; i++) {
PyObject *slot = PyTuple_GET_ITEM(slots, i);
if ((ctx->add_dict &&
_PyUnicode_EqualToASCIIId(slot, &PyId___dict__)) ||
(ctx->add_weak &&
_PyUnicode_EqualToASCIIString(slot, "__weakref__")))
{
continue;
}
slot =_Py_Mangle(ctx->name, slot);
if (!slot) {
goto error;
}
PyList_SET_ITEM(new_slots, j, slot);
int r = PyDict_Contains(dict, slot);
if (r < 0) {
goto error;
}
if (r > 0) {
/* CPython inserts __qualname__ and __classcell__ (when needed)
into the namespace when creating a class. They will be deleted
below so won't act as class variables. */
if (!_PyUnicode_EqualToASCIIId(slot, &PyId___qualname__) &&
!_PyUnicode_EqualToASCIIId(slot, &PyId___classcell__))
{
PyErr_Format(PyExc_ValueError,
"%R in __slots__ conflicts with class variable",
slot);
goto error;
}
}
j++;
}
assert(j == new_nslot);
if (PyList_Sort(new_slots) == -1) {
goto error;
}
PyObject *tuple = PyList_AsTuple(new_slots);
Py_DECREF(new_slots);
if (tuple == NULL) {
return NULL;
}
assert(PyTuple_GET_SIZE(tuple) == new_nslot);
return tuple;
error:
Py_DECREF(new_slots);
return NULL;
}
static void
type_new_slots_bases(type_new_ctx *ctx)
{
Py_ssize_t nbases = PyTuple_GET_SIZE(ctx->bases);
if (nbases > 1 &&
((ctx->may_add_dict && ctx->add_dict == 0) ||
(ctx->may_add_weak && ctx->add_weak == 0)))
{
for (Py_ssize_t i = 0; i < nbases; i++) {
PyObject *base = PyTuple_GET_ITEM(ctx->bases, i);
if (base == (PyObject *)ctx->base) {
/* Skip primary base */
continue;
}
assert(PyType_Check(base));
PyTypeObject *type = (PyTypeObject *)base;
if (ctx->may_add_dict && ctx->add_dict == 0 &&
type->tp_dictoffset != 0)
{
ctx->add_dict++;
}
if (ctx->may_add_weak && ctx->add_weak == 0 &&
type->tp_weaklistoffset != 0)
{
ctx->add_weak++;
}
if (ctx->may_add_dict && ctx->add_dict == 0) {
continue;
}
if (ctx->may_add_weak && ctx->add_weak == 0) {
continue;
}
/* Nothing more to check */
break;
}
}
}
static int
type_new_slots_impl(type_new_ctx *ctx, PyObject *dict)
{
/* Are slots allowed? */
if (ctx->nslot > 0 && ctx->base->tp_itemsize != 0) {
PyErr_Format(PyExc_TypeError,
"nonempty __slots__ not supported for subtype of '%s'",
ctx->base->tp_name);
return -1;
}
if (type_new_visit_slots(ctx) < 0) {
return -1;
}
PyObject *new_slots = type_new_copy_slots(ctx, dict);
if (new_slots == NULL) {
return -1;
}
assert(PyTuple_CheckExact(new_slots));
Py_XSETREF(ctx->slots, new_slots);
ctx->nslot = PyTuple_GET_SIZE(new_slots);
/* Secondary bases may provide weakrefs or dict */
type_new_slots_bases(ctx);
return 0;
}
static Py_ssize_t
type_new_slots(type_new_ctx *ctx, PyObject *dict)
{
// Check for a __slots__ sequence variable in dict, and count it
ctx->add_dict = 0;
ctx->add_weak = 0;
ctx->may_add_dict = (ctx->base->tp_dictoffset == 0);
ctx->may_add_weak = (ctx->base->tp_weaklistoffset == 0
&& ctx->base->tp_itemsize == 0);
if (ctx->slots == NULL) {
if (ctx->may_add_dict) {
ctx->add_dict++;
}
if (ctx->may_add_weak) {
ctx->add_weak++;
}
}
else {
/* Have slots */
if (type_new_slots_impl(ctx, dict) < 0) {
return -1;
}
}
return 0;
}
static PyTypeObject*
type_new_alloc(type_new_ctx *ctx)
{
PyTypeObject *metatype = ctx->metatype;
PyTypeObject *type;
// Allocate the type object
type = (PyTypeObject *)metatype->tp_alloc(metatype, ctx->nslot);
if (type == NULL) {
return NULL;
}
PyHeapTypeObject *et = (PyHeapTypeObject *)type;
// Initialize tp_flags.
// All heap types need GC, since we can create a reference cycle by storing
// an instance on one of its parents.
type->tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE |
Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC);
// Initialize essential fields
type->tp_as_async = &et->as_async;
type->tp_as_number = &et->as_number;
type->tp_as_sequence = &et->as_sequence;
type->tp_as_mapping = &et->as_mapping;
type->tp_as_buffer = &et->as_buffer;
type->tp_bases = Py_NewRef(ctx->bases);
type->tp_base = (PyTypeObject *)Py_NewRef(ctx->base);
type->tp_dealloc = subtype_dealloc;
/* Always override allocation strategy to use regular heap */
type->tp_alloc = PyType_GenericAlloc;
type->tp_free = PyObject_GC_Del;
type->tp_traverse = subtype_traverse;
type->tp_clear = subtype_clear;
et->ht_name = Py_NewRef(ctx->name);
et->ht_module = NULL;
return type;
}
static int
type_new_set_name(const type_new_ctx *ctx, PyTypeObject *type)
{
Py_ssize_t name_size;
type->tp_name = PyUnicode_AsUTF8AndSize(ctx->name, &name_size);
if (!type->tp_name) {
return -1;
}
if (strlen(type->tp_name) != (size_t)name_size) {
PyErr_SetString(PyExc_ValueError,
"type name must not contain null characters");
return -1;
}
return 0;
}
/* Set __module__ in the dict */
static int
type_new_set_module(PyTypeObject *type)
{
int r = _PyDict_ContainsId(type->tp_dict, &PyId___module__);
if (r < 0) {
return -1;
}
if (r > 0) {
return 0;
}
PyObject *globals = PyEval_GetGlobals();
if (globals == NULL) {
return 0;
}
PyObject *module = _PyDict_GetItemIdWithError(globals, &PyId___name__);
if (module == NULL) {
if (PyErr_Occurred()) {
return -1;
}
return 0;
}
if (_PyDict_SetItemId(type->tp_dict, &PyId___module__, module) < 0) {
return -1;
}
return 0;
}
/* Set ht_qualname to dict['__qualname__'] if available, else to
__name__. The __qualname__ accessor will look for ht_qualname. */
static int
type_new_set_ht_name(PyTypeObject *type)
{
PyHeapTypeObject *et = (PyHeapTypeObject *)type;
PyObject *qualname = _PyDict_GetItemIdWithError(type->tp_dict,
&PyId___qualname__);
if (qualname != NULL) {
if (!PyUnicode_Check(qualname)) {
PyErr_Format(PyExc_TypeError,
"type __qualname__ must be a str, not %s",
Py_TYPE(qualname)->tp_name);
return -1;
}
et->ht_qualname = Py_NewRef(qualname);
if (_PyDict_DelItemId(type->tp_dict, &PyId___qualname__) < 0) {
return -1;
}
}
else {
if (PyErr_Occurred()) {
return -1;
}
et->ht_qualname = Py_NewRef(et->ht_name);
}
return 0;
}
/* Set tp_doc to a copy of dict['__doc__'], if the latter is there
and is a string. The __doc__ accessor will first look for tp_doc;
if that fails, it will still look into __dict__. */
static int
type_new_set_doc(PyTypeObject *type)
{
PyObject *doc = _PyDict_GetItemIdWithError(type->tp_dict, &PyId___doc__);
if (doc == NULL) {
if (PyErr_Occurred()) {
return -1;
}
// no __doc__ key
return 0;
}
if (!PyUnicode_Check(doc)) {
// ignore non-string __doc__
return 0;
}
const char *doc_str = PyUnicode_AsUTF8(doc);
if (doc_str == NULL) {
return -1;
}
// Silently truncate the docstring if it contains a null byte
Py_ssize_t size = strlen(doc_str) + 1;
char *tp_doc = (char *)PyObject_Malloc(size);
if (tp_doc == NULL) {
PyErr_NoMemory();
return -1;
}
memcpy(tp_doc, doc_str, size);
type->tp_doc = tp_doc;
return 0;
}
static int
type_new_staticmethod(PyTypeObject *type, _Py_Identifier *attr_id)
{
PyObject *func = _PyDict_GetItemIdWithError(type->tp_dict, attr_id);
if (func == NULL) {
if (PyErr_Occurred()) {
return -1;
}
return 0;
}
if (!PyFunction_Check(func)) {
return 0;
}
PyObject *static_func = PyStaticMethod_New(func);
if (static_func == NULL) {
return -1;
}
if (_PyDict_SetItemId(type->tp_dict, attr_id, static_func) < 0) {
Py_DECREF(static_func);
return -1;
}
Py_DECREF(static_func);
return 0;
}
static int
type_new_classmethod(PyTypeObject *type, _Py_Identifier *attr_id)
{
PyObject *func = _PyDict_GetItemIdWithError(type->tp_dict, attr_id);
if (func == NULL) {
if (PyErr_Occurred()) {
return -1;
}
return 0;
}
if (!PyFunction_Check(func)) {
return 0;
}
PyObject *method = PyClassMethod_New(func);
if (method == NULL) {
return -1;
}
if (_PyDict_SetItemId(type->tp_dict, attr_id, method) < 0) {
Py_DECREF(method);
return -1;
}
Py_DECREF(method);
return 0;
}
/* Add descriptors for custom slots from __slots__, or for __dict__ */
static int
type_new_descriptors(const type_new_ctx *ctx, PyTypeObject *type)
{
PyHeapTypeObject *et = (PyHeapTypeObject *)type;
Py_ssize_t slotoffset = ctx->base->tp_basicsize;
if (et->ht_slots != NULL) {
PyMemberDef *mp = PyHeapType_GET_MEMBERS(et);
Py_ssize_t nslot = PyTuple_GET_SIZE(et->ht_slots);
for (Py_ssize_t i = 0; i < nslot; i++, mp++) {
mp->name = PyUnicode_AsUTF8(
PyTuple_GET_ITEM(et->ht_slots, i));
if (mp->name == NULL) {
return -1;
}
mp->type = T_OBJECT_EX;
mp->offset = slotoffset;
/* __dict__ and __weakref__ are already filtered out */
assert(strcmp(mp->name, "__dict__") != 0);
assert(strcmp(mp->name, "__weakref__") != 0);
slotoffset += sizeof(PyObject *);
}
}
if (ctx->add_dict) {
if (ctx->base->tp_itemsize) {
type->tp_dictoffset = -(long)sizeof(PyObject *);
}
else {
type->tp_dictoffset = slotoffset;
}
slotoffset += sizeof(PyObject *);
}
if (ctx->add_weak) {
assert(!ctx->base->tp_itemsize);
type->tp_weaklistoffset = slotoffset;
slotoffset += sizeof(PyObject *);
}
type->tp_basicsize = slotoffset;
type->tp_itemsize = ctx->base->tp_itemsize;
type->tp_members = PyHeapType_GET_MEMBERS(et);
return 0;
}
static void
type_new_set_slots(const type_new_ctx *ctx, PyTypeObject *type)
{
if (type->tp_weaklistoffset && type->tp_dictoffset) {
type->tp_getset = subtype_getsets_full;
}
else if (type->tp_weaklistoffset && !type->tp_dictoffset) {
type->tp_getset = subtype_getsets_weakref_only;
}
else if (!type->tp_weaklistoffset && type->tp_dictoffset) {
type->tp_getset = subtype_getsets_dict_only;
}
else {
type->tp_getset = NULL;
}
/* Special case some slots */
if (type->tp_dictoffset != 0 || ctx->nslot > 0) {
PyTypeObject *base = ctx->base;
if (base->tp_getattr == NULL && base->tp_getattro == NULL) {
type->tp_getattro = PyObject_GenericGetAttr;
}
if (base->tp_setattr == NULL && base->tp_setattro == NULL) {
type->tp_setattro = PyObject_GenericSetAttr;
}
}
}
/* store type in class' cell if one is supplied */