Author: Ronan Lamy <[email protected]>
Branch: refactor-pycall
Changeset: r76689:0e6061661c1e
Date: 2015-04-02 05:06 +0100
http://bitbucket.org/pypy/pypy/changeset/0e6061661c1e/

Log:    Implement *-unpacking as an online transform

        f(*(a, b, c)) should now be completely equivalent to f(a, b, c)

diff --git a/rpython/annotator/argument.py b/rpython/annotator/argument.py
--- a/rpython/annotator/argument.py
+++ b/rpython/annotator/argument.py
@@ -155,18 +155,6 @@
         keywords_w = [_kwds_w[key] for key in self.keywords]
         return ArgumentsForTranslation(args_w, dict(zip(self.keywords, 
keywords_w)))
 
-    @classmethod
-    def fromshape(cls, (shape_cnt, shape_keys, shape_star), data_w):
-        args_w = data_w[:shape_cnt]
-        p = end_keys = shape_cnt + len(shape_keys)
-        if shape_star:
-            w_star = data_w[p]
-            p += 1
-        else:
-            w_star = None
-        return cls(args_w, dict(zip(shape_keys, data_w[shape_cnt:end_keys])),
-                w_star)
-
 
 def rawshape(args):
     return args._rawshape()
diff --git a/rpython/annotator/test/test_annrpython.py 
b/rpython/annotator/test/test_annrpython.py
--- a/rpython/annotator/test/test_annrpython.py
+++ b/rpython/annotator/test/test_annrpython.py
@@ -354,6 +354,25 @@
         assert isinstance(s, annmodel.SomeInteger)
         assert s.const == 3
 
+    def test_star_unpack_list(self):
+        def g():
+            pass
+        def f(l):
+            return g(*l)
+        a = self.RPythonAnnotator()
+        with py.test.raises(annmodel.AnnotatorError):
+            a.build_types(f, [[int]])
+
+    def test_star_unpack_and_keywords(self):
+        def g(a, b, c=0, d=0):
+            return a + b + c + d
+
+        def f(a, b):
+            return g(a, *(b,), d=5)
+        a = self.RPythonAnnotator()
+        s_result = a.build_types(f, [int, int])
+        assert isinstance(s_result, annmodel.SomeInteger)
+
     def test_pbc_attr_preserved_on_instance(self):
         a = self.RPythonAnnotator()
         s = a.build_types(snippet.preserve_pbc_attr_on_instance, [bool])
diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py
--- a/rpython/annotator/unaryop.py
+++ b/rpython/annotator/unaryop.py
@@ -6,6 +6,7 @@
 
 from rpython.flowspace.operation import op
 from rpython.flowspace.model import const, Constant
+from rpython.flowspace.argument import CallSpec
 from rpython.annotator.model import (SomeObject, SomeInteger, SomeBool,
     SomeString, SomeChar, SomeList, SomeDict, SomeTuple, SomeImpossibleValue,
     SomeUnicodeCodePoint, SomeInstance, SomeBuiltin, SomeBuiltinMethod,
@@ -47,11 +48,35 @@
 
 @op.simple_call.register(SomeObject)
 def simple_call_SomeObject(annotator, func, *args):
-    return 
annotator.annotation(func).call(simple_args([annotator.annotation(arg) for arg 
in args]))
+    return annotator.annotation(func).call(
+        simple_args([annotator.annotation(arg) for arg in args]))
+
[email protected]_args.register_transform(SomeObject)
+def transform_varargs(annotator, v_func, v_shape, *data_v):
+    callspec = CallSpec.fromshape(v_shape.value, list(data_v))
+    v_vararg = callspec.w_stararg
+    if callspec.w_stararg:
+        s_vararg = annotator.annotation(callspec.w_stararg)
+        if not isinstance(s_vararg, SomeTuple):
+            raise AnnotatorError(
+                "Calls like f(..., *arg) require 'arg' to be a tuple")
+        n_items = len(s_vararg.items)
+        ops = [op.getitem(v_vararg, const(i)) for i in range(n_items)]
+        new_args = callspec.arguments_w + [hlop.result for hlop in ops]
+        if callspec.keywords:
+            newspec = CallSpec(new_args, callspec.keywords)
+            shape, data_v = newspec.flatten()
+            call_op = op.call_args(v_func, const(shape), *data_v)
+        else:
+            call_op = op.simple_call(v_func, *new_args)
+        ops.append(call_op)
+        return ops
+
 
 @op.call_args.register(SomeObject)
-def call_args(annotator, func, *args):
-    return 
annotator.annotation(func).call(complex_args([annotator.annotation(arg) for arg 
in args]))
+def call_args(annotator, func, *args_v):
+    callspec = complex_args([annotator.annotation(v_arg) for v_arg in args_v])
+    return annotator.annotation(func).call(callspec)
 
 class __extend__(SomeObject):
 
@@ -722,7 +747,7 @@
         if attr not in dct:
             continue
         obj = dct[attr]
-        if (not isinstance(obj, Constant) or 
+        if (not isinstance(obj, Constant) or
                 not isinstance(obj.value, property)):
             return
         result.append(getattr(obj.value, meth))
diff --git a/rpython/flowspace/argument.py b/rpython/flowspace/argument.py
--- a/rpython/flowspace/argument.py
+++ b/rpython/flowspace/argument.py
@@ -111,3 +111,16 @@
             return self.arguments_w
         else:
             return self.arguments_w + [const(x) for x in self.w_stararg.value]
+
+    @classmethod
+    def fromshape(cls, (shape_cnt, shape_keys, shape_star), data_w):
+        args_w = data_w[:shape_cnt]
+        p = end_keys = shape_cnt + len(shape_keys)
+        if shape_star:
+            w_star = data_w[p]
+            p += 1
+        else:
+            w_star = None
+        return cls(args_w, dict(zip(shape_keys, data_w[shape_cnt:end_keys])),
+                w_star)
+
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to