[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