[pypy-commit] pypy default: merge branch refactor-pycall

rlamy noreply at buildbot.pypy.org
Tue Apr 7 19:51:36 CEST 2015


Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: 
Changeset: r76737:cacbf7ed6310
Date: 2015-04-07 18:38 +0100
http://bitbucket.org/pypy/pypy/changeset/cacbf7ed6310/

Log:	merge branch refactor-pycall

diff --git a/rpython/annotator/annrpython.py b/rpython/annotator/annrpython.py
--- a/rpython/annotator/annrpython.py
+++ b/rpython/annotator/annrpython.py
@@ -10,7 +10,6 @@
     Variable, Constant, FunctionGraph, checkgraph)
 from rpython.translator import simplify, transform
 from rpython.annotator import model as annmodel, signature
-from rpython.annotator.argument import simple_args
 from rpython.annotator.bookkeeper import Bookkeeper
 from rpython.rtyper.normalizecalls import perform_normalizations
 
@@ -91,22 +90,14 @@
 
     def get_call_parameters(self, function, args_s, policy):
         desc = self.bookkeeper.getdesc(function)
-        args = simple_args(args_s)
-        result = []
-        def schedule(graph, inputcells):
-            result.append((graph, inputcells))
-            return annmodel.s_ImpossibleValue
-
         prevpolicy = self.policy
         self.policy = policy
         self.bookkeeper.enter(None)
         try:
-            desc.pycall(schedule, args, annmodel.s_ImpossibleValue)
+            return desc.get_call_parameters(args_s)
         finally:
             self.bookkeeper.leave()
             self.policy = prevpolicy
-        [(graph, inputcells)] = result
-        return graph, inputcells
 
     def annotate_helper(self, function, args_s, policy=None):
         if policy is None:
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/description.py b/rpython/annotator/description.py
--- a/rpython/annotator/description.py
+++ b/rpython/annotator/description.py
@@ -1,13 +1,14 @@
 from __future__ import absolute_import
 import types
 from rpython.annotator.signature import (
-    enforce_signature_args, enforce_signature_return)
+    enforce_signature_args, enforce_signature_return, finish_type)
 from rpython.flowspace.model import Constant, FunctionGraph
 from rpython.flowspace.bytecode import cpython_code_signature
-from rpython.annotator.argument import rawshape, ArgErr
+from rpython.annotator.argument import rawshape, ArgErr, simple_args
 from rpython.tool.sourcetools import valid_identifier, func_with_new_name
 from rpython.tool.pairtype import extendabletype
-from rpython.annotator.model import AnnotatorError, SomeInteger, SomeString
+from rpython.annotator.model import (
+    AnnotatorError, SomeInteger, SomeString, s_ImpossibleValue)
 
 class CallFamily(object):
     """A family of Desc objects that could be called from common call sites.
@@ -75,7 +76,6 @@
         try:
             return self.attrs[attrname]
         except KeyError:
-            from rpython.annotator.model import s_ImpossibleValue
             return s_ImpossibleValue
 
     def set_s_value(self, attrname, s_value):
@@ -97,7 +97,6 @@
     # ClassAttrFamily is more precise: it is only about one attribut name.
 
     def __init__(self, desc):
-        from rpython.annotator.model import s_ImpossibleValue
         self.descs = {desc: True}
         self.read_locations = {}     # set of position_keys
         self.s_value = s_ImpossibleValue    # union of possible values
@@ -321,6 +320,24 @@
         result = unionof(result, s_previous_result)
         return result
 
+    def get_call_parameters(self, args_s):
+        args = simple_args(args_s)
+        inputcells = self.parse_arguments(args)
+        graph = self.specialize(inputcells)
+        assert isinstance(graph, FunctionGraph)
+        # if that graph has a different signature, we need to re-parse
+        # the arguments.
+        # recreate the args object because inputcells may have been changed
+        new_args = args.unmatch_signature(self.signature, inputcells)
+        inputcells = self.parse_arguments(new_args, graph)
+        signature = getattr(self.pyobj, '_signature_', None)
+        if signature:
+            s_result = finish_type(signature[1], self.bookkeeper, self.pyobj)
+            if s_result is not None:
+                self.bookkeeper.annotator.addpendingblock(
+                    graph, graph.returnblock, [s_result])
+        return graph, inputcells
+
     def bind_under(self, classdef, name):
         # XXX static methods
         return self.bookkeeper.getmethoddesc(self,
@@ -352,7 +369,6 @@
     @staticmethod
     def row_to_consider(descs, args, op):
         # see comments in CallFamily
-        from rpython.annotator.model import s_ImpossibleValue
         row = {}
         for desc in descs:
             def enlist(graph, ignore):
@@ -685,7 +701,6 @@
         # look up an attribute in the class
         cdesc = self.lookup(name)
         if cdesc is None:
-            from rpython.annotator.model import s_ImpossibleValue
             return s_ImpossibleValue
         else:
             # delegate to s_get_value to turn it into an annotation
@@ -999,7 +1014,6 @@
         try:
             value = self.read_attribute(attr)
         except AttributeError:
-            from rpython.annotator.model import s_ImpossibleValue
             return s_ImpossibleValue
         else:
             return self.bookkeeper.immutablevalue(value)
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]))
+
+ at op.call_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)
+
diff --git a/rpython/rtyper/normalizecalls.py b/rpython/rtyper/normalizecalls.py
--- a/rpython/rtyper/normalizecalls.py
+++ b/rpython/rtyper/normalizecalls.py
@@ -86,12 +86,7 @@
         return False   # nothing to do, all signatures already match
 
     shape_cnt, shape_keys, shape_star = shape
-    if shape_star:
-        raise TyperError(
-            "not implemented: a call is done with a '*' argument, and the"
-            " multiple functions or methods that it can go to don't have"
-            " all the same signature (different argument names or defaults)."
-            " The call can go to:\n%s" % '\n'.join(map(repr, graphs)))
+    assert not shape_star, "should have been removed at this stage"
 
     # for the first 'shape_cnt' arguments we need to generalize to
     # a common type
diff --git a/rpython/rtyper/rbuiltin.py b/rpython/rtyper/rbuiltin.py
--- a/rpython/rtyper/rbuiltin.py
+++ b/rpython/rtyper/rbuiltin.py
@@ -47,31 +47,14 @@
         # to it.
         return (self.__class__, self.methodname, id(self.s_self))
 
-def call_args_expand(hop, takes_kwds = True):
+def call_args_expand(hop):
     hop = hop.copy()
     from rpython.annotator.argument import ArgumentsForTranslation
     arguments = ArgumentsForTranslation.fromshape(
             hop.args_s[1].const, # shape
             range(hop.nb_args-2))
-    if arguments.w_stararg is not None:
-        # expand the *arg in-place -- it must be a tuple
-        from rpython.rtyper.rtuple import TupleRepr
-        if arguments.w_stararg != hop.nb_args - 3:
-            raise TyperError("call pattern too complex")
-        v_tuple = hop.args_v.pop()
-        s_tuple = hop.args_s.pop()
-        r_tuple = hop.args_r.pop()
-        if not isinstance(r_tuple, TupleRepr):
-            raise TyperError("*arg must be a tuple")
-        for i in range(len(r_tuple.items_r)):
-            v_item = r_tuple.getitem_internal(hop.llops, v_tuple, i)
-            hop.args_v.append(v_item)
-            hop.args_s.append(s_tuple.items[i])
-            hop.args_r.append(r_tuple.items_r[i])
-
+    assert arguments.w_stararg is None
     keywords = arguments.keywords
-    if not takes_kwds and keywords:
-        raise TyperError("kwds args not supported")
     # prefix keyword arguments with 'i_'
     kwds_i = {}
     for key in keywords:
diff --git a/rpython/rtyper/rptr.py b/rpython/rtyper/rptr.py
--- a/rpython/rtyper/rptr.py
+++ b/rpython/rtyper/rptr.py
@@ -1,4 +1,3 @@
-from rpython.annotator import model as annmodel
 from rpython.rtyper.llannotation import (
     SomePtr, SomeInteriorPtr, SomeLLADTMeth, lltype_to_annotation)
 from rpython.flowspace import model as flowmodel
@@ -107,11 +106,7 @@
                          resulttype = self.lowleveltype.TO.RESULT)
 
     def rtype_call_args(self, hop):
-        from rpython.rtyper.rbuiltin import call_args_expand
-        hop, _ = call_args_expand(hop, takes_kwds=False)
-        hop.swap_fst_snd_args()
-        hop.r_s_popfirstarg()
-        return self.rtype_simple_call(hop)
+        raise TyperError("kwds args not supported")
 
 class __extend__(pairtype(PtrRepr, PtrRepr)):
     def convert_from_to((r_ptr1, r_ptr2), v, llop):
diff --git a/rpython/rtyper/test/test_normalizecalls.py b/rpython/rtyper/test/test_normalizecalls.py
--- a/rpython/rtyper/test/test_normalizecalls.py
+++ b/rpython/rtyper/test/test_normalizecalls.py
@@ -237,25 +237,6 @@
         import re
         assert re.match(msg, excinfo.value.args[0])
 
-    def test_methods_with_named_arg_call(self):
-        class Base:
-            def fn(self, y):
-                raise NotImplementedError
-        class Sub1(Base):
-            def fn(self, y):
-                return 1 + y
-        class Sub2(Base):
-            def fn(self, x):    # different name!
-                return x - 2
-        def dummyfn(n):
-            if n == 1:
-                s = Sub1()
-            else:
-                s = Sub2()
-            return s.fn(*(n,))
-
-        py.test.raises(TyperError, self.rtype, dummyfn, [int], int)
-
 
 class PBase:
     def fn(self):


More information about the pypy-commit mailing list