[pypy-svn] r57654 - in pypy/dist/pypy/objspace/std: . test

arigo at codespeak.net arigo at codespeak.net
Wed Aug 27 17:42:32 CEST 2008


Author: arigo
Date: Wed Aug 27 17:42:31 2008
New Revision: 57654

Modified:
   pypy/dist/pypy/objspace/std/test/test_typeobject.py
   pypy/dist/pypy/objspace/std/typeobject.py
   pypy/dist/pypy/objspace/std/typetype.py
Log:
issue390 resolved

Merge of the typeobject-init branch:
    
* Refactor W_TypeObject.__init__() into a small forest of helpers.
* Use some of the same helpers for assignment to __bases__.
* More tests.



Modified: pypy/dist/pypy/objspace/std/test/test_typeobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/test/test_typeobject.py	(original)
+++ pypy/dist/pypy/objspace/std/test/test_typeobject.py	Wed Aug 27 17:42:31 2008
@@ -111,6 +111,20 @@
 
 
 class AppTestTypeObject:
+
+    def test_call_type(self):
+        assert type(42) is int
+        C = type('C', (object,), {'x': lambda: 42})
+        unbound_meth = C.x
+        raises(TypeError, unbound_meth)
+        assert unbound_meth.im_func() == 42
+        raises(TypeError, type)
+        raises(TypeError, type, 'test', (object,))
+        raises(TypeError, type, 'test', (object,), {}, 42)
+        raises(TypeError, type, 42, (object,), {})
+        raises(TypeError, type, 'test', 42, {})
+        raises(TypeError, type, 'test', (object,), 42)
+
     def test_bases(self):
         assert int.__bases__ == (object,)
         class X:
@@ -314,17 +328,98 @@
             raise TestFailed, "didn't catch MRO conflict"
 
     def test_mutable_bases_versus_nonheap_types(self):
-        skip("in-progress")
         class A(int):
-            __slots__ = []
+            pass
+        class B(int):
+            __slots__ = ['b']
         class C(int):
             pass
         raises(TypeError, 'C.__bases__ = (A,)')
+        raises(TypeError, 'C.__bases__ = (B,)')
+        raises(TypeError, 'C.__bases__ = (C,)')
         raises(TypeError, 'int.__bases__ = (object,)')
         C.__bases__ = (int,)
+        #--- the following raises on CPython but works on PyPy.
+        #--- I don't see an obvious reason why it should fail...
+        import sys
+        if '__pypy__' not in sys.builtin_module_names:
+            skip("works on PyPy only")
+        class MostlyLikeInt(int):
+            __slots__ = []
+        C.__bases__ = (MostlyLikeInt,)
+
+    def test_mutable_bases_versus_slots(self):
+        class A(object):
+            __slots__ = ['a']
+        class B(A):
+            __slots__ = ['b1', 'b2']
+        class C(B):
+            pass
+        raises(TypeError, 'C.__bases__ = (A,)')
+
+    def test_mutable_bases_versus_weakref(self):
+        class A(object):
+            __slots__ = ['a']
+        class B(A):
+            __slots__ = ['__weakref__']
+        class C(B):
+            pass
+        raises(TypeError, 'C.__bases__ = (A,)')
+
+    def test_mutable_bases_same_slots(self):
+        class A(object):
+            __slots__ = ['a']
+        class B(A):
+            __slots__ = []
+        class C(B):
+            pass
+        c = C()
+        c.a = 42
+        assert C.__mro__ == (C, B, A, object)
+        C.__bases__ = (A,)
+        assert C.__mro__ == (C, A, object)
+        assert c.a == 42
+
+    def test_mutable_bases_versus_slots_2(self):
+        class A(object):
+            __slots__ = ['a']
+        class B(A):
+            __slots__ = ['b1', 'b2']
+        class C(B):
+            __slots__ = ['c']
+        raises(TypeError, 'C.__bases__ = (A,)')
+
+    def test_mutable_bases_keeping_slots(self):
+        class A(object):
+            __slots__ = ['a']
+        class B(A):
+            __slots__ = []
+        class C(B):
+            __slots__ = ['c']
+        c = C()
+        c.a = 42
+        c.c = 85
+        assert C.__mro__ == (C, B, A, object)
+        C.__bases__ = (A,)
+        assert C.__mro__ == (C, A, object)
+        assert c.a == 42
+        assert c.c == 85
+
+        class D(A):
+            __slots__ = []
+        C.__bases__ = (B, D)
+        assert C.__mro__ == (C, B, D, A, object)
+        assert c.a == 42
+        assert c.c == 85
+        raises(TypeError, 'C.__bases__ = (B, D, B)')
+
+        class E(A):
+            __slots__ = ['e']
+        raises(TypeError, 'C.__bases__ = (B, E)')
+        raises(TypeError, 'C.__bases__ = (E, B)')
+        raises(TypeError, 'C.__bases__ = (E,)')
 
     def test_compatible_slot_layout(self):
-        skip("in-progress")
         class A(object):
             __slots__ = ['a']
         class B(A):
@@ -410,6 +505,8 @@
         assert B_mro().b == 1
         assert getattr(B_mro, 'a', None) == None
         assert getattr(B_mro(), 'a', None) == None
+        # also check what the built-in mro() method would return for 'B_mro'
+        assert type.mro(B_mro) == [B_mro, A_mro, object]
 
     def test_abstract_mro(self):
         class A1:    # old-style class
@@ -552,6 +649,53 @@
         assert a.__ == 4
         assert a.__dict__ == {}
 
+    def test_slots_multiple_inheritance(self):
+        class A(object):
+            __slots__ = ['a']
+        class B(A):
+            __slots__ = []
+        class E(A):
+            __slots__ = ['e']
+        class C(B, E):
+            pass
+        c = C()
+        c.a = 42
+        c.e = 85
+        assert c.a == 42
+        assert c.e == 85
+
+    def test_base_attr(self):
+        # check the '__base__'
+        class A(object):
+            __slots__ = ['a']
+        class B(A):
+            __slots__ = []
+        class E(A):
+            __slots__ = ['e']
+        class C(B, E):
+            pass
+        class D(A):
+            __slots__ = []
+        class F(B, D):
+            pass
+        assert C.__base__ is E
+        assert F.__base__ is B
+        assert bool.__base__ is int
+        assert int.__base__ is object
+        assert object.__base__ is None
+
+    def test_cannot_subclass(self):
+        raises(TypeError, type, 'A', (bool,), {})
+
+    def test_slot_conflict(self):
+        class A(object):
+            __slots__ = ['a']
+        class B(A):
+            __slots__ = ['b']
+        class E(A):
+            __slots__ = ['e']
+        raises(TypeError, type, 'C', (B, E), {})
+
     def test_repr(self):
         globals()['__name__'] = 'a'
         class A(object):

Modified: pypy/dist/pypy/objspace/std/typeobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/typeobject.py	(original)
+++ pypy/dist/pypy/objspace/std/typeobject.py	Wed Aug 27 17:42:31 2008
@@ -1,6 +1,5 @@
 from pypy.objspace.std.objspace import *
 from pypy.interpreter.function import Function, StaticMethod
-from pypy.interpreter.argument import Arguments
 from pypy.interpreter import gateway
 from pypy.interpreter.typedef import weakref_descr
 from pypy.objspace.std.stdtypedef import std_dict_descr, issubtypedef, Member
@@ -49,6 +48,7 @@
     from pypy.objspace.std.typetype import type_typedef as typedef
 
     lazyloaders = {} # can be overridden by specific instances
+    version_tag = None
 
     uses_object_getattribute = False
     # ^^^ for config.objspace.std.getattributeshortcut
@@ -60,166 +60,25 @@
         w_self.name = name
         w_self.bases_w = bases_w
         w_self.dict_w = dict_w
-        w_self.ensure_static__new__()
         w_self.nslots = 0
+        w_self.hasdict = False
         w_self.needsdel = False
-        w_self.w_bestbase = None
+        w_self.weakrefable = False
+        w_self.w_same_layout_as = None
         w_self.weak_subclasses = []
-
-        # make sure there is a __doc__ in dict_w
-        if '__doc__' not in dict_w:
-            dict_w['__doc__'] = space.w_None
+        w_self.__flags__ = 0           # or _HEAPTYPE
+        w_self.instancetypedef = overridetypedef
 
         if overridetypedef is not None:
-            w_self.instancetypedef = overridetypedef
-            w_self.hasdict = overridetypedef.hasdict
-            w_self.weakrefable = overridetypedef.weakrefable
-            w_self.__flags__ = 0 # not a heaptype
-            if overridetypedef.base is not None:
-                w_self.w_bestbase = space.gettypeobject(overridetypedef.base)
+            setup_builtin_type(w_self)
+            custom_metaclass = False
         else:
-            w_self.__flags__ = _HEAPTYPE
-            # initialize __module__ in the dict
-            if '__module__' not in dict_w:
-                try:
-                    caller = space.getexecutioncontext().framestack.top()
-                except IndexError:
-                    w_globals = w_locals = space.newdict()
-                else:
-                    w_globals = caller.w_globals
-                    w_str_name = space.wrap('__name__')
-                    w_name = space.finditem(w_globals, w_str_name)
-                    if w_name is not None:
-                        dict_w['__module__'] = w_name
-            # find the most specific typedef
-            instancetypedef = object_typedef
-            for w_base in bases_w:
-                if not isinstance(w_base, W_TypeObject):
-                    continue
-                if issubtypedef(w_base.instancetypedef, instancetypedef):
-                    if instancetypedef is not w_base.instancetypedef:
-                        instancetypedef = w_base.instancetypedef
-                        w_self.w_bestbase = w_base
-                elif not issubtypedef(instancetypedef, w_base.instancetypedef):
-                    raise OperationError(space.w_TypeError,
-                                space.wrap("instance layout conflicts in "
-                                                    "multiple inheritance"))
-            if not instancetypedef.acceptable_as_base_class:
-                raise OperationError(space.w_TypeError,
-                                     space.wrap("type '%s' is not an "
-                                                "acceptable base class" %
-                                                instancetypedef.name))
-            w_self.instancetypedef = instancetypedef
-            w_self.hasdict = False
-            w_self.weakrefable = False
-            hasoldstylebase = False
-            w_most_derived_base_with_slots = None
-            w_newstyle = None
-            for w_base in bases_w:
-                if not isinstance(w_base, W_TypeObject):
-                    hasoldstylebase = True
-                    continue
-                if not w_newstyle:
-                    w_newstyle = w_base
-                if w_base.nslots != 0:
-                    if w_most_derived_base_with_slots is None:
-                        w_most_derived_base_with_slots = w_base
-                    else:
-                        if space.is_true(space.issubtype(w_base, w_most_derived_base_with_slots)):
-                            w_most_derived_base_with_slots = w_base
-                        elif not space.is_true(space.issubtype(w_most_derived_base_with_slots, w_base)):
-                            raise OperationError(space.w_TypeError,
-                                                 space.wrap("instance layout conflicts in "
-                                                            "multiple inheritance"))
-                w_self.hasdict = w_self.hasdict or w_base.hasdict
-                w_self.needsdel = w_self.needsdel or w_base.needsdel
-                w_self.weakrefable = w_self.weakrefable or w_base.weakrefable
-            if not w_newstyle: # only classic bases
-                raise OperationError(space.w_TypeError,
-                                     space.wrap("a new-style class can't have only classic bases"))
+            setup_user_defined_type(w_self)
+            custom_metaclass = not space.is_w(space.type(w_self), space.w_type)
 
-            if w_most_derived_base_with_slots:
-                nslots = w_most_derived_base_with_slots.nslots
-                w_self.w_bestbase = w_most_derived_base_with_slots
-            else:
-                nslots = 0
-
-            if w_self.w_bestbase is None:
-                w_self.w_bestbase = w_newstyle
-
-            wantdict = True
-            wantweakref = True
-            if '__slots__' in dict_w:
-                wantdict = False
-                wantweakref = False
-
-                w_slots = dict_w['__slots__']
-                if space.is_true(space.isinstance(w_slots, space.w_str)):
-                    if space.int_w(space.len(w_slots)) == 0:
-                        raise OperationError(space.w_TypeError,
-                                             space.wrap('__slots__ must be identifiers'))
-                    slot_names_w = [w_slots]
-                else:
-                    slot_names_w = space.unpackiterable(w_slots)
-                for w_slot_name in slot_names_w:
-                    slot_name = space.str_w(w_slot_name)
-                    # slot_name should be a valid identifier
-                    if len(slot_name) == 0:
-                        raise OperationError(space.w_TypeError,
-                                             space.wrap('__slots__ must be identifiers'))
-                    first_char = slot_name[0]
-                    if not first_char.isalpha() and first_char != '_':
-                        raise OperationError(space.w_TypeError,
-                                             space.wrap('__slots__ must be identifiers'))                        
-                    for c in slot_name:
-                        if not c.isalnum() and c!= '_':
-                            raise OperationError(space.w_TypeError,
-                                                 space.wrap('__slots__ must be identifiers'))
-                    if slot_name == '__dict__':
-                        if wantdict or w_self.hasdict:
-                            raise OperationError(space.w_TypeError,
-                                                 space.wrap("__dict__ slot disallowed: we already got one"))
-                        wantdict = True
-                    elif slot_name == '__weakref__':
-                        if wantweakref or w_self.weakrefable:
-                            raise OperationError(space.w_TypeError,
-                                                 space.wrap("__weakref__ slot disallowed: we already got one"))
-                                                
-                        wantweakref = True
-                    else:
-                        # create member
-                        slot_name = _mangle(slot_name, name)
-                        # Force interning of slot names.
-                        slot_name = space.str_w(space.new_interned_str(slot_name))
-                        w_self.dict_w[slot_name] = space.wrap(Member(nslots, slot_name, w_self))
-                        nslots += 1
-
-            w_self.nslots = nslots
-                        
-            wantdict = wantdict or hasoldstylebase
-
-            if wantdict and not w_self.hasdict:
-                w_self.dict_w['__dict__'] = space.wrap(std_dict_descr)
-                w_self.hasdict = True
-            if '__del__' in dict_w:
-                w_self.needsdel = True
-            if wantweakref and not w_self.weakrefable:
-                w_self.dict_w['__weakref__'] = space.wrap(weakref_descr)
-                w_self.weakrefable = True
-            w_type = space.type(w_self)
-            if not space.is_w(w_type, space.w_type):
-                if space.config.objspace.std.withtypeversion:
-                    w_self.version_tag = None
-                w_self.mro_w = []
-                mro_func = space.lookup(w_self, 'mro')
-                mro_func_args = Arguments(space, [w_self])
-                w_mro = space.call_args(mro_func, mro_func_args)
-                w_self.mro_w = space.unpackiterable(w_mro)
-                return
-        w_self.mro_w = w_self.compute_mro()
         if space.config.objspace.std.withtypeversion:
-            if w_self.instancetypedef.hasdict:
-                w_self.version_tag = None
+            if w_self.instancetypedef.hasdict or custom_metaclass:
+                pass
             else:
                 w_self.version_tag = VersionTag()
 
@@ -250,33 +109,14 @@
                 continue
             w_base.add_subclass(w_self)
 
-    # compute the most parent class with the same layout as us
-    def get_layout(w_self):
-        w_bestbase = w_self.w_bestbase
-        if w_bestbase is None: # object
-            return w_self
-        if w_self.instancetypedef is not w_bestbase.instancetypedef:
-            return w_self
-        if w_self.nslots == w_bestbase.nslots:
-            return w_bestbase.get_layout()
-        return w_self
-
     # compute a tuple that fully describes the instance layout
     def get_full_instance_layout(w_self):
-        w_layout = w_self.get_layout()
+        w_layout = w_self.w_same_layout_as or w_self
         return (w_layout, w_self.hasdict, w_self.needsdel, w_self.weakrefable)
 
-    def compute_mro(w_self):
+    def compute_default_mro(w_self):
         return compute_C3_mro(w_self.space, w_self)
 
-    def ensure_static__new__(w_self):
-        # special-case __new__, as in CPython:
-        # if it is a Function, turn it into a static method
-        if '__new__' in w_self.dict_w:
-            w_new = w_self.dict_w['__new__']
-            if isinstance(w_new, Function):
-                w_self.dict_w['__new__'] = StaticMethod(w_new)
-
     def getdictvalue(w_self, space, w_attr):
         return w_self.getdictvalue_w(space, space.str_w(w_attr))
     
@@ -487,6 +327,230 @@
     def setweakref(self, space, weakreflifeline):
         self._lifeline_ = weakreflifeline
 
+# ____________________________________________________________
+# Initialization of type objects
+
+def get_parent_layout(w_type):
+    """Compute the most parent class of 'w_type' whose layout
+       is the same as 'w_type', or None if all parents of 'w_type'
+       have a different layout than 'w_type'.
+    """
+    w_starttype = w_type
+    while len(w_type.bases_w) > 0:
+        w_bestbase = find_best_base(w_type.space, w_type.bases_w)
+        if w_type.instancetypedef is not w_bestbase.instancetypedef:
+            break
+        if w_type.nslots != w_bestbase.nslots:
+            break
+        w_type = w_bestbase
+    if w_type is not w_starttype:
+        return w_type
+    else:
+        return None
+
+def issublayout(w_layout1, w_layout2):
+    space = w_layout2.space
+    while w_layout1 is not w_layout2:
+        w_layout1 = find_best_base(space, w_layout1.bases_w)
+        if w_layout1 is None:
+            return False
+        w_layout1 = w_layout1.w_same_layout_as or w_layout1
+    return True
+
+def find_best_base(space, bases_w):
+    """The best base is one of the bases in the given list: the one
+       whose layout a new type should use as a starting point.
+    """
+    w_bestbase = None
+    for w_candidate in bases_w:
+        if not isinstance(w_candidate, W_TypeObject):
+            continue
+        if w_bestbase is None:
+            w_bestbase = w_candidate   # for now
+            continue
+        candtypedef = w_candidate.instancetypedef
+        besttypedef = w_bestbase.instancetypedef
+        if candtypedef is besttypedef:
+            # two candidates with the same typedef are equivalent unless
+            # one has extra slots over the other
+            if w_candidate.nslots > w_bestbase.nslots:
+                w_bestbase = w_candidate
+        elif issubtypedef(candtypedef, besttypedef):
+            w_bestbase = w_candidate
+    return w_bestbase
+
+def check_and_find_best_base(space, bases_w):
+    """The best base is one of the bases in the given list: the one
+       whose layout a new type should use as a starting point.
+       This version checks that bases_w is an acceptable tuple of bases.
+    """
+    w_bestbase = find_best_base(space, bases_w)
+    if w_bestbase is None:
+        raise OperationError(space.w_TypeError,
+                             space.wrap("a new-style class can't have "
+                                        "only classic bases"))
+    if not w_bestbase.instancetypedef.acceptable_as_base_class:
+        raise OperationError(space.w_TypeError,
+                             space.wrap("type '%s' is not an "
+                                        "acceptable base class" %
+                                        w_bestbase.instancetypedef.name))
+
+    # check that all other bases' layouts are superclasses of the bestbase
+    w_bestlayout = w_bestbase.w_same_layout_as or w_bestbase
+    for w_base in bases_w:
+        if isinstance(w_base, W_TypeObject):
+            w_layout = w_base.w_same_layout_as or w_base
+            if not issublayout(w_bestlayout, w_layout):
+                raise OperationError(space.w_TypeError,
+                                     space.wrap("instance layout conflicts in "
+                                                "multiple inheritance"))
+    return w_bestbase
+
+def copy_flags_from_bases(w_self, w_bestbase):
+    hasoldstylebase = False
+    for w_base in w_self.bases_w:
+        if not isinstance(w_base, W_TypeObject):
+            hasoldstylebase = True
+            continue
+        w_self.hasdict = w_self.hasdict or w_base.hasdict
+        w_self.needsdel = w_self.needsdel or w_base.needsdel
+        w_self.weakrefable = w_self.weakrefable or w_base.weakrefable
+    w_self.nslots = w_bestbase.nslots
+    return hasoldstylebase
+
+def create_all_slots(w_self, hasoldstylebase):
+    space = w_self.space
+    dict_w = w_self.dict_w
+    if '__slots__' not in dict_w:
+        wantdict = True
+        wantweakref = True
+    else:
+        wantdict = False
+        wantweakref = False
+        w_slots = dict_w['__slots__']
+        if space.is_true(space.isinstance(w_slots, space.w_str)):
+            slot_names_w = [w_slots]
+        else:
+            slot_names_w = space.unpackiterable(w_slots)
+        for w_slot_name in slot_names_w:
+            slot_name = space.str_w(w_slot_name)
+            if slot_name == '__dict__':
+                if wantdict or w_self.hasdict:
+                    raise OperationError(space.w_TypeError,
+                            space.wrap("__dict__ slot disallowed: "
+                                       "we already got one"))
+                wantdict = True
+            elif slot_name == '__weakref__':
+                if wantweakref or w_self.weakrefable:
+                    raise OperationError(space.w_TypeError,
+                            space.wrap("__weakref__ slot disallowed: "
+                                       "we already got one"))
+                wantweakref = True
+            else:
+                create_slot(w_self, slot_name)
+    wantdict = wantdict or hasoldstylebase
+    if wantdict: create_dict_slot(w_self)
+    if wantweakref: create_weakref_slot(w_self)
+    if '__del__' in dict_w: w_self.needsdel = True
+
+def create_slot(w_self, slot_name):
+    space = w_self.space
+    if not valid_slot_name(slot_name):
+        raise OperationError(space.w_TypeError,
+                             space.wrap('__slots__ must be identifiers'))
+    # create member
+    slot_name = _mangle(slot_name, w_self.name)
+    # Force interning of slot names.
+    slot_name = space.str_w(space.new_interned_str(slot_name))
+    member = Member(w_self.nslots, slot_name, w_self)
+    w_self.dict_w[slot_name] = space.wrap(member)
+    w_self.nslots += 1
+
+def create_dict_slot(w_self):
+    if not w_self.hasdict:
+        w_self.dict_w['__dict__'] = w_self.space.wrap(std_dict_descr)
+        w_self.hasdict = True
+
+def create_weakref_slot(w_self):
+    if not w_self.weakrefable:
+        w_self.dict_w['__weakref__'] = w_self.space.wrap(weakref_descr)
+        w_self.weakrefable = True
+
+def valid_slot_name(slot_name):
+    if len(slot_name) == 0 or slot_name[0].isdigit():
+        return False
+    for c in slot_name:
+        if not c.isalnum() and c != '_':
+            return False
+    return True
+
+def setup_user_defined_type(w_self):
+    if len(w_self.bases_w) == 0:
+        w_self.bases_w = [w_self.space.w_object]
+    w_bestbase = check_and_find_best_base(w_self.space, w_self.bases_w)
+    w_self.instancetypedef = w_bestbase.instancetypedef
+    w_self.__flags__ = _HEAPTYPE
+
+    hasoldstylebase = copy_flags_from_bases(w_self, w_bestbase)
+    create_all_slots(w_self, hasoldstylebase)
+
+    w_self.w_same_layout_as = get_parent_layout(w_self)
+    ensure_common_attributes(w_self)
+
+def setup_builtin_type(w_self):
+    w_self.hasdict = w_self.instancetypedef.hasdict
+    w_self.weakrefable = w_self.instancetypedef.weakrefable
+    ensure_common_attributes(w_self)
+
+def ensure_common_attributes(w_self):
+    ensure_static_new(w_self)
+    ensure_doc_attr(w_self)
+    if w_self.is_heaptype():
+        ensure_module_attr(w_self)
+    w_self.mro_w = []      # temporarily
+    compute_mro(w_self)
+
+def ensure_static_new(w_self):
+    # special-case __new__, as in CPython:
+    # if it is a Function, turn it into a static method
+    if '__new__' in w_self.dict_w:
+        w_new = w_self.dict_w['__new__']
+        if isinstance(w_new, Function):
+            w_self.dict_w['__new__'] = StaticMethod(w_new)
+
+def ensure_doc_attr(w_self):
+    # make sure there is a __doc__ in dict_w
+    w_self.dict_w.setdefault('__doc__', w_self.space.w_None)
+
+def ensure_module_attr(w_self):
+    # initialize __module__ in the dict (user-defined types only)
+    if '__module__' not in w_self.dict_w:
+        space = w_self.space
+        try:
+            caller = space.getexecutioncontext().framestack.top()
+        except IndexError:
+            pass
+        else:
+            w_globals = caller.w_globals
+            w_name = space.finditem(w_globals, space.wrap('__name__'))
+            if w_name is not None:
+                w_self.dict_w['__module__'] = w_name
+
+def compute_mro(w_self):
+    if w_self.is_heaptype():
+        space = w_self.space
+        w_metaclass = space.type(w_self)
+        w_where, w_mro_func = space.lookup_in_type_where(w_metaclass, 'mro')
+        assert w_mro_func is not None      # because there is one in 'type'
+        if not space.is_w(w_where, space.w_type):
+            w_mro_meth = space.get(w_mro_func, w_self)
+            w_mro = space.call_function(w_mro_meth)
+            w_self.mro_w = space.unpackiterable(w_mro)
+            # do some checking here
+            return    # done
+    w_self.mro_w = w_self.compute_default_mro()
+
+# ____________________________________________________________
 
 def call__Type(space, w_type, __args__):
     # special case for type(x)

Modified: pypy/dist/pypy/objspace/std/typetype.py
==============================================================================
--- pypy/dist/pypy/objspace/std/typetype.py	(original)
+++ pypy/dist/pypy/objspace/std/typetype.py	Wed Aug 27 17:42:31 2008
@@ -56,6 +56,8 @@
                                      (space.type(w_type).getname(space, '?'))))
     return w_type
 
+# ____________________________________________________________
+
 def _check(space, w_type, msg=None):
     from pypy.objspace.std.typeobject import W_TypeObject
     if not isinstance(w_type, W_TypeObject):
@@ -78,138 +80,94 @@
 
 def descr_get__mro__(space, w_type):
     w_type = _check(space, w_type)
-    # XXX this should be inside typeobject.py
     return space.newtuple(w_type.mro_w)
 
 def descr_mro(space, w_type):
     """Return a type's method resolution order."""
     w_type = _check(space, w_type,"expected type")
-    return space.newlist(w_type.compute_mro())
+    return space.newlist(w_type.compute_default_mro())
 
 def descr_get__bases__(space, w_type):
     w_type = _check(space, w_type)
     return space.newtuple(w_type.bases_w)
 
 def mro_subclasses(space, w_type, temp):
-    from pypy.objspace.std.typeobject import W_TypeObject
+    from pypy.objspace.std.typeobject import W_TypeObject, compute_mro
+    temp.append((w_type, w_type.mro_w))
+    compute_mro(w_type)
     for w_sc in w_type.get_subclasses():
         assert isinstance(w_sc, W_TypeObject)
-        temp.append((w_sc, w_sc.mro_w))
-        mro_internal(space, w_sc)
         mro_subclasses(space, w_sc, temp)
 
-# should be a W_TypeObject method i guess
-def mro_internal(space, w_type):
-    if not space.is_w(space.type(w_type), space.w_type):
-        #w_type.mro_w = []
-        mro_func = space.lookup(w_type, 'mro')
-        mro_func_args = Arguments(space, [w_type])
-        w_mro = space.call_args(mro_func, mro_func_args)
-        w_type.mro_w = space.unpackiterable(w_mro)
-        # do some checking here
-    else:
-        w_type.mro_w = w_type.compute_mro()
-
-def best_base(space, newstyle_bases_w):
-    if not newstyle_bases_w:
-        raise OperationError(space.w_TypeError,
-                             space.wrap("a new-style class can't have only classic bases"))
-    w_bestbase = None
-    w_winner = None
-    for w_base in newstyle_bases_w:
-        w_candidate = w_base.get_layout()
-        if w_winner is None:
-            w_winner = w_candidate
-            w_bestbase = w_base
-        elif space.is_true(space.issubtype(w_winner, w_candidate)):
-            pass
-        elif space.is_true(space.issubtype(w_candidate, w_winner)):
-            w_winner = w_candidate
-            w_bestbase = w_base
-        else:
-            raise OperationError(space.w_TypeError,
-                                 space.wrap("multiple bases have instance lay-out conflict"))
-    return w_bestbase
-
 def descr_set__bases__(space, w_type, w_value):
-    from pypy.objspace.std.typeobject import W_TypeObject
     # this assumes all app-level type objects are W_TypeObject
+    from pypy.objspace.std.typeobject import W_TypeObject
+    from pypy.objspace.std.typeobject import check_and_find_best_base
+    from pypy.objspace.std.typeobject import get_parent_layout
     w_type = _check(space, w_type)
     if not w_type.is_heaptype():
         raise OperationError(space.w_TypeError,
                              space.wrap("can't set %s.__bases__" %
-                                        w_type.name))
+                                        (w_type.name,)))
     if not space.is_true(space.isinstance(w_value, space.w_tuple)):
         raise OperationError(space.w_TypeError,
                              space.wrap("can only assign tuple"
                                         " to %s.__bases__, not %s"%
-                                     (w_type.name,
-                                      space.type(w_value).getname(space, '?'))))
-    if space.int_w(space.len(w_value)) == 0:
+                                    (w_type.name,
+                                     space.type(w_value).getname(space, '?'))))
+    newbases_w = space.unpackiterable(w_value)
+    if len(newbases_w) == 0:
         raise OperationError(space.w_TypeError,
-                             space.wrap("can only assign non-empty tuple to %s.__bases__, not ()"%
-                                        w_type.name))
-    new_newstyle_bases = []
-    for w_base in space.unpackiterable(w_value):
-        if not isinstance(w_base, W_TypeObject):
-            w_typ = space.type(w_base)
-            if not space.is_w(w_typ, space.w_classobj):
-                raise OperationError(space.w_TypeError,
-                                     space.wrap("%s.__bases__ must be tuple "
-                                                "of old- or new-style classes"
-                                                ", not '%s'"%
-                                                (w_type.name,
-                                                 w_typ.getname(space, '?'))))
-        else:
-            new_newstyle_bases.append(w_base)
-            if space.is_true(space.issubtype(w_base, w_type)):
+                             space.wrap("can only assign non-empty tuple"
+                                        " to %s.__bases__, not ()"%
+                                        (w_type.name,)))
+
+    for w_newbase in newbases_w:
+        if isinstance(w_newbase, W_TypeObject):
+            if w_type in w_newbase.compute_default_mro():
                 raise OperationError(space.w_TypeError,
-                                     space.wrap("a __bases__ item causes an inheritance cycle"))
+                                     space.wrap("a __bases__ item causes"
+                                                " an inheritance cycle"))
 
-    new_base = best_base(space, new_newstyle_bases)
+    w_oldbestbase = check_and_find_best_base(space, w_type.bases_w)
+    w_newbestbase = check_and_find_best_base(space, newbases_w)
+    oldlayout = w_oldbestbase.get_full_instance_layout()
+    newlayout = w_newbestbase.get_full_instance_layout()
 
-    if w_type.w_bestbase.get_full_instance_layout() != new_base.get_full_instance_layout():
+    if oldlayout != newlayout:
         raise OperationError(space.w_TypeError,
-                             space.wrap("__bases__ assignment: '%s' object layout differs from '%s'" %
-                                        (w_type.getname(space, '?'), new_base.getname(space, '?'))))
+                space.wrap("__bases__ assignment: '%s' object layout"
+                           " differs from '%s'" %
+                           (w_newbestbase.getname(space, '?'),
+                            w_oldbestbase.getname(space, '?'))))
 
     # invalidate the version_tag of all the current subclasses
     w_type.mutated()
 
-    saved_bases = w_type.bases_w
-    saved_base = w_type.w_bestbase
-    saved_mro = w_type.mro_w
-
-    w_type.bases_w = space.unpackiterable(w_value)
-    w_type.w_bestbase = new_base
-
+    # now we can go ahead and change 'w_type.bases_w'
+    saved_bases_w = w_type.bases_w
     temp = []
     try:
-        mro_internal(space, w_type)
-
+        for w_oldbase in saved_bases_w:
+            if isinstance(w_oldbase, W_TypeObject):
+                w_oldbase.remove_subclass(w_type)
+        w_type.bases_w = newbases_w
+        for w_newbase in newbases_w:
+            if isinstance(w_newbase, W_TypeObject):
+                w_newbase.add_subclass(w_type)
+        # try to recompute all MROs
         mro_subclasses(space, w_type, temp)
-
-        for old_base in saved_bases:
-            if isinstance(old_base, W_TypeObject):
-                old_base.remove_subclass(w_type)
-        for new_base in new_newstyle_bases:
-            new_base.add_subclass(w_type)
     except:
         for cls, old_mro in temp:
             cls.mro_w = old_mro
-        w_type.bases_w = saved_bases
-        w_type.w_bestbase = saved_base
-        w_type.mro_w = saved_mro
+        w_type.bases_w = saved_bases_w
         raise
-    
+    assert w_type.w_same_layout_as is get_parent_layout(w_type)  # invariant
+
 def descr__base(space, w_type):
+    from pypy.objspace.std.typeobject import find_best_base
     w_type = _check(space, w_type)
-    if w_type.w_bestbase is not None:
-        return w_type.w_bestbase
-    elif w_type is not space.w_object:
-        return space.w_object
-    else:
-        return space.w_None
+    return find_best_base(space, w_type.bases_w)
 
 def descr__doc(space, w_type):
     if space.is_w(w_type, space.w_type):



More information about the Pypy-commit mailing list