Author: fijal
Branch: rpython-20
Changeset: r93046:5f87d65c7f82
Date: 2017-11-15 19:26 +0100
http://bitbucket.org/pypy/pypy/changeset/5f87d65c7f82/
Log: start a branch to play with stronger type guarantees
diff --git a/rpython/annotator/model.py b/rpython/annotator/model.py
--- a/rpython/annotator/model.py
+++ b/rpython/annotator/model.py
@@ -47,19 +47,33 @@
allow_int_to_float = True
TLS = State()
+def compare_dict(d1, d2, ommit):
+ for k, v in d1.iteritems():
+ if k in ommit:
+ continue
+ if k not in d2 or v != d2[k]:
+ return False
+ for k, v in d2.iteritems():
+ if k in ommit:
+ continue
+ if k not in d1: # don't need to compare again
+ return False
+ return True
+
class SomeObject(object):
"""The set of all objects. Each instance stands
for an arbitrary object about which nothing is known."""
__metaclass__ = extendabletype
immutable = False
knowntype = object
+ can_union = True
def __init__(self):
assert type(self) is not SomeObject
def __eq__(self, other):
return (self.__class__ is other.__class__ and
- self.__dict__ == other.__dict__)
+ compare_dict(self.__dict__, other.__dict__, ('can_union',)))
def __ne__(self, other):
return not (self == other)
@@ -74,7 +88,7 @@
else:
reprdict[self] = True
try:
- items = self.__dict__.items()
+ items = [x for x in self.__dict__.items() if x[0] !=
'can_union']
items.sort()
args = []
for k, v in items:
@@ -269,11 +283,10 @@
d1 = self.__dict__
d2 = other.__dict__
if not TLS.check_str_without_nul:
- d1 = d1.copy()
- d1['no_nul'] = 0
- d2 = d2.copy()
- d2['no_nul'] = 0
- return d1 == d2
+ ommit = ('no_nul', 'can_union')
+ else:
+ ommit = ()
+ return compare_dict(d1, d2, ommit)
def nonnoneify(self):
return self.__class__(can_be_None=False, no_nul=self.no_nul)
@@ -341,11 +354,8 @@
return False
if not self.listdef.same_as(other.listdef):
return False
- selfdic = self.__dict__.copy()
- otherdic = other.__dict__.copy()
- del selfdic['listdef']
- del otherdic['listdef']
- return selfdic == otherdic
+ return compare_dict(self.__dict__, other.__dict__,
+ ('listdef', 'can_union'))
def can_be_none(self):
return True
@@ -383,11 +393,8 @@
return False
if not self.dictdef.same_as(other.dictdef):
return False
- selfdic = self.__dict__.copy()
- otherdic = other.__dict__.copy()
- del selfdic['dictdef']
- del otherdic['dictdef']
- return selfdic == otherdic
+ return compare_dict(self.__dict__, other.__dict__,
+ ('dictdef', 'can_union'))
def can_be_none(self):
return True
@@ -755,8 +762,15 @@
if s1 == s2:
# Most pair(...).union() methods deal incorrectly with that case
# when constants are involved.
- return s1
- return pair(s1, s2).union()
+ r = s1
+ else:
+ r = pair(s1, s2).union()
+ if not s1.can_union and not s1 == r:
+ raise AnnotatorError("Merging %s and %s forbidden" % (s2, s1))
+ if not s2.can_union and not s2 == r:
+ raise AnnotatorError("Merging %s and %s forbidden" % (s1, s2))
+ return r
+
finally:
TLS.no_side_effects_in_union -= 1
@@ -773,6 +787,17 @@
# See comment in union() above
if s1 != s2:
s1 = pair(s1, s2).union()
+ for i, s in enumerate(somevalues):
+ if not s.can_union and not s == s1:
+ l = []
+ for j, _s in enumerate(somevalues):
+ if i == j:
+ l.append("* " + repr(_s))
+ else:
+ l.append(" " + repr(_s))
+ allargs = "\n".join(l)
+ raise AnnotatorError("Merging:\n%s\nwill produce %s, * marks
strict"
+ " which cannot be generalized" % (allargs, s1))
return s1
diff --git a/rpython/annotator/test/test_strongly_typed.py
b/rpython/annotator/test/test_strongly_typed.py
new file mode 100644
--- /dev/null
+++ b/rpython/annotator/test/test_strongly_typed.py
@@ -0,0 +1,40 @@
+
+import py
+
+from rpython.conftest import option
+
+from rpython.annotator import model
+from rpython.annotator.annrpython import RPythonAnnotator as _RPythonAnnotator
+
+
+class TestAnnotateTestCase:
+ class RPythonAnnotator(_RPythonAnnotator):
+ def build_types(self, *args):
+ s = _RPythonAnnotator.build_types(self, *args)
+ self.validate()
+ if option.view:
+ self.translator.view()
+ return s
+
+ def build_types(self, func, types):
+ a = self.RPythonAnnotator()
+ return a.build_types(func, types)
+
+ def test_simple(self):
+ def f(a):
+ return a
+
+ s = model.SomeInteger()
+ s.can_union = False
+ self.build_types(f, [s])
+ assert s == model.SomeInteger()
+
+ def test_generalize_boom(self):
+ def f(i):
+ if i % 15 == 0:
+ return f(1.5)
+ return i
+
+ s = model.SomeInteger()
+ s.can_union = False
+ py.test.raises(model.AnnotatorError, self.build_types, f, [s])
diff --git a/rpython/doc/signatures.rst b/rpython/doc/signatures.rst
new file mode 100644
--- /dev/null
+++ b/rpython/doc/signatures.rst
@@ -0,0 +1,54 @@
+
+Basic types::
+
+ int - signed machine size integer
+ r_uint - unsigned machine size integer
+ r_long/r_ulong/r_longlong/r_ulonglong - various integers
+ char - single character (byte)
+ bytes - immutable array of chars
+ bytes? - nullable bytes
+ float - double-sized IEEE floating point
+
+Low level types:
+
+ ll.UCHAR
+ ll.INT
+ ...
+ ll.Array(xxx)
+ ll.Struct(xxx)
+ ll.GcStruct(xxx)
+ ll.GcArray(xxx)
+
+Container types::
+
+ list(X) - resizable list of X
+ array(X) - non-resizable list of X
+ dict(X, Y) - dict of X keys and Y values
+ tuple(A, B, C) - tuple of 3 items, A, B, C
+ list?(X) - nullable list, array or dict
+
+Classes::
+
+ class A(object):
+ _rpython_ = """
+ class foobar.A # <- namespace declaration for type name
+
+ a: int
+ b: list(int)
+ c: array(int)
+ """
+
+PBCs::
+
+ space = rpython_pbc("space.ObjSpace", space) - registers PBC under the name
"space.ObjSpace",
+ to be used in signatures
+
+Examples of a signature::
+
+ @rpython("int -> int")
+ def f(a):
+ return a
+
+ @rpython("space.ObjSpace, int, float -> bytes")
+ def f(space, i, f):
+ return space.str_w(space.newbytes(str(i)))
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit