[pypy-commit] pypy default: Try to clean up the construction of GcStructs with inlined fields.

arigo noreply at buildbot.pypy.org
Wed Dec 10 12:16:22 CET 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r74876:1a2817c44b28
Date: 2014-12-10 11:16 +0000
http://bitbucket.org/pypy/pypy/changeset/1a2817c44b28/

Log:	Try to clean up the construction of GcStructs with inlined fields.
	Complains e.g. on GcStructs containing inlined no-length arrays.

diff --git a/rpython/rtyper/lltypesystem/lltype.py b/rpython/rtyper/lltypesystem/lltype.py
--- a/rpython/rtyper/lltypesystem/lltype.py
+++ b/rpython/rtyper/lltypesystem/lltype.py
@@ -182,8 +182,8 @@
     def _freeze_(self):
         return True
 
-    def _inline_is_varsize(self, last):
-        return False
+    def _note_inlined_into(self, parent, first, last):
+        """Called when this type is being used inline in a container."""
 
     def _is_atomic(self):
         return False
@@ -201,8 +201,9 @@
 class ContainerType(LowLevelType):
     _adtmeths = {}
 
-    def _inline_is_varsize(self, last):
-        raise TypeError("%r cannot be inlined in structure" % self)
+    def _note_inlined_into(self, parent, first, last):
+        raise TypeError("%r cannot be inlined in %r" % (
+            self.__class__.__name__, parent.__class__.__name__))
 
     def _install_extras(self, adtmeths={}, hints={}):
         self._adtmeths = frozendict(adtmeths)
@@ -279,11 +280,13 @@
 
         # look if we have an inlined variable-sized array as the last field
         if fields:
+            first = True
             for name, typ in fields[:-1]:
-                typ._inline_is_varsize(False)
+                typ._note_inlined_into(self, first=first, last=False)
                 first = False
             name, typ = fields[-1]
-            if typ._inline_is_varsize(True):
+            typ._note_inlined_into(self, first=first, last=True)
+            if typ._is_varsize():
                 self._arrayfld = name
         self._flds = frozendict(flds)
         self._names = tuple(names)
@@ -299,11 +302,14 @@
                 return first, FIRSTTYPE
         return None, None
 
-    def _inline_is_varsize(self, last):
-        if self._arrayfld:
+    def _note_inlined_into(self, parent, first, last):
+        if self._arrayfld is not None:
             raise TypeError("cannot inline a var-sized struct "
                             "inside another container")
-        return False
+        if self._gckind == 'gc':
+            if not first or not isinstance(parent, GcStruct):
+                raise TypeError("a GcStruct can only be inlined as the first "
+                                "field of another GcStruct")
 
     def _is_atomic(self):
         for typ in self._flds.values():
@@ -428,15 +434,18 @@
         if isinstance(self.OF, ContainerType) and self.OF._gckind != 'raw':
             raise TypeError("cannot have a %s container as array item type"
                             % (self.OF._gckind,))
-        self.OF._inline_is_varsize(False)
+        self.OF._note_inlined_into(self, first=False, last=False)
 
         self._install_extras(**kwds)
 
-    def _inline_is_varsize(self, last):
-        if not last:
+    def _note_inlined_into(self, parent, first, last):
+        if not last or not isinstance(parent, Struct):
             raise TypeError("cannot inline an array in another container"
                             " unless as the last field of a structure")
-        return True
+        if self._gckind == 'gc':
+            raise TypeError("cannot inline a GC array inside a structure")
+        if parent._gckind == 'gc' and self._hints.get('nolength', False):
+            raise TypeError("cannot inline a no-length array inside a GcStruct")
 
     def _is_atomic(self):
         return self.OF._is_atomic()
@@ -474,9 +483,6 @@
 
 class GcArray(Array):
     _gckind = 'gc'
-    def _inline_is_varsize(self, last):
-        raise TypeError("cannot inline a GC array inside a structure")
-
 
 class FixedSizeArray(Struct):
     # behaves more or less like a Struct with fields item0, item1, ...
@@ -508,7 +514,7 @@
         if isinstance(self.OF, ContainerType) and self.OF._gckind != 'raw':
             raise TypeError("cannot have a %s container as array item type"
                             % (self.OF._gckind,))
-        self.OF._inline_is_varsize(False)
+        self.OF._note_inlined_into(self, first=False, last=False)
 
     def _str_fields(self):
         return str(self.OF)
@@ -579,8 +585,11 @@
     def __str__(self):
         return "%s (opaque)" % self.tag
 
-    def _inline_is_varsize(self, last):
-        return False    # OpaqueType can be inlined
+    def _note_inlined_into(self, parent, first, last):
+        # OpaqueType can be inlined, but not GcOpaqueType
+        if self._gckind == 'gc':
+            raise TypeError("%r cannot be inlined in %r" % (
+                self.__class__.__name__, parent.__class__.__name__))
 
     def _container_example(self):
         return _opaque(self)
@@ -599,10 +608,6 @@
     def __str__(self):
         return "%s (gcopaque)" % self.tag
 
-    def _inline_is_varsize(self, last):
-        raise TypeError("%r cannot be inlined in structure" % self)
-
-
 class ForwardReference(ContainerType):
     _gckind = 'raw'
     def become(self, realcontainertype):
diff --git a/rpython/rtyper/lltypesystem/test/test_lltype.py b/rpython/rtyper/lltypesystem/test/test_lltype.py
--- a/rpython/rtyper/lltypesystem/test/test_lltype.py
+++ b/rpython/rtyper/lltypesystem/test/test_lltype.py
@@ -808,6 +808,20 @@
     assert F.RESULT == Signed
     assert F.ARGS == (Signed,)
 
+def test_cannot_inline_random_stuff_in_gcstruct():
+    S = GcStruct('S')
+    GcStruct('X', ('a', S))    # works
+    py.test.raises(TypeError, GcStruct, 'X', ('a', Signed), ('b', S))
+    GcStruct('X', ('a', Array(Signed)))   # works
+    py.test.raises(TypeError, GcStruct, 'X', ('a', Array(Signed)),
+                                             ('b', Signed))
+    Struct('X', ('a', Array(Signed, hints={'nolength': True})))   # works
+    py.test.raises(TypeError, GcStruct, 'X',
+                   ('a', Array(Signed, hints={'nolength': True})))
+    GcStruct('X', ('a', OpaqueType('foo')))   # works
+    py.test.raises(TypeError, GcStruct, 'X', ('a', GcOpaqueType('foo')))
+
+
 class TestTrackAllocation:
     def test_automatic_tracking(self):
         # calls to start_tracking_allocations/stop_tracking_allocations


More information about the pypy-commit mailing list