Author: Spenser Bauman <saba...@gmail.com> Branch: value-classes Changeset: r87255:7c0752bdace0 Date: 2016-09-20 12:07 -0400 http://bitbucket.org/pypy/pypy/changeset/7c0752bdace0/
Log: Start working on _value_class_ annotation diff --git a/rpython/rtyper/rclass.py b/rpython/rtyper/rclass.py --- a/rpython/rtyper/rclass.py +++ b/rpython/rtyper/rclass.py @@ -62,6 +62,9 @@ """Raised when the _immutable_ or _immutable_fields_ hints are not consistent across a class hierarchy.""" +class ValueClassConflictError(Exception): + """Raise when the _value_class_ hints are not consistent across + the class heirarchy""" def getclassrepr(rtyper, classdef): if classdef is None: @@ -517,6 +520,7 @@ if hints is None: hints = {} hints = self._check_for_immutable_hints(hints) + hints = self._check_for_value_class_hints(hints) kwds = {} if self.gcflavor == 'gc': kwds['rtti'] = True @@ -560,6 +564,38 @@ hints['immutable_fields'] = accessor return hints + def _check_for_value_class_hints(self, hints): + """Look for value class hints in the class heirarchy to extract the proper + hints and ensure consistency of the _value_class_ annotation. This is + mostly equivalent to _check_for_immutable_hints except that + _value_class_=True requires _immutable_=True as well.""" + hints = hints.copy() + classdesc = self.classdef.classdesc + value_class = classdesc.get_param('_value_class_', inherit=False) + if value_class is None: + if classdesc.get_param('_value_class_', inherit=True): + raise ValueClassConflictError( + "class %r inherits from its parent _value_class_=True, " + "so it should also declare _value_class_=True" % ( + self.classdef,)) + elif value_class is not True: + raise TyperError( + "class %r: _value_class_ = something else than True" % ( + self.classdef,)) + elif not hints.get('immutable', False): + raise ValueClassConflictError( + "class %r: _value_class_ = True requires that " + "_immutable_ = True as well") + else: + # Value classes may only be subclasses of other value classes + basedesc = classdesc.basedesc + if basedesc and not basedesc.get_param('_value_class_', False): + raise ValueClassConflictError( + "class %r: _value_class_ = True, but its parent " + "class %r does not") + hints['value_class'] = True + return hints + def __repr__(self): if self.classdef is None: clsname = 'object' diff --git a/rpython/rtyper/test/test_rclass.py b/rpython/rtyper/test/test_rclass.py --- a/rpython/rtyper/test/test_rclass.py +++ b/rpython/rtyper/test/test_rclass.py @@ -1305,3 +1305,53 @@ def f(): return a.next.next.next.next is not None assert self.interpret(f, []) == True + + def test_value_class(self): + + class I(object): + _immutable_ = True + _value_class_ = True + + def __init__(self, v): + self.v = v + + i = I(3) + def f(): + return i.v + + t, typer, graph = self.gengraph(f, [], backendopt=True) + assert summary(graph) == {} + + def test_value_class_not_immutable(self): + from rpython.rtyper.rclass import ValueClassConflictError + + class I(object): + _value_class_ = True + + def __init__(self, v): + self.v = v + + i = I(3) + def f(): + return i.v + + py.test.raises(ValueClassConflictError, self.gengraph, f, []) + + def test_value_class_subclass_not_value_class(self): + from rpython.rtyper.rclass import ValueClassConflictError + + class Base(object): + _immutable_ = True + + class I(Base): + _immutable_ = True + _value_class_ = True + + def __init__(self, v): + self.v = v + + i = I(3) + def f(): + return i.v + + py.test.raises(ValueClassConflictError, self.gengraph, f, []) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit