[Python-checkins] CVS: python/dist/src/Objects typeobject.c,2.16.8.35,2.16.8.36

Guido van Rossum gvanrossum@users.sourceforge.net
Thu, 07 Jun 2001 12:14:47 -0700


Update of /cvsroot/python/python/dist/src/Objects
In directory usw-pr-cvs1:/tmp/cvs-serv7429

Modified Files:
      Tag: descr-branch
	typeobject.c 
Log Message:
Better multiple inheritance, using the method resolution order
specification from "Putting Metaclasses to Work" by Forman and
Danforth (Addison-Wesley 1999).

The functions type_init() and PyType_InitDict() are quite different
now.

__bases__ and tp_base are now set properly by PyType_InitDict() to
make the default base class 'object'; thus the __bases__ descriptor
can be simpler.

New standard attributes of type objects:

- __base__ (singular!), the unique base class on the path to the root
  that has all the instance variable additions;

- __mro__, the method resolution order (a tuple of classes starting
  with type type itself and ending with 'object');

- __introduced__, a read-only proxy for the dictionary of methods and
  slots introduced by this class (possibly overriding or extending an
  inherited method, but not *just* inherited).

The former "intrinsic attributes" of objects are now inherited from
'object'.

The 'object' type now has a (no-op) constructor, so that every type
now has an __init__ method!

The helper functions add_methods(), add_wrappers(), add_members() and
add_getset() now update tp_introduced instead of tp_dict, and don't
overwrite existing keys.

There's still a lot to do!  E.g. the method resolution order
computation doesn't even check for errors.


Index: typeobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/typeobject.c,v
retrieving revision 2.16.8.35
retrieving revision 2.16.8.36
diff -C2 -r2.16.8.35 -r2.16.8.36
*** typeobject.c	2001/06/06 19:00:33	2.16.8.35
--- typeobject.c	2001/06/07 19:14:45	2.16.8.36
***************
*** 15,44 ****
  	{"__weaklistoffset__", T_LONG,
  	 offsetof(PyTypeObject, tp_weaklistoffset), READONLY},
  	{"__dictoffset__", T_LONG,
  	 offsetof(PyTypeObject, tp_dictoffset), READONLY},
  	{0}
  };
  
  static PyObject *
- type_bases(PyTypeObject *type, void *context)
- {
- 	PyObject *bases;
- 	PyTypeObject *base;
- 
- 	bases = type->tp_bases;
- 	if (bases != NULL) {
- 		Py_INCREF(bases);
- 		return bases;
- 	}
- 	base = type->tp_base;
- 	if (base == NULL) {
- 		if (type == &PyBaseObject_Type)
- 			return PyTuple_New(0);
- 		base = &PyBaseObject_Type;
- 	}
- 	return Py_BuildValue("(O)", base);
- }
- 
- static PyObject *
  type_module(PyTypeObject *type, void *context)
  {
--- 15,27 ----
  	{"__weaklistoffset__", T_LONG,
  	 offsetof(PyTypeObject, tp_weaklistoffset), READONLY},
+ 	{"__base__", T_OBJECT, offsetof(PyTypeObject, tp_base), READONLY},
  	{"__dictoffset__", T_LONG,
  	 offsetof(PyTypeObject, tp_dictoffset), READONLY},
+ 	{"__bases__", T_OBJECT, offsetof(PyTypeObject, tp_bases), READONLY},
+ 	{"__mro__", T_OBJECT, offsetof(PyTypeObject, tp_mro), READONLY},
  	{0}
  };
  
  static PyObject *
  type_module(PyTypeObject *type, void *context)
  {
***************
*** 50,67 ****
  {
  	if (type->tp_dict == NULL) {
! 		if (PyType_InitDict(type) < 0)
! 			return NULL;
! 		if (type->tp_dict == NULL) {
! 			Py_INCREF(Py_None);
! 			return Py_None;
! 		}
  	}
  	return PyDictProxy_New(type->tp_dict);
  }
  
  struct getsetlist type_getsets[] = {
- 	{"__bases__", (getter)type_bases, NULL, NULL},
  	{"__module__", (getter)type_module, NULL, NULL},
  	{"__dict__",  (getter)type_dict,  NULL, NULL},
  	{0}
  };
--- 33,56 ----
  {
  	if (type->tp_dict == NULL) {
! 		Py_INCREF(Py_None);
! 		return Py_None;
  	}
  	return PyDictProxy_New(type->tp_dict);
  }
  
+ static PyObject *
+ type_introduced(PyTypeObject *type, void *context)
+ {
+ 	if (type->tp_introduced == NULL) {
+ 		Py_INCREF(Py_None);
+ 		return Py_None;
+ 	}
+ 	return PyDictProxy_New(type->tp_introduced);
+ }
+ 
  struct getsetlist type_getsets[] = {
  	{"__module__", (getter)type_module, NULL, NULL},
  	{"__dict__",  (getter)type_dict,  NULL, NULL},
+ 	{"__introduced__",  (getter)type_introduced,  NULL, NULL},
  	{0}
  };
***************
*** 204,217 ****
  }
  
  /* TypeType's initializer; called when a type is subclassed */
  static int
  type_init(PyObject *self, PyObject *args, PyObject *kwds)
  {
! 	PyObject *name, *bases, *dict, *x, *slots;
  	PyTypeObject *type, *base;
  	static char *kwlist[] = {"name", "bases", "dict", 0};
  	etype *et;
  	struct memberlist *mp;
! 	int i, n, nslots, slotoffset, allocsize;
  
  	assert(PyType_Check(self));
--- 193,328 ----
  }
  
+ /* Method resolution order algorithm from "Putting Metaclasses to Work"
+    by Forman and Danforth (Addison-Wesley 1999). */
+ 
+ static int
+ conservative_merge(PyObject *left, PyObject *right)
+ {
+ 	int left_size;
+ 	int right_size;
+ 	int i, j, r;
+ 	PyObject *temp, *rr;
+ 
+ 	/* XXX add error checking */
+ 
+   again:
+ 	left_size = PyList_GET_SIZE(left);
+ 	right_size = PyList_GET_SIZE(right);
+ 	for (i = 0; i < left_size; i++) {
+ 		for (j = 0; j < right_size; j++) {
+ 			if (PyList_GET_ITEM(left, i) ==
+ 			    PyList_GET_ITEM(right, j)) {
+ 				/* found a merge point */
+ 				temp = PyList_New(0);
+ 				for (r = 0; r < j; r++) {
+ 					rr = PyList_GET_ITEM(right, r);
+ 					if (!PySequence_Contains(left, rr))
+ 						PyList_Append(temp, rr);
+ 				}
+ 				PyList_SetSlice(left, i, i, temp);
+ 				Py_DECREF(temp);
+ 				PyList_SetSlice(right, 0, j+1, NULL);
+ 				goto again;
+ 			}
+ 		}
+ 	}
+ 	return PyList_SetSlice(left, left_size, left_size, right);
+ }
+ 
+ static int
+ serious_order_disagreements(PyObject *left, PyObject *right)
+ {
+ 	return 0; /* XXX later -- for now, we cheat: "don't do that" */
+ }
+ 
+ static PyObject *
+ method_resolution_order(PyTypeObject *type)
+ {
+ 	int i, n;
+ 	PyObject *bases;
+ 	PyObject *result;
+ 
+ 	/* XXX add error checking */
+ 
+ 	if (type->tp_mro != NULL)
+ 		return PySequence_List(type->tp_mro);
+ 
+ 	bases = type->tp_bases;
+ 	if (bases == NULL || !PyTuple_Check(bases))
+ 		return NULL;
+ 	n = PyTuple_GET_SIZE(bases);
+ 	result = Py_BuildValue("[O]", type);
+ 	for (i = 0; i < n; i++) {
+ 		PyTypeObject *base = (PyTypeObject *)
+ 			PyTuple_GET_ITEM(bases, i);
+ 		PyObject *parentMRO = method_resolution_order(base);
+ 		if (parentMRO == NULL) {
+ 			Py_DECREF(result);
+ 			return NULL;
+ 		}
+ 		if (serious_order_disagreements(result, parentMRO)) {
+ 			Py_DECREF(result);
+ 			return NULL;
+ 		}
+ 		conservative_merge(result, parentMRO);
+ 		Py_DECREF(parentMRO);
+ 	}
+ 	if (result != NULL && type->tp_mro == NULL)
+ 		type->tp_mro = PySequence_Tuple(result);
+ 	return result;
+ }
+ 
+ /* 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)
+ {
+ 	int i, n;
+ 	PyTypeObject *base, *winner, *candidate, *base_i;
+ 
+ 	assert(PyTuple_Check(bases));
+ 	n = PyTuple_GET_SIZE(bases);
+ 	assert(n > 0);
+ 	base = (PyTypeObject *)PyTuple_GET_ITEM(bases, 0);
+ 	winner = &PyBaseObject_Type;
+ 	for (i = 0; i < n; i++) {
+ 		base_i = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
+ 		if (!PyType_Check((PyObject *)base_i)) {
+ 			PyErr_SetString(
+ 				PyExc_TypeError,
+ 				"bases must be types");
+ 			return NULL;
+ 		}
+ 		candidate = solid_base(base_i);
+ 		if (issubtype(winner, candidate))
+ 			;
+ 		else if (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;
+ }
+ 
  /* TypeType's initializer; called when a type is subclassed */
+ 
  static int
  type_init(PyObject *self, PyObject *args, PyObject *kwds)
  {
! 	PyObject *name, *bases, *dict, *slots;
  	PyTypeObject *type, *base;
  	static char *kwlist[] = {"name", "bases", "dict", 0};
  	etype *et;
  	struct memberlist *mp;
! 	int i, nbases, nslots, slotoffset, allocsize;
  
  	assert(PyType_Check(self));
***************
*** 227,267 ****
  		return -1;
  	}
! 	n = PyTuple_GET_SIZE(bases);
! 	if (n > 0) {
! 		PyTypeObject *winner, *candidate, *base_i;
! 		base = (PyTypeObject *)PyTuple_GET_ITEM(bases, 0);
! 		winner = &PyBaseObject_Type;
! 		for (i = 0; i < n; i++) {
! 			base_i = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
! 			if (!PyType_Check((PyObject *)base_i)) {
! 				PyErr_SetString(
! 					PyExc_TypeError,
! 					"bases must be types");
! 				return -1;
! 			}
! 			candidate = solid_base(base_i);
! 			if (issubtype(winner, candidate))
! 				;
! 			else if (issubtype(candidate, winner)) {
! 				winner = candidate;
! 				base = base_i;
! 			}
! 			else {
! 				PyErr_SetString(
! 					PyExc_TypeError,
! 					"multiple bases have "
! 					"instance lay-out conflict");
! 				return -1;
! 			}
! 		}
  	}
  	else
! 		base = &PyBaseObject_Type;
! 	if (base->tp_new == NULL) {
  		PyErr_SetString(PyExc_TypeError,
! 				"base type must have a tp_new slot");
  		return -1;
  	}
  
  	/* Check for a __slots__ sequence variable in dict, and count it */
  	slots = PyDict_GetItemString(dict, "__slots__");
--- 338,368 ----
  		return -1;
  	}
! 
! 	/* Adjust empty bases */
! 	nbases = PyTuple_GET_SIZE(bases);
! 	if (nbases == 0) {
! 		bases = Py_BuildValue("(O)", &PyBaseObject_Type);
! 		if (bases == NULL)
! 			return -1;
! 		nbases = 1;
  	}
  	else
! 		Py_INCREF(bases);
! 
! 	/* Calculate best base */
! 	base = best_base(bases);
! 	if (base == NULL)
! 		return -1;
! 	if (base->tp_init == NULL) {
  		PyErr_SetString(PyExc_TypeError,
! 				"base type must have a constructor slot");
  		return -1;
  	}
  
+ 	/* Set tp_base and tp_bases */
+ 	type->tp_bases = bases;
+ 	Py_INCREF(base);
+ 	type->tp_base = base;
+ 
  	/* Check for a __slots__ sequence variable in dict, and count it */
  	slots = PyDict_GetItemString(dict, "__slots__");
***************
*** 312,330 ****
  	type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE;
  
- 	/* Set tp_base and tp_bases properly */
- 	if (PyTuple_GET_SIZE(bases) == 0)
- 		bases = Py_BuildValue("(O)", &PyBaseObject_Type);
- 	else
- 		Py_INCREF(bases);
- 	type->tp_bases = bases;
- 	Py_INCREF(base);
- 	type->tp_base = base;
- 
- 	/* Copy slots and dict from the base type */
- 	if (PyType_InitDict(type) < 0) {
- 		Py_DECREF(type);
- 		return -1;
- 	}
- 
  	/* Override some slots with specific requirements */
  	if (type->tp_dealloc)
--- 413,416 ----
***************
*** 338,346 ****
  		type->tp_setattr = NULL;
  	}
  
! 	/* Add custom slots */
  	mp = et->members;
! 	slotoffset = type->tp_basicsize;
! 	if (type->tp_flags & Py_TPFLAGS_GC)
  		slotoffset -= PyGC_HEAD_SIZE;
  	if (slots != NULL) {
--- 424,437 ----
  		type->tp_setattr = NULL;
  	}
+ 
+ 	/* Initialize tp_introduced from passed-in dict */
+ 	type->tp_introduced = dict = PyDict_Copy(dict);
+ 	if (dict == NULL)
+ 		return -1;
  
! 	/* Add descriptors for custom slots from __slots__, or for __dict__ */
  	mp = et->members;
! 	slotoffset = base->tp_basicsize;
! 	if (base->tp_flags & Py_TPFLAGS_GC)
  		slotoffset -= PyGC_HEAD_SIZE;
  	if (slots != NULL) {
***************
*** 349,359 ****
  				PyTuple_GET_ITEM(slots, i));
  			mp->type = T_OBJECT;
! 			mp->offset = slotoffset + i*sizeof(PyObject *);
  		}
- 		type->tp_basicsize += nslots*sizeof(PyObject *);
  	}
  	else if (nslots) {
  		type->tp_dictoffset = slotoffset;
! 		type->tp_basicsize += sizeof(PyObject *);
  		mp->name = "__dict__";
  		mp->type = T_OBJECT;
--- 440,450 ----
  				PyTuple_GET_ITEM(slots, i));
  			mp->type = T_OBJECT;
! 			mp->offset = slotoffset;
! 			slotoffset += i*sizeof(PyObject *);
  		}
  	}
  	else if (nslots) {
  		type->tp_dictoffset = slotoffset;
! 		slotoffset += sizeof(PyObject *);
  		mp->name = "__dict__";
  		mp->type = T_OBJECT;
***************
*** 361,389 ****
  		mp->readonly = 1;
  	}
  	add_members(type, et->members);
  
! 	/* XXX This is close, but not quite right! */
! 	if (n > 1) {
! 		PyTypeObject *t;
! 		for (i = n; --i >= 0; ) {
! 			t = (PyTypeObject *) PyTuple_GET_ITEM(bases, i);
! 			if (t->tp_dict == NULL)
! 				continue;
! 			x = PyObject_CallMethod(type->tp_dict,
! 						"update", "O", t->tp_dict);
! 			if (x == NULL) {
! 				Py_DECREF(type);
! 				return -1;
! 			}
! 		}
! 	}
! 
! 	x = PyObject_CallMethod(type->tp_dict, "update", "O", dict);
! 	if (x == NULL) {
! 		Py_DECREF(type);
  		return -1;
! 	}
! 	Py_DECREF(x); /* throw away None */
! 	override_slots(type, dict);
  	return 0;
  }
--- 452,464 ----
  		mp->readonly = 1;
  	}
+ 	type->tp_basicsize = slotoffset;
  	add_members(type, et->members);
  
! 	/* Initialize tp_bases, tp_dict, tp_introduced; inherit slots */
! 	if (PyType_InitDict(type) < 0)
  		return -1;
! 
! 	/* Override slots that deserve it */
! 	override_slots(type, type->tp_dict);
  	return 0;
  }
***************
*** 485,488 ****
--- 560,564 ----
  	Py_XDECREF(et->name);
  	Py_XDECREF(et->slots);
+ 	/* XXX more, e.g. bases, mro, introduced ... */
  	PyObject_DEL(type);
  }
***************
*** 543,546 ****
--- 619,633 ----
  }
  
+ static struct memberlist object_members[] = {
+ 	{"__class__", T_OBJECT, offsetof(PyObject, ob_type), READONLY},
+ 	{0}
+ };
+ 
+ static int
+ object_init(PyObject *self, PyObject *args, PyObject *kwds)
+ {
+ 	return 0;
+ }
+ 
  PyTypeObject PyBaseObject_Type = {
  	PyObject_HEAD_INIT(&PyType_Type)
***************
*** 573,577 ****
  	0,					/* tp_iternext */
  	0,					/* tp_methods */
! 	0,					/* tp_members */
  	0,					/* tp_getset */
  	0,					/* tp_base */
--- 660,664 ----
  	0,					/* tp_iternext */
  	0,					/* tp_methods */
! 	object_members,				/* tp_members */
  	0,					/* tp_getset */
  	0,					/* tp_base */
***************
*** 580,584 ****
  	0,					/* tp_descr_set */
  	0,					/* tp_dictoffset */
! 	0,					/* tp_init */
  	PyType_GenericAlloc,			/* tp_alloc */
  	PyType_GenericNew,			/* tp_new */
--- 667,671 ----
  	0,					/* tp_descr_set */
  	0,					/* tp_dictoffset */
! 	object_init,				/* tp_init */
  	PyType_GenericAlloc,			/* tp_alloc */
  	PyType_GenericNew,			/* tp_new */
***************
*** 588,611 ****
  /* Initialize the __dict__ in a type object */
  
- static struct PyMethodDef intrinsic_methods[] = {
- 	{0}
- };
- 
- static struct memberlist intrinsic_members[] = {
- 	{"__class__", T_OBJECT, offsetof(PyObject, ob_type), READONLY},
- 	{0}
- };
- 
- static struct getsetlist intrinsic_getsets[] = {
- 	{0}
- };
- 
  static int
  add_methods(PyTypeObject *type, PyMethodDef *meth)
  {
! 	PyObject *dict = type->tp_dict;
  
  	for (; meth->ml_name != NULL; meth++) {
! 		PyObject *descr = PyDescr_NewMethod(type, meth);
  		if (descr == NULL)
  			return -1;
--- 675,688 ----
  /* Initialize the __dict__ in a type object */
  
  static int
  add_methods(PyTypeObject *type, PyMethodDef *meth)
  {
! 	PyObject *dict = type->tp_introduced;
  
  	for (; meth->ml_name != NULL; meth++) {
! 		PyObject *descr;
! 		if (PyDict_GetItemString(dict, meth->ml_name))
! 			continue;
! 		descr = PyDescr_NewMethod(type, meth);
  		if (descr == NULL)
  			return -1;
***************
*** 620,627 ****
  add_wrappers(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
  {
! 	PyObject *dict = type->tp_dict;
  
  	for (; base->name != NULL; base++) {
! 		PyObject *descr = PyDescr_NewWrapper(type, base, wrapped);
  		if (descr == NULL)
  			return -1;
--- 697,707 ----
  add_wrappers(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
  {
! 	PyObject *dict = type->tp_introduced;
  
  	for (; base->name != NULL; base++) {
! 		PyObject *descr;
! 		if (PyDict_GetItemString(dict, base->name))
! 			continue;
! 		descr = PyDescr_NewWrapper(type, base, wrapped);
  		if (descr == NULL)
  			return -1;
***************
*** 636,643 ****
  add_members(PyTypeObject *type, struct memberlist *memb)
  {
! 	PyObject *dict = type->tp_dict;
  
  	for (; memb->name != NULL; memb++) {
! 		PyObject *descr = PyDescr_NewMember(type, memb);
  		if (descr == NULL)
  			return -1;
--- 716,726 ----
  add_members(PyTypeObject *type, struct memberlist *memb)
  {
! 	PyObject *dict = type->tp_introduced;
  
  	for (; memb->name != NULL; memb++) {
! 		PyObject *descr;
! 		if (PyDict_GetItemString(dict, memb->name))
! 			continue;
! 		descr = PyDescr_NewMember(type, memb);
  		if (descr == NULL)
  			return -1;
***************
*** 652,659 ****
  add_getset(PyTypeObject *type, struct getsetlist *gsp)
  {
! 	PyObject *dict = type->tp_dict;
  
  	for (; gsp->name != NULL; gsp++) {
! 		PyObject *descr = PyDescr_NewGetSet(type, gsp);
  
  		if (descr == NULL)
--- 735,745 ----
  add_getset(PyTypeObject *type, struct getsetlist *gsp)
  {
! 	PyObject *dict = type->tp_introduced;
  
  	for (; gsp->name != NULL; gsp++) {
! 		PyObject *descr;
! 		if (PyDict_GetItemString(dict, gsp->name))
! 			continue;
! 		descr = PyDescr_NewGetSet(type, gsp);
  
  		if (descr == NULL)
***************
*** 836,866 ****
  PyType_InitDict(PyTypeObject *type)
  {
! 	PyObject *dict;
! 	PyTypeObject *base = type->tp_base;
  
  	if (type->tp_dict != NULL)
! 		return 0;
  	if (base) {
  		if (PyType_InitDict(base) < 0)
  			return -1;
- 		dict = PyDict_Copy(base->tp_dict);
  	}
! 	else
  		dict = PyDict_New();
! 	if (dict == NULL)
! 		return -1;
! 	type->tp_dict = dict;
  
! 	/* Add intrinsics */
! 	if (add_methods(type, intrinsic_methods) < 0)
! 		return -1;
! 	if (add_members(type, intrinsic_members) < 0)
! 		return -1;
! 	if (add_getset(type, intrinsic_getsets) < 0)
! 		return -1;
  	if (add_operators(type) < 0)
  		return -1;
- 
- 	/* Add type-specific descriptors */
  	if (type->tp_methods != NULL) {
  		if (add_methods(type, type->tp_methods) < 0)
--- 922,967 ----
  PyType_InitDict(PyTypeObject *type)
  {
! 	PyObject *dict, *bases, *x;
! 	PyTypeObject *base;
! 	int i, n;
  
  	if (type->tp_dict != NULL)
! 		return 0; /* Already initialized */
! 
! 	/* Initialize tp_base (defaults to BaseObject unless that's us) */
! 	base = type->tp_base;
! 	if (base == NULL && type != &PyBaseObject_Type)
! 		base = type->tp_base = &PyBaseObject_Type;
! 
! 	/* Initialize tp_bases */
! 	bases = type->tp_bases;
! 	if (bases == NULL) {
! 		if (base == NULL)
! 			bases = PyTuple_New(0);
! 		else
! 			bases = Py_BuildValue("(O)", base);
! 		if (bases == NULL)
! 			return -1;
! 		type->tp_bases = bases;
! 	}
! 
! 	/* Initialize the base class */
  	if (base) {
  		if (PyType_InitDict(base) < 0)
  			return -1;
  	}
! 
! 	/* Initialize tp_introduced */
! 	dict = type->tp_introduced;
! 	if (dict == NULL) {
  		dict = PyDict_New();
! 		if (dict == NULL)
! 			return -1;
! 		type->tp_introduced = dict;
! 	}
  
! 	/* Add type-specific descriptors to tp_introduced */
  	if (add_operators(type) < 0)
  		return -1;
  	if (type->tp_methods != NULL) {
  		if (add_methods(type, type->tp_methods) < 0)
***************
*** 875,884 ****
  			return -1;
  	}
  
! 	/* Inherit base class slots and methods */
  	if (base) {
  		if (inherit_slots(type, base) < 0)
  			return -1;
  	}
  
  	return 0;
--- 976,1022 ----
  			return -1;
  	}
+ 
+ 	/* Initialize tp_dict from tp_introduced */
+ 	type->tp_dict = PyDict_Copy(dict);
+ 	if (type->tp_dict == NULL)
+ 		return -1;
  
! 	/* Inherit base class slots */
  	if (base) {
  		if (inherit_slots(type, base) < 0)
  			return -1;
  	}
+ 
+ 	/* Calculate method resolution order */
+ 	x = method_resolution_order(type);
+ 	if (x == NULL) {
+ 		if (!PyErr_Occurred())
+ 			PyErr_SetString(PyExc_TypeError,
+ 					"method resolution order failed");
+ 		return -1;
+ 	}
+ 	Py_DECREF(x);
+ 
+ 	/* Inherit methods, updating from last base backwards */
+ 	bases = type->tp_mro;
+ 	assert(bases != NULL);
+ 	assert(PyTuple_Check(bases));
+ 	n = PyTuple_GET_SIZE(bases);
+  	for (i = n; --i >= 0; ) {
+ 		base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
+ 		assert(PyType_Check(base));
+ 		x = base->tp_introduced;
+ 		if (x != NULL) {
+ 			x = PyObject_CallMethod(type->tp_dict, "update","O",x);
+ 			if (x == NULL)
+ 				return -1;
+ 			Py_DECREF(x); /* throw away None */
+ 		}
+ 	}
+ 
+ 	/* Inherit slots from direct base */
+ 	if (type->tp_base != NULL)
+ 		if (inherit_slots(type, type->tp_base) < 0)
+ 			return -1;
  
  	return 0;