[pypy-svn] pypy default: Change the definition of "_immutable_ = True" to be explicitly

arigo commits-noreply at bitbucket.org
Wed Feb 23 22:54:43 CET 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r42247:72ff127c6643
Date: 2011-02-23 22:52 +0100
http://bitbucket.org/pypy/pypy/changeset/72ff127c6643/

Log:	Change the definition of "_immutable_ = True" to be explicitly
	required on all subclasses when we put it on a class. Previously, we
	got this effect implicitly. However, it made an obscure bug that
	took me three days to locate: app-level subclasses of the immutable
	built-in types, like 'long', have their fields flagged as immutable
	too, including the 'storage' from the mapdict, which is nonsense.

diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py
--- a/pypy/objspace/std/unicodeobject.py
+++ b/pypy/objspace/std/unicodeobject.py
@@ -21,7 +21,7 @@
 
 class W_UnicodeObject(W_Object):
     from pypy.objspace.std.unicodetype import unicode_typedef as typedef
-    _immutable_ = True
+    _immutable_fields_ = ['_value']
 
     def __init__(w_self, unistr):
         assert isinstance(unistr, unicode)

diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -563,7 +563,7 @@
 
 class StaticMethod(Wrappable):
     """The staticmethod objects."""
-    _immutable_ = True
+    _immutable_fields_ = ['w_function']
 
     def __init__(self, w_function):
         self.w_function = w_function
@@ -577,7 +577,7 @@
 
 class ClassMethod(Wrappable):
     """The classmethod objects."""
-    _immutable_ = True
+    _immutable_fields_ = ['w_function']
 
     def __init__(self, w_function):
         self.w_function = w_function

diff --git a/pypy/objspace/std/intobject.py b/pypy/objspace/std/intobject.py
--- a/pypy/objspace/std/intobject.py
+++ b/pypy/objspace/std/intobject.py
@@ -17,9 +17,8 @@
 
 class W_IntObject(W_Object):
     __slots__ = 'intval'
+    _immutable_fields_ = ['intval']
 
-    _immutable_ = True
-    
     from pypy.objspace.std.inttype import int_typedef as typedef
     
     def __init__(w_self, intval):

diff --git a/pypy/objspace/std/complexobject.py b/pypy/objspace/std/complexobject.py
--- a/pypy/objspace/std/complexobject.py
+++ b/pypy/objspace/std/complexobject.py
@@ -14,7 +14,7 @@
     """This is a reimplementation of the CPython "PyComplexObject"
     """
     from pypy.objspace.std.complextype import complex_typedef as typedef
-    _immutable_ = True
+    _immutable_fields_ = ['realval', 'imagval']
 
     def __init__(w_self, realval=0.0, imgval=0.0):
         w_self.realval = float(realval)

diff --git a/pypy/objspace/std/smalllongobject.py b/pypy/objspace/std/smalllongobject.py
--- a/pypy/objspace/std/smalllongobject.py
+++ b/pypy/objspace/std/smalllongobject.py
@@ -19,7 +19,7 @@
 
 class W_SmallLongObject(W_Object):
     from pypy.objspace.std.longtype import long_typedef as typedef
-    _immutable_ = True
+    _immutable_fields_ = ['longlong']
 
     def __init__(w_self, value):
         assert isinstance(value, r_longlong)

diff --git a/pypy/objspace/std/ropeunicodeobject.py b/pypy/objspace/std/ropeunicodeobject.py
--- a/pypy/objspace/std/ropeunicodeobject.py
+++ b/pypy/objspace/std/ropeunicodeobject.py
@@ -78,7 +78,7 @@
 
 class W_RopeUnicodeObject(W_Object):
     from pypy.objspace.std.unicodetype import unicode_typedef as typedef
-    _immutable_ = True
+    _immutable_fields_ = ['_node']
 
     def __init__(w_self, node):
         w_self._node = node

diff --git a/pypy/objspace/std/longobject.py b/pypy/objspace/std/longobject.py
--- a/pypy/objspace/std/longobject.py
+++ b/pypy/objspace/std/longobject.py
@@ -11,7 +11,7 @@
 class W_LongObject(W_Object):
     """This is a wrapper of rbigint."""
     from pypy.objspace.std.longtype import long_typedef as typedef
-    _immutable_ = True
+    _immutable_fields_ = ['num']
 
     def __init__(w_self, l):
         w_self.num = l # instance of rbigint

diff --git a/pypy/rpython/rclass.py b/pypy/rpython/rclass.py
--- a/pypy/rpython/rclass.py
+++ b/pypy/rpython/rclass.py
@@ -158,7 +158,13 @@
         pass
 
     def _check_for_immutable_hints(self, hints):
-        if self.classdef.classdesc.lookup('_immutable_') is not None:
+        loc = self.classdef.classdesc.lookup('_immutable_')
+        if loc is not None:
+            if loc is not self.classdef.classdesc:
+                raise ImmutableConflictError(
+                    "class %r inherits from its parent _immutable_=True, "
+                    "so it should also declare _immutable_=True" % (
+                    self.classdef,))
             hints = hints.copy()
             hints['immutable'] = True
         self.immutable_field_list = []  # unless overwritten below

diff --git a/pypy/objspace/std/ropeobject.py b/pypy/objspace/std/ropeobject.py
--- a/pypy/objspace/std/ropeobject.py
+++ b/pypy/objspace/std/ropeobject.py
@@ -21,7 +21,7 @@
 
 class W_RopeObject(W_Object):
     from pypy.objspace.std.stringtype import str_typedef as typedef
-    _immutable_ = True
+    _immutable_fields_ = ['_node']
 
     def __init__(w_self, node):
         if not we_are_translated():

diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py
--- a/pypy/objspace/std/stringobject.py
+++ b/pypy/objspace/std/stringobject.py
@@ -21,7 +21,7 @@
 
 class W_StringObject(W_Object):
     from pypy.objspace.std.stringtype import str_typedef as typedef
-    _immutable_ = True
+    _immutable_fields_ = ['_value']
 
     def __init__(w_self, str):
         w_self._value = str

diff --git a/pypy/rpython/test/test_rclass.py b/pypy/rpython/test/test_rclass.py
--- a/pypy/rpython/test/test_rclass.py
+++ b/pypy/rpython/test/test_rclass.py
@@ -853,17 +853,17 @@
                accessor.fields == {"ov" : ""} # for ootype
 
     def test_immutable_subclass_1(self):
+        from pypy.rpython.rclass import ImmutableConflictError
         from pypy.jit.metainterp.typesystem import deref
         class A(object):
             _immutable_ = True
         class B(A):
             pass
         def f():
+            A()
             B().v = 123
             return B()
-        t, typer, graph = self.gengraph(f, [])
-        B_TYPE = deref(graph.getreturnvar().concretetype)
-        assert B_TYPE._hints["immutable"]    # inherited from A
+        py.test.raises(ImmutableConflictError, self.gengraph, f, [])
 
     def test_immutable_subclass_2(self):
         from pypy.jit.metainterp.typesystem import deref
@@ -872,6 +872,7 @@
         class B(A):
             _immutable_ = True
         def f():
+            A()
             B().v = 123
             return B()
         t, typer, graph = self.gengraph(f, [])

diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py
--- a/pypy/objspace/std/floatobject.py
+++ b/pypy/objspace/std/floatobject.py
@@ -25,7 +25,7 @@
        it is assumed that the constructor takes a real Python float as
        an argument"""
     from pypy.objspace.std.floattype import float_typedef as typedef
-    _immutable_ = True
+    _immutable_fields_ = ['floatval']
 
     def __init__(w_self, floatval):
         w_self.floatval = floatval

diff --git a/pypy/objspace/std/sliceobject.py b/pypy/objspace/std/sliceobject.py
--- a/pypy/objspace/std/sliceobject.py
+++ b/pypy/objspace/std/sliceobject.py
@@ -8,7 +8,7 @@
 
 class W_SliceObject(W_Object):
     from pypy.objspace.std.slicetype import slice_typedef as typedef
-    _immutable_ = True
+    _immutable_fields_ = ['w_start', 'w_stop', 'w_step']
 
     def __init__(w_self, w_start, w_stop, w_step):
         assert w_start is not None


More information about the Pypy-commit mailing list