From: Guido van Rossum <guido@python.org>
Date: Fri, 17 Aug 2001 11:18:38 +0000 (+0000)
Subject: type_new(): only defer to the winning metatype if it's different from
X-Git-Tag: v2.2a3~483
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8d32c8b59f9b5f4315f42a48b73a52adea3e10a2;p=python

type_new(): only defer to the winning metatype if it's different from
the metatype passed in as an argument.  This prevents infinite
recursion when a metatype written in Python calls type.__new__() as a
"super" call.

Also tweaked some comments.
---

diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index c38340e2b3..474ff3ee2b 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -497,21 +497,21 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
 	PyObject *name, *bases, *dict;
 	static char *kwlist[] = {"name", "bases", "dict", 0};
 	PyObject *slots, *tmp;
-	PyTypeObject *type, *base, *tmptype;
+	PyTypeObject *type, *base, *tmptype, *winner;
 	etype *et;
 	struct memberlist *mp;
 	int i, nbases, nslots, slotoffset, dynamic;
 
+	/* Special case: type(x) should return x->ob_type */
 	if (metatype == &PyType_Type &&
 	    PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1 &&
 	    (kwds == NULL || (PyDict_Check(kwds) && PyDict_Size(kwds) == 0))) {
-		/* type(x) -> x.__class__ */
 		PyObject *x = PyTuple_GET_ITEM(args, 0);
 		Py_INCREF(x->ob_type);
 		return (PyObject *) x->ob_type;
 	}
 
-	/* Check arguments */
+	/* Check arguments: (name, bases, dict) */
 	if (!PyArg_ParseTupleAndKeywords(args, kwds, "SO!O!:type", kwlist,
 					 &name,
 					 &PyTuple_Type, &bases,
@@ -523,21 +523,25 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
 	   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 = tmp->ob_type;
-		if (PyType_IsSubtype(metatype, tmptype))
+		if (PyType_IsSubtype(winner, tmptype))
 			continue;
-		if (PyType_IsSubtype(tmptype, metatype)) {
-			metatype = tmptype;
+		if (PyType_IsSubtype(tmptype, winner)) {
+			winner = tmptype;
 			continue;
 		}
 		PyErr_SetString(PyExc_TypeError,
 				"metatype conflict among bases");
 		return NULL;
 	}
-	if (metatype->tp_new != type_new) /* Pass it to the winner */
-		return metatype->tp_new(metatype, args, kwds);
+	if (winner != metatype) {
+		if (winner->tp_new != type_new) /* Pass it to the winner */
+			return winner->tp_new(winner, args, kwds);
+		metatype = winner;
+	}
 
 	/* Adjust for empty tuple bases */
 	if (nbases == 0) {