Index: Lib/test/test_descr.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_descr.py,v retrieving revision 1.156 diff -c -r1.156 test_descr.py *** Lib/test/test_descr.py 23 Aug 2002 18:21:26 -0000 1.156 --- Lib/test/test_descr.py 7 Oct 2002 02:16:32 -0000 *************** *** 932,958 **** def all_method(self): return "D b" ! class M2(object, D): def m2method(self): return "M2 a" def all_method(self): return "M2 b" ! vereq(M2.__mro__, (M2, object, D, C)) m = M2() vereq(m.cmethod(), "C a") vereq(m.dmethod(), "D a") vereq(m.m2method(), "M2 a") vereq(m.all_method(), "M2 b") ! class M3(M1, object, M2): def m3method(self): return "M3 a" def all_method(self): return "M3 b" ! # XXX Expected this (the commented-out result): ! # vereq(M3.__mro__, (M3, M1, M2, object, D, C)) ! vereq(M3.__mro__, (M3, M1, M2, D, C, object)) # XXX ? m = M3() vereq(m.cmethod(), "C a") vereq(m.dmethod(), "D a") --- 932,956 ---- def all_method(self): return "D b" ! class M2(D, object): def m2method(self): return "M2 a" def all_method(self): return "M2 b" ! vereq(M2.__mro__, (M2, D, C, object)) m = M2() vereq(m.cmethod(), "C a") vereq(m.dmethod(), "D a") vereq(m.m2method(), "M2 a") vereq(m.all_method(), "M2 b") ! class M3(M1, M2, object): def m3method(self): return "M3 a" def all_method(self): return "M3 b" ! vereq(M3.__mro__, (M3, M1, M2, D, C, object)) m = M3() vereq(m.cmethod(), "C a") vereq(m.dmethod(), "D a") *************** *** 993,1006 **** vereq(E().spam(), "B") vereq(E().boo(), "C") vereq(E.__mro__, (E, C, B, A, object)) ! class F(D, E): pass ! vereq(F().spam(), "B") ! vereq(F().boo(), "B") ! vereq(F.__mro__, (F, D, E, B, C, A, object)) ! class G(E, D): pass ! vereq(G().spam(), "B") ! vereq(G().boo(), "C") ! vereq(G.__mro__, (G, E, D, C, B, A, object)) def objects(): if verbose: print "Testing object class..." --- 991,1055 ---- vereq(E().spam(), "B") vereq(E().boo(), "C") vereq(E.__mro__, (E, C, B, A, object)) ! # MRO order disagreement ! # class F(D, E): pass ! # vereq(F().spam(), "B") ! # vereq(F().boo(), "B") ! # vereq(F.__mro__, (F, D, E, B, C, A, object)) ! # class G(E, D): pass ! # vereq(G().spam(), "B") ! # vereq(G().boo(), "C") ! # vereq(G.__mro__, (G, E, D, C, B, A, object)) ! ! ! # see thread python-dev/2002-October/029035.html ! def ex5(): ! if verbose: print "Testing ex5 from C3 switch discussion..." ! class A(object): pass ! class B(object): pass ! class C(object): pass ! class X(A): pass ! class Y(A): pass ! class Z(X,B,Y,C): pass ! vereq(Z.__mro__, (Z, X, B, Y, A, C, object)) ! ! # see "A Monotonic Superclass Linearization for Dylan", ! # by Kim Barrett et al. (OOPSLA 1996) ! def monotonicity(): ! if verbose: print "Testing MRO monotonicity..." ! class Boat(object): pass ! class DayBoat(Boat): pass ! class WheelBoat(Boat): pass ! class EngineLess(DayBoat): pass ! class SmallMultihull(DayBoat): pass ! class PedalWheelBoat(EngineLess,WheelBoat): pass ! class SmallCatamaran(SmallMultihull): pass ! class Pedalo(PedalWheelBoat,SmallCatamaran): pass ! ! vereq(PedalWheelBoat.__mro__, ! (PedalWheelBoat, EngineLess, DayBoat, WheelBoat, Boat, ! object)) ! vereq(SmallCatamaran.__mro__, ! (SmallCatamaran, SmallMultihull, DayBoat, Boat, object)) ! ! vereq(Pedalo.__mro__, ! (Pedalo, PedalWheelBoat, EngineLess, SmallCatamaran, ! SmallMultihull, DayBoat, WheelBoat, Boat, object)) ! ! # see "A Monotonic Superclass Linearization for Dylan", ! # by Kim Barrett et al. (OOPSLA 1996) ! def consistency_with_epg(): ! if verbose: print "Testing consistentcy with EPG..." ! class Pane(object): pass ! class ScrollingMixin(object): pass ! class EditingMixin(object): pass ! class ScrollablePane(Pane,ScrollingMixin): pass ! class EditablePane(Pane,EditingMixin): pass ! class EditableScrollablePane(ScrollablePane,EditablePane): pass ! ! vereq(EditableScrollablePane.__mro__, ! (EditableScrollablePane, ScrollablePane, EditablePane, ! Pane, ScrollingMixin, EditingMixin, object)) def objects(): if verbose: print "Testing object class..." *************** *** 1214,1224 **** a.foo = 42 vereq(a.__dict__, {"foo": 42}) ! class C3(C1, C2): ! __slots__ = [] ! ! class C4(C2, C1): ! __slots__ = [] def dynamics(): if verbose: print "Testing class attribute propagation..." --- 1263,1275 ---- a.foo = 42 vereq(a.__dict__, {"foo": 42}) ! # MRO order disagreement ! # ! # class C3(C1, C2): ! # __slots__ = [] ! # ! # class C4(C2, C1): ! # __slots__ = [] def dynamics(): if verbose: print "Testing class attribute propagation..." *************** *** 1505,1516 **** vereq(D.mro(), [D, B, C, A, object]) vereq(D.__mro__, (D, B, C, A, object)) vereq(D().f(), "C") class PerverseMetaType(type): def mro(cls): L = type.mro(cls) L.reverse() return L ! class X(A,B,C,D): __metaclass__ = PerverseMetaType vereq(X.__mro__, (object, A, C, B, D, X)) vereq(X().f(), "A") --- 1556,1568 ---- vereq(D.mro(), [D, B, C, A, object]) vereq(D.__mro__, (D, B, C, A, object)) vereq(D().f(), "C") + class PerverseMetaType(type): def mro(cls): L = type.mro(cls) L.reverse() return L ! class X(D,B,C,A): __metaclass__ = PerverseMetaType vereq(X.__mro__, (object, A, C, B, D, X)) vereq(X().f(), "A") *************** *** 3346,3351 **** --- 3398,3406 ---- pymods() multi() diamond() + ex5() + monotonicity() + consistency_with_epg() objects() slots() slotspecials() Index: Objects/typeobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/typeobject.c,v retrieving revision 2.179 diff -c -r2.179 typeobject.c *** Objects/typeobject.c 16 Aug 2002 17:01:08 -0000 2.179 --- Objects/typeobject.c 7 Oct 2002 02:16:39 -0000 *************** *** 613,678 **** return retval; } - /* 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, ok; - PyObject *temp, *rr; - - assert(PyList_Check(left)); - assert(PyList_Check(right)); - - 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); - if (temp == NULL) - return -1; - for (r = 0; r < j; r++) { - rr = PyList_GET_ITEM(right, r); - ok = PySequence_Contains(left, rr); - if (ok < 0) { - Py_DECREF(temp); - return -1; - } - if (!ok) { - ok = PyList_Append(temp, rr); - if (ok < 0) { - Py_DECREF(temp); - return -1; - } - } - } - ok = PyList_SetSlice(left, i, i, temp); - Py_DECREF(temp); - if (ok < 0) - return -1; - ok = PyList_SetSlice(right, 0, j+1, NULL); - if (ok < 0) - return -1; - 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 int fill_classic_mro(PyObject *mro, PyObject *cls) { --- 613,618 ---- *************** *** 714,724 **** --- 654,746 ---- return NULL; } + /* + 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) + + */ + + static int + tail_contains(PyObject *list, int whence, PyObject *o) { + int j, size; + size = PyList_GET_SIZE(list); + + for (j = whence+1; j < size; j++) { + if (PyList_GET_ITEM(list, j) == o) return 1; + } + return 0; + } + + static int + pmerge(PyObject *acc, PyObject* to_merge) { + int i, j, to_merge_size; + int *remain; + int ok, empty_cnt; + + to_merge_size = PyList_GET_SIZE(to_merge); + + remain = PyMem_MALLOC(SIZEOF_INT*to_merge_size); + if (remain == NULL) + 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++) { + int constrained; + PyObject *candidate; + + PyObject *cur_list = PyList_GET_ITEM(to_merge, i); + + if (remain[i] >= PyList_GET_SIZE(cur_list)) { + empty_cnt++; + continue; + } + + candidate = PyList_GET_ITEM(cur_list, remain[i]); + constrained = 0; + for (j = 0; j < to_merge_size; j++) { + PyObject *j_lst = PyList_GET_ITEM(to_merge, j); + if (tail_contains(j_lst, remain[j], candidate)) { + constrained = 1; + break; + } + } + if (constrained) continue; + ok = PyList_Append(acc, candidate); + if (ok < 0) { + PyMem_Free(remain); + return -1; + } + for (j = 0; j < to_merge_size; j++) { + PyObject *j_lst = PyList_GET_ITEM(to_merge, j); + if (PyList_GET_ITEM(j_lst, remain[j]) == candidate) { + remain[j]++; + } + } + goto again; + + } + + PyMem_FREE(remain); + if (empty_cnt == to_merge_size) + return 0; + PyErr_SetString( + PyExc_TypeError, + "MRO order disagreement"); + return -1; + } + static PyObject * mro_implementation(PyTypeObject *type) { int i, n, ok; PyObject *bases, *result; + PyObject *to_merge, *bases_aslist; if(type->tp_dict == NULL) { if(PyType_Ready(type) < 0) *************** *** 727,735 **** bases = type->tp_bases; n = PyTuple_GET_SIZE(bases); ! result = Py_BuildValue("[O]", (PyObject *)type); ! if (result == NULL) return NULL; for (i = 0; i < n; i++) { PyObject *base = PyTuple_GET_ITEM(bases, i); PyObject *parentMRO; --- 749,759 ---- bases = type->tp_bases; n = PyTuple_GET_SIZE(bases); ! ! to_merge=PyList_New(n+1); ! if (to_merge == NULL) return NULL; + for (i = 0; i < n; i++) { PyObject *base = PyTuple_GET_ITEM(bases, i); PyObject *parentMRO; *************** *** 739,758 **** else parentMRO = classic_mro(base); if (parentMRO == NULL) { ! Py_DECREF(result); ! return NULL; ! } ! if (serious_order_disagreements(result, parentMRO)) { ! Py_DECREF(result); return NULL; ! } ! ok = conservative_merge(result, parentMRO); ! Py_DECREF(parentMRO); ! if (ok < 0) { ! Py_DECREF(result); ! return NULL; ! } } return result; } --- 763,796 ---- else parentMRO = classic_mro(base); if (parentMRO == NULL) { ! Py_DECREF(to_merge); return NULL; ! } ! ! ! PyList_SET_ITEM(to_merge, i, parentMRO); } + + bases_aslist = PySequence_List(bases); + if (bases_aslist == NULL) { + Py_DECREF(to_merge); + return NULL; + } + PyList_SET_ITEM(to_merge, n, bases_aslist); + + result = Py_BuildValue("[O]", (PyObject *)type); + if (result == NULL) { + Py_DECREF(to_merge); + return NULL; + } + + ok = pmerge(result, to_merge); + Py_DECREF(to_merge); + if (ok < 0) { + Py_DECREF(result); + return NULL; + } + return result; }