Commits

Carl Friedrich Bolz committed 86204e9

try to produce better error messages for the scary
"assert nshapes == 1, "XXX call table too complex"

Comments (0)

Files changed (2)

pypy/rpython/normalizecalls.py

                                                               row)
             if did_something:
                 assert not callfamily.normalized, "change in call family normalisation"
-                assert nshapes == 1, "XXX call table too complex"
+                if nshapes != 1:
+                    raise_call_table_too_complex_error(callfamily, annotator)
     while True: 
         progress = False
         for shape, table in callfamily.calltables.items():
             return   # done
         assert not callfamily.normalized, "change in call family normalisation"
 
+def raise_call_table_too_complex_error(callfamily, annotator):
+    msg = []
+    items = callfamily.calltables.items()
+    for i, (shape1, table1) in enumerate(items):
+        for shape2, table2 in items[i + 1:]:
+            if shape1 == shape2:
+                continue
+            row1 = table1[0]
+            row2 = table2[0]
+            problematic_function_graphs = set(row1.values()).union(set(row2.values()))
+            pfg = [str(graph) for graph in problematic_function_graphs]
+            pfg.sort()
+            msg.append("the following functions:")
+            msg.append("    %s" % ("\n    ".join(pfg), ))
+            msg.append("are called with inconsistent numbers of arguments")
+            if shape1[0] != shape2[0]:
+                msg.append("sometimes with %s arguments, sometimes with %s" % (shape1[0], shape2[0]))
+            else:
+                pass # XXX better message in this case
+            callers = []
+            msg.append("the callers of these functions are:")
+            for tag, (caller, callee) in annotator.translator.callgraph.iteritems():
+                if callee not in problematic_function_graphs:
+                    continue
+                if str(caller) in callers:
+                    continue
+                callers.append(str(caller))
+            callers.sort()
+            for caller in callers:
+                msg.append("    %s" % (caller, ))
+    raise TyperError("\n".join(msg))
+
 def normalize_calltable_row_signature(annotator, shape, row):
     graphs = row.values()
     assert graphs, "no graph??"

pypy/rpython/test/test_normalizecalls.py

 from pypy.annotation import model as annmodel
 from pypy.translator.translator import TranslationContext, graphof
 from pypy.rpython.llinterp import LLInterpreter
+from pypy.rpython.error import TyperError
 from pypy.rpython.test.test_llinterp import interpret
 from pypy.rpython.lltypesystem import lltype
 from pypy.rpython.normalizecalls import TotalOrderSymbolic, MAX
         res = llinterp.eval_graph(graphof(translator, dummyfn), [2])
         assert res == -2
 
+    def test_methods_with_defaults(self):
+        class Base:
+            def fn(self):
+                raise NotImplementedError
+        class Sub1(Base):
+            def fn(self, x=1):
+                return 1 + x
+        class Sub2(Base):
+            def fn(self):
+                return -2
+        def otherfunc(x):
+            return x.fn()
+        def dummyfn(n):
+            if n == 1:
+                x = Sub1()
+                n = x.fn(2)
+            else:
+                x = Sub2()
+            return otherfunc(x) + x.fn()
+
+        excinfo = py.test.raises(TyperError, "self.rtype(dummyfn, [int], int)")
+        msg = """the following functions:
+    .+Base.fn
+    .+Sub1.fn
+    .+Sub2.fn
+are called with inconsistent numbers of arguments
+sometimes with 2 arguments, sometimes with 1
+the callers of these functions are:
+    .+otherfunc
+    .+dummyfn"""
+        import re
+        assert re.match(msg, excinfo.value.args[0])
+
 
 class PBase:
     def fn(self):