Author: Armin Rigo <ar...@tunes.org>
Branch: SpecialisedTuples
Changeset: r50297:363bac62f6dc
Date: 2011-12-08 14:23 +0100
http://bitbucket.org/pypy/pypy/changeset/363bac62f6dc/

Log:    Rework the source code. Kill a few features that don't really make
        sense to have; write by hand a fast decision tree to pick which
        tuple to specialize for; general fixes left and right.

diff --git a/pypy/objspace/std/specialisedtupleobject.py 
b/pypy/objspace/std/specialisedtupleobject.py
--- a/pypy/objspace/std/specialisedtupleobject.py
+++ b/pypy/objspace/std/specialisedtupleobject.py
@@ -4,35 +4,27 @@
 from pypy.objspace.std.multimethod import FailedToImplement
 from pypy.objspace.std.tupleobject import W_TupleObject
 from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
-from pypy.objspace.std.floatobject import _hash_float
 from pypy.rlib.rarithmetic import intmask
 from pypy.rlib.objectmodel import compute_hash
 from pypy.rlib.unroll import unrolling_iterable
 
-class Any(object):
+class NotSpecialised(Exception):
     pass
 
-class NotSpecialised(Exception):
-    pass         
-
-_specialisations = []
-
-def makespecialisedtuple(space, list_w):          
-    for specialisedClass in unrolling_iterable(_specialisations):
-            try:
-                return specialisedClass.try_specialisation(space, list_w)
-            except NotSpecialised:
-                pass
-    raise NotSpecialised
-
 class W_SpecialisedTupleObject(W_Object):
     from pypy.objspace.std.tupletype import tuple_typedef as typedef
     __slots__ = []
 
+    def __repr__(self):
+        """ representation for debugging purposes """
+        reprlist = [repr(item) for item in self._to_unwrapped_list()]
+        return "%s(%s)" % (self.__class__.__name__, ', '.join(reprlist))
+
     def tolist(self):
         raise NotImplementedError
 
-    def _tolistunwrapped(self):
+    def _to_unwrapped_list(self):
+        "NOT_RPYTHON"
         raise NotImplementedError
 
     def length(self):
@@ -52,7 +44,7 @@
 
     def unwrap(self, space):
         return tuple(self._to_unwrapped_list())
-                        
+
 
 def make_specialised_class(typetuple):
     assert type(typetuple) == tuple
@@ -61,79 +53,68 @@
     iter_n = unrolling_iterable(range(nValues))
     
     class cls(W_SpecialisedTupleObject):
-        def __init__(self, space, values):
-            #print cls,cls.__class__, values
+        def __init__(self, space, *values):
+            self.space = space
             assert len(values) == nValues
             for i in iter_n:
-                if typetuple[i] != Any:
+                if typetuple[i] != object:
                     assert isinstance(values[i], typetuple[i])
-            self.space = space
+                setattr(self, 'value%s' % i, values[i])
+
+        @classmethod
+        def make(cls, space, *values_w):
+            unwrappedparams = ()
             for i in iter_n:
-                setattr(self, 'value%s' % i, values[i])
-                
-        
-        @classmethod
-        def try_specialisation(cls, space, paramlist):
-            if len(paramlist) != nValues:
-                raise NotSpecialised
-            for param,val_type in unrolling_iterable(zip(paramlist, 
typetuple)):
+                w_obj = values_w[i]
+                val_type = typetuple[i]
                 if val_type == int:
-                    if space.type(param) != space.w_int:
-                        raise NotSpecialised
+                    unwrapped = space.int_w(w_obj)
                 elif val_type == float:
-                    if space.type(param) != space.w_float:
-                        raise NotSpecialised
+                    unwrapped = space.float_w(w_obj)
                 elif val_type == str:
-                    if space.type(param) != space.w_str:
-                        raise NotSpecialised
-                elif val_type == Any:
-                    pass
+                    unwrapped = space.str_w(w_obj)
+                elif val_type == object:
+                    unwrapped = w_obj
                 else:
-                    raise NotSpecialised 
-            unwrappedparams = [None] * nValues            
-            for i in iter_n:
-                if typetuple[i] == int:
-                    unwrappedparams[i] = space.int_w(paramlist[i])
-                elif typetuple[i] == float:
-                    unwrappedparams[i] = space.float_w(paramlist[i])
-                elif typetuple[i] == str:
-                    unwrappedparams[i] = space.str_w(paramlist[i])
-                elif typetuple[i] == Any:
-                    unwrappedparams[i] = paramlist[i]
-                else:
-                    raise NotSpecialised 
-            return cls(space, unwrappedparams)
-    
+                    raise AssertionError
+                unwrappedparams += (unwrapped,)
+            return cls(space, *unwrappedparams)
+
         def length(self):
             return nValues
-    
+
         def tolist(self):
             list_w = [None] * nValues            
             for i in iter_n:
-                if typetuple[i] == Any:
-                    list_w[i] = getattr(self, 'value%s' % i)
-                else:
-                    list_w[i] = self.space.wrap(getattr(self, 'value%s' % i))
+                value = getattr(self, 'value%s' % i)
+                if typetuple[i] != object:
+                    value = self.space.wrap(value)
+                list_w[i] = value
             return list_w
-            
+
         def _to_unwrapped_list(self):
-            list_w = [None] * nValues            
+            "NOT_RPYTHON"
+            list_w = [None] * nValues
             for i in iter_n:
-                if typetuple[i] == Any:
-                    list_w[i] = space.unwrap(getattr(self, 'value%s' % i))#xxx
-                else:
-                    list_w[i] = getattr(self, 'value%s' % i)
+                value = getattr(self, 'value%s' % i)
+                if typetuple[i] == object:
+                    value = self.space.unwrap(value)
+                list_w[i] = value
             return list_w
-                        
+
         def hash(self, space):
+            # XXX duplicate logic from tupleobject.py
             mult = 1000003
             x = 0x345678
             z = 2
             for i in iter_n:
                 value = getattr(self, 'value%s' % i)
-                if typetuple[i] == Any:
-                    y = space.int_w(space.hash(value))    
-                elif typetuple[i] == float: # get correct hash for float which 
is an integer & other less frequent cases
+                if typetuple[i] == object:
+                    y = space.int_w(space.hash(value))
+                elif typetuple[i] == float:
+                    # get the correct hash for float which is an
+                    # integer & other less frequent cases
+                    from pypy.objspace.std.floatobject import _hash_float
                     y = _hash_float(space, value)
                 else:
                     y = compute_hash(value)
@@ -142,57 +123,109 @@
                 mult += 82520 + z + z
             x += 97531
             return space.wrap(intmask(x))
-    
+
         def _eq(self, w_other):
-            if not isinstance(w_other, cls): #so we will be sure we are 
comparing same types
+            if not isinstance(w_other, cls):
+                # if we are not comparing same types, give up
                 raise FailedToImplement
             for i in iter_n:
-                if typetuple[i] == Any:
-                    if not self.space.is_true(self.space.eq(getattr(self, 
'value%s' % i), getattr(w_other, 'value%s' % i))):
-                       return False
+                myval    = getattr(self,    'value%s' % i)
+                otherval = getattr(w_other, 'value%s' % i)
+                if typetuple[i] == object:
+                    if not self.space.eq_w(myval, otherval):
+                        return False
                 else:
-                   if getattr(self, 'value%s' % i) != getattr(w_other, 
'value%s' % i):
-                       return False
+                    if myval != otherval:
+                        return False
             else:
                 return True
-    
+
         def eq(self, space, w_other):
             return space.newbool(self._eq(w_other))
-    
+
         def ne(self, space, w_other):
             return space.newbool(not self._eq(w_other))
-    
-        def _compare(self, compare_op, w_other):
-            if not isinstance(w_other, cls):
-                raise FailedToImplement
-            ncmp = min(self.length(), w_other.length())
-            for i in iter_n:
-                if typetuple[i] == Any:#like space.eq on wrapped or two params?
-                    raise FailedToImplement
-                if ncmp > i:
-                    l_val = getattr(self, 'value%s' % i)
-                    r_val = getattr(w_other, 'value%s' % i)
-                    if l_val != r_val:
-                        return compare_op(l_val, r_val)
-            return compare_op(self.length(), w_other.length())
-            
+
+##        def _compare(self, compare_op, w_other):
+##            if not isinstance(w_other, cls):
+##                raise FailedToImplement
+##            ncmp = min(self.length(), w_other.length())
+##            for i in iter_n:
+##                if typetuple[i] == Any:#like space.eq on wrapped or two 
params?
+##                    raise FailedToImplement
+##                if ncmp > i:
+##                    l_val = getattr(self, 'value%s' % i)
+##                    r_val = getattr(w_other, 'value%s' % i)
+##                    if l_val != r_val:
+##                        return compare_op(l_val, r_val)
+##            return compare_op(self.length(), w_other.length())
+
         def getitem(self, index):
             for i in iter_n:
                 if index == i:
-                    if typetuple[i] == Any:
-                        return getattr(self, 'value%s' % i)
-                    else:
-                        return self.space.wrap(getattr(self, 'value%s' % i))
+                    value = getattr(self, 'value%s' % i)
+                    if typetuple[i] != object:
+                        value = self.space.wrap(value)
+                    return value
             raise IndexError
 
-    cls.__name__ = 'W_SpecialisedTupleObject' + 
''.join([t.__name__.capitalize() for t in typetuple])      
+    cls.__name__ = ('W_SpecialisedTupleObject_' +
+                    ''.join([t.__name__[0] for t in typetuple]))
     _specialisations.append(cls)
     return cls
 
-make_specialised_class((float, float))
-for _typ1 in [int, str, Any]:
-    for _typ2 in [int, str, Any]:
-        make_specialised_class((_typ1, _typ2))
+# ---------- current specialized versions ----------
+
+_specialisations = []
+Cls_ii = make_specialised_class((int, int))
+Cls_is = make_specialised_class((int, str))
+Cls_io = make_specialised_class((int, object))
+Cls_si = make_specialised_class((str, int))
+Cls_ss = make_specialised_class((str, str))
+Cls_so = make_specialised_class((str, object))
+Cls_oi = make_specialised_class((object, int))
+Cls_os = make_specialised_class((object, str))
+Cls_oo = make_specialised_class((object, object))
+Cls_ff = make_specialised_class((float, float))
+Cls_ooo = make_specialised_class((object, object, object))
+
+def makespecialisedtuple(space, list_w):
+    if len(list_w) == 2:
+        w_arg1, w_arg2 = list_w
+        w_type1 = space.type(w_arg1)
+        w_type2 = space.type(w_arg2)
+        #
+        if w_type1 is space.w_int:
+            if w_type2 is space.w_int:
+                return Cls_ii.make(space, w_arg1, w_arg2)
+            elif w_type2 is space.w_str:
+                return Cls_is.make(space, w_arg1, w_arg2)
+            else:
+                return Cls_io.make(space, w_arg1, w_arg2)
+        #
+        elif w_type1 is space.w_str:
+            if w_type2 is space.w_int:
+                return Cls_si.make(space, w_arg1, w_arg2)
+            elif w_type2 is space.w_str:
+                return Cls_ss.make(space, w_arg1, w_arg2)
+            else:
+                return Cls_so.make(space, w_arg1, w_arg2)
+        #
+        elif w_type1 is space.w_float and w_type2 is space.w_float:
+            return Cls_ff.make(space, w_arg1, w_arg2)
+        #
+        else:
+            if w_type2 is space.w_int:
+                return Cls_oi.make(space, w_arg1, w_arg2)
+            elif w_type2 is space.w_str:
+                return Cls_os.make(space, w_arg1, w_arg2)
+            else:
+                return Cls_oo.make(space, w_arg1, w_arg2)
+        #
+    elif len(list_w) == 3:
+        return Cls_ooo.make(space, list_w[0], list_w[1], list_w[2])
+    else:
+        raise NotSpecialised
 
 # ____________________________________________________________
 
@@ -224,23 +257,23 @@
         start += step
     return space.newtuple(subitems)
 
-def mul_specialisedtuple_times(space, w_tuple, w_times):
-    try:
-        times = space.getindex_w(w_times, space.w_OverflowError)
-    except OperationError, e:
-        if e.match(space, space.w_TypeError):
-            raise FailedToImplement
-        raise
-    if times == 1 and space.type(w_tuple) == space.w_tuple:
-        return w_tuple
-    items = w_tuple.tolist()
-    return space.newtuple(items * times)
+##def mul_specialisedtuple_times(space, w_tuple, w_times):
+##    try:
+##        times = space.getindex_w(w_times, space.w_OverflowError)
+##    except OperationError, e:
+##        if e.match(space, space.w_TypeError):
+##            raise FailedToImplement
+##        raise
+##    if times == 1 and space.type(w_tuple) == space.w_tuple:
+##        return w_tuple
+##    items = w_tuple.tolist()
+##    return space.newtuple(items * times)
 
-def mul__SpecialisedTuple_ANY(space, w_tuple, w_times):
-    return mul_specialisedtuple_times(space, w_tuple, w_times)
+##def mul__SpecialisedTuple_ANY(space, w_tuple, w_times):
+##    return mul_specialisedtuple_times(space, w_tuple, w_times)
 
-def mul__ANY_SpecialisedTuple(space, w_times, w_tuple):
-    return mul_specialisedtuple_times(space, w_tuple, w_times)
+##def mul__ANY_SpecialisedTuple(space, w_times, w_tuple):
+##    return mul_specialisedtuple_times(space, w_tuple, w_times)
 
 def eq__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2):
     return w_tuple1.eq(space, w_tuple2)
@@ -248,19 +281,19 @@
 def ne__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2):
     return w_tuple1.ne(space, w_tuple2)
 
-from operator import lt, le, ge, gt   
+##from operator import lt, le, ge, gt   
  
-def lt__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2):
-    return space.newbool(w_tuple1._compare(lt, w_tuple2))
+##def lt__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2):
+##    return space.newbool(w_tuple1._compare(lt, w_tuple2))
 
-def le__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2):
-    return space.newbool(w_tuple1._compare(le, w_tuple2))
+##def le__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2):
+##    return space.newbool(w_tuple1._compare(le, w_tuple2))
 
-def ge__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2):
-    return space.newbool(w_tuple1._compare(ge, w_tuple2))
+##def ge__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2):
+##    return space.newbool(w_tuple1._compare(ge, w_tuple2))
 
-def gt__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2):
-    return space.newbool(w_tuple1._compare(gt, w_tuple2))
+##def gt__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2):
+##    return space.newbool(w_tuple1._compare(gt, w_tuple2))
 
 def hash__SpecialisedTuple(space, w_tuple):
     return w_tuple.hash(space)
diff --git a/pypy/objspace/std/test/test_specialisedtupleobject.py 
b/pypy/objspace/std/test/test_specialisedtupleobject.py
--- a/pypy/objspace/std/test/test_specialisedtupleobject.py
+++ b/pypy/objspace/std/test/test_specialisedtupleobject.py
@@ -1,10 +1,10 @@
-import py
+import py, sys
 from pypy.objspace.std.tupleobject import W_TupleObject
 from pypy.objspace.std.specialisedtupleobject import W_SpecialisedTupleObject
 from pypy.objspace.std.specialisedtupleobject import _specialisations
 from pypy.interpreter.error import OperationError
 from pypy.conftest import gettestobjspace
-from pypy.objspace.std.test.test_tupleobject import AppTestW_TupleObject
+from pypy.objspace.std.test import test_tupleobject
 from pypy.interpreter import gateway
 
 
@@ -19,7 +19,7 @@
 
     def test_isspecialisedtupleobjectintint(self):
         w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)])
-        assert isinstance(w_tuple, W_SpecialisedTupleObjectIntInt)
+        assert isinstance(w_tuple, W_SpecialisedTupleObject_ii)
         
     def test_isnotspecialisedtupleobject(self):
         w_tuple = self.space.newtuple([self.space.wrap({})])
@@ -27,8 +27,8 @@
         
     def test_specialisedtupleclassname(self):
         w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)])
-        assert w_tuple.__class__.__name__ == 'W_SpecialisedTupleObjectIntInt'
-            
+        assert w_tuple.__class__.__name__ == 'W_SpecialisedTupleObject_ii'
+
     def test_hash_against_normal_tuple(self):
         N_space = gettestobjspace(**{"objspace.std.withspecialisedtuple": 
False})
         S_space = gettestobjspace(**{"objspace.std.withspecialisedtuple": 
True})
@@ -62,13 +62,17 @@
         assert len(list_w) == 1
         assert self.space.eq_w(list_w[0], self.space.wrap(5))        
 
-class AppTestW_SpecialisedTupleObject(AppTestW_TupleObject):
+class AppTestW_SpecialisedTupleObject:
 
     def setup_class(cls):
         cls.space = gettestobjspace(**{"objspace.std.withspecialisedtuple": 
True})
         def forbid_delegation(space, w_tuple):
             def delegation_forbidden():
-                raise NotImplementedError
+                # haaaack
+                if sys._getframe(2).f_code.co_name == '_mm_repr_tupleS0':
+                    return old_tolist()
+                raise NotImplementedError, w_tuple
+            old_tolist = w_tuple.tolist
             w_tuple.tolist = delegation_forbidden
             return w_tuple
         cls.w_forbid_delegation = 
cls.space.wrap(gateway.interp2app(forbid_delegation))
@@ -80,20 +84,23 @@
         return ("SpecialisedTupleObject" + expected) in r
 
     def test_createspecialisedtuple(self):
-        spec = {int: 'Int',
-                float: 'Float',
-                str: 'Str',
-                list: 'Any'}
+        spec = {int: 'i',
+                float: 'f',
+                str: 's',
+                list: 'o'}
         #
         for x in [42, 4.2, "foo", []]:
             for y in [43, 4.3, "bar", []]:
                 expected1 = spec[type(x)]
                 expected2 = spec[type(y)]
-                if (expected1 == 'Float') ^ (expected2 == 'Float'):
-                    if expected1 == 'Float': expected1 = 'Any'
-                    if expected2 == 'Float': expected2 = 'Any'
+                if (expected1 == 'f') ^ (expected2 == 'f'):
+                    if expected1 == 'f': expected1 = 'o'
+                    if expected2 == 'f': expected2 = 'o'
                 obj = (x, y)
-                assert self.isspecialised(obj, expected1 + expected2)
+                assert self.isspecialised(obj, '_' + expected1 + expected2)
+        #
+        obj = (1, 2, 3)
+        assert self.isspecialised(obj, '_ooo')
 
     def test_len(self):
         t = self.forbid_delegation((42,43))
@@ -104,31 +111,37 @@
         assert not self.isspecialised((1.5,))
 
     def test_slicing_to_specialised(self):
-        assert self.isspecialised((1, 2, 3)[0:2])   
-        assert self.isspecialised((1, '2', 3)[0:5:2])
+        t = (1, 2, 3)
+        assert self.isspecialised(t[0:2])
+        t = (1, '2', 3)
+        assert self.isspecialised(t[0:5:2])
 
     def test_adding_to_specialised(self):
-        assert self.isspecialised((1,)+(2,))
+        t = (1,)
+        assert self.isspecialised(t + (2,))
 
     def test_multiply_to_specialised(self):
-        assert self.isspecialised((1,)*2)
+        t = (1,)
+        assert self.isspecialised(t * 2)
 
     def test_slicing_from_specialised(self):
-        assert (1,2,3)[0:2:1] == (1,2)
+        t = (1, 2, 3)
+        assert t[0:2:1] == (1, 2)
 
     def test_eq_no_delegation(self):
-        a = self.forbid_delegation((1,2))
-        b = (1,2)
+        t = (1,)
+        a = self.forbid_delegation(t + (2,))
+        b = (1, 2)
         assert a == b
-        
-        c = (2,1)
+
+        c = (2, 1)
         assert not a == c
-                
+
     def test_eq_can_delegate(self):        
         a = (1,2)
         b = (1,3,2)
         assert not a == b
-         
+
         values = [2, 2L, 2.0, 1, 1L, 1.0]
         for x in values:
             for y in values:
@@ -144,11 +157,11 @@
         assert a != c
         
     def test_ordering(self):
-        a = self.forbid_delegation((1,2))
+        a = (1,2) #self.forbid_delegation((1,2)) --- code commented out
         assert a <  (2,2)    
         assert a <  (1,3)    
         assert not a <  (1,2) 
-           
+
         assert a <=  (2,2)    
         assert a <=  (1,2) 
         assert not a <=  (1,1) 
@@ -160,15 +173,34 @@
         assert a > (0,2)    
         assert a > (1,1)    
         assert not a > (1,3)    
+
+        assert (2,2) > a
+        assert (1,3) > a
+        assert not (1,2) > a
+           
+        assert (2,2) >= a
+        assert (1,2) >= a
+        assert not (1,1) >= a
+           
+        assert (0,2) <= a
+        assert (1,2) <= a
+        assert not (1,3) <= a
         
+        assert (0,2) < a
+        assert (1,1) < a
+        assert not (1,3) < a
+
     def test_hash(self):
         a = (1,2)
-        b = (1,) + (2,) # else a and b refer to same constant
+        b = (1,)
+        b += (2,) # else a and b refer to same constant
         assert hash(a) == hash(b)
 
         c = (2,4)
         assert hash(a) != hash(c)
 
+        assert hash(a) == hash((1L, 2L)) == hash((1.0, 2.0)) == hash((1.0, 2L))
+
     def test_getitem(self):
         t = self.forbid_delegation((5,3))
         assert (t)[0] == 5
@@ -176,34 +208,25 @@
         assert (t)[-1] == 3
         assert (t)[-2] == 5
         raises(IndexError, "t[2]")
-        
+        raises(IndexError, "t[-3]")
+
     def test_three_tuples(self):
-        if not self.isspecialised((1,2,3)):
-            skip('3-tuples of ints are not specialised, so skip specific tests 
on them')
-        b = self.forbid_delegation((1,2,3))
+        b = self.forbid_delegation((1, 2, 3))
         c = (1,)
-        d = c + (2,3)
+        d = c + (2, 3)
         assert self.isspecialised(d)
         assert b == d
-        assert b <= d
-        
+
     def test_mongrel(self):
         a = self.forbid_delegation((1, 2.2, '333'))
-        if not self.isspecialised(a):
-            skip('my chosen kind of mixed type tuple is not specialised, so 
skip specific tests on them')
+        assert self.isspecialised(a)
         assert len(a) == 3
         assert a[0] == 1 and a[1] == 2.2 and a[2] == '333'
-        assert a == (1,) + (2.2,) + ('333',)
-        assert a < (1, 2.2, '334')
-        
-    def test_mongrel_with_any(self):
-        a = self.forbid_delegation((1, 2.2, '333',[]))
-        b = (1, 2.2) + ('333', [])
-        if not self.isspecialised(a):
-            skip('my chosen kind of mixed type tuple is not specialised, so 
skip specific tests on them')
-        assert len(a) == 4
-        assert a[0] == 1 and a[1] == 2.2 and a[2] == '333' and a[3] == []
-        assert a != (1, 2.2, '334', [])
-#        assert b == a
-#        assert a == (1,) + (2.2,) + ('333',) + ([],)
-#        assert a < (1, 2.2, '334', {})
+        b = ('333',)
+        assert a == (1, 2.2,) + b
+        assert not a != (1, 2.2) + b
+
+
+class AppTestAll(test_tupleobject.AppTestW_TupleObject):
+    def test_mul_identity(self):
+        skip("not working with specialisedtuple")
diff --git a/pypy/objspace/std/test/test_tupleobject.py 
b/pypy/objspace/std/test/test_tupleobject.py
--- a/pypy/objspace/std/test/test_tupleobject.py
+++ b/pypy/objspace/std/test/test_tupleobject.py
@@ -280,6 +280,8 @@
         assert () * 10 == ()
         assert (5,) * 3 == (5,5,5)
         assert (5,2) * 2 == (5,2,5,2)
+
+    def test_mul_identity(self):
         t = (1,2,3)
         assert (t * 1) is t
 
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to