[pypy-svn] r10926 - in pypy/dist/pypy: annotation objspace/flow translator translator/test

arigo at codespeak.net arigo at codespeak.net
Wed Apr 20 17:53:43 CEST 2005


Author: arigo
Date: Wed Apr 20 17:53:43 2005
New Revision: 10926

Added:
   pypy/dist/pypy/translator/test/test_annsimplifyrpython.py
      - copied unchanged from r10925, pypy/branch/canonlyraise-pypy/translator/test/test_annsimplifyrpython.py
Modified:
   pypy/dist/pypy/annotation/binaryop.py
   pypy/dist/pypy/annotation/model.py
   pypy/dist/pypy/objspace/flow/model.py
   pypy/dist/pypy/translator/ann_override.py
   pypy/dist/pypy/translator/annrpython.py
   pypy/dist/pypy/translator/test/test_annrpython.py
   pypy/dist/pypy/translator/transform.py
Log:
Merge of a small branch cleaning up what occurs with operations and functions 
that never return but always raise exceptions:

- SomeImpossibleValue(benign=True) is gone.

- a new exception CanOnlyRaise is introduced, similar to BlockedInference
    but not signalling an error.  It merely indicates that the current 
    operation (or called function) always raises.

- a new test showing the problem.

- tranform.py is more subtle about cutting off dead branches which, in this
    situation, can be the last non-exceptional links out of a block.

- test_annrpython duplicated: the copy test_annsimplifyrpython also calls
    transform.py to check the simplification going on there.



Modified: pypy/dist/pypy/annotation/binaryop.py
==============================================================================
--- pypy/dist/pypy/annotation/binaryop.py	(original)
+++ pypy/dist/pypy/annotation/binaryop.py	Wed Apr 20 17:53:43 2005
@@ -382,10 +382,6 @@
         result =  SomePBC(d)
         return result
 
-class __extend__(pairtype(SomeImpossibleValue, SomeImpossibleValue)):
-    def union((imp1, imp2)):
-        return SomeImpossibleValue(benign=imp1.benign and imp2.benign)
-
 class __extend__(pairtype(SomeImpossibleValue, SomeObject)):
     def union((imp1, obj2)):
         return obj2

Modified: pypy/dist/pypy/annotation/model.py
==============================================================================
--- pypy/dist/pypy/annotation/model.py	(original)
+++ pypy/dist/pypy/annotation/model.py	Wed Apr 20 17:53:43 2005
@@ -253,13 +253,11 @@
 class SomeImpossibleValue(SomeObject):
     """The empty set.  Instances are placeholders for objects that
     will never show up at run-time, e.g. elements of an empty list."""
-    def __init__(self, benign=False):
-        self.benign = benign
 
 
 def unionof(*somevalues):
     "The most precise SomeValue instance that contains all the values."
-    s1 = SomeImpossibleValue(benign=len(somevalues)>0)
+    s1 = SomeImpossibleValue()
     for s2 in somevalues:
         if s1 != s2:
             s1 = pair(s1, s2).union()

Modified: pypy/dist/pypy/objspace/flow/model.py
==============================================================================
--- pypy/dist/pypy/objspace/flow/model.py	(original)
+++ pypy/dist/pypy/objspace/flow/model.py	Wed Apr 20 17:53:43 2005
@@ -26,21 +26,21 @@
     def getreturnvar(self):
         return self.returnblock.inputargs[0]
 
-    def hasonlyexceptionreturns(self):
-        try:
-            return self._onlyex
-        except AttributeError: 
-            def visit(link):
-                if isinstance(link, Link):
-                    if link.target == self.returnblock: 
-                        raise ValueError(link) 
-            try:
-                traverse(visit, self)
-            except ValueError:
-                self._onlyex = False 
-            else:
-                self._onlyex = True
-            return self._onlyex 
+##    def hasonlyexceptionreturns(self):
+##        try:
+##            return self._onlyex
+##        except AttributeError: 
+##            def visit(link):
+##                if isinstance(link, Link):
+##                    if link.target == self.returnblock: 
+##                        raise ValueError(link) 
+##            try:
+##                traverse(visit, self)
+##            except ValueError:
+##                self._onlyex = False 
+##            else:
+##                self._onlyex = True
+##            return self._onlyex 
 
     def show(self):
         from pypy.translator.tool.graphpage import SingleGraphPage
@@ -332,6 +332,10 @@
                         assert isinstance(v, (Constant, Variable))
                         if isinstance(v, Variable):
                             assert v in vars
+                        else:
+                            assert v.value != last_exception
+                            assert v.value != last_exc_value
+                exc_links = {}
                 if block.exitswitch is None:
                     assert len(block.exits) <= 1
                     if block.exits:
@@ -342,16 +346,24 @@
                     assert block.exits[0].exitcase is None
                     for link in block.exits[1:]:
                         assert issubclass(link.exitcase, Exception)
+                        exc_links[link] = True
                 else:
                     assert isinstance(block.exitswitch, Variable)
                     assert block.exitswitch in vars
                 for link in block.exits:
                     assert len(link.args) == len(link.target.inputargs)
                     assert link.prevblock is block
+                    exc_link = link in exc_links
                     for v in link.args:
                         assert isinstance(v, (Constant, Variable))
                         if isinstance(v, Variable):
                             assert v in vars
+                            if exc_link:
+                                assert v != block.operations[-1].result
+                        else:
+                            if not exc_link:
+                                assert v.value != last_exception
+                                assert v.value != last_exc_value
                 vars_previous_blocks.update(vars)
 
         try:

Modified: pypy/dist/pypy/translator/ann_override.py
==============================================================================
--- pypy/dist/pypy/translator/ann_override.py	(original)
+++ pypy/dist/pypy/translator/ann_override.py	Wed Apr 20 17:53:43 2005
@@ -10,7 +10,7 @@
 from pypy.objspace.std.objspace import StdObjSpace
 
 def hole(*args):
-    return annmodel.SomeImpossibleValue(benign=True)
+    pass   # no result (similar to setattr and setitem)
 
 def ignore(*args):
     bk = getbookkeeper()

Modified: pypy/dist/pypy/translator/annrpython.py
==============================================================================
--- pypy/dist/pypy/translator/annrpython.py	(original)
+++ pypy/dist/pypy/translator/annrpython.py	Wed Apr 20 17:53:43 2005
@@ -226,13 +226,10 @@
         try:
             return self.bindings[v]
         except KeyError: 
-            # let's see if the graph only has exception returns 
-            if graph.hasonlyexceptionreturns(): 
-                # XXX for functions with exceptions what to 
-                #     do anyway? 
-                #return self.bookkeeper.immutablevalue(None)
-                return annmodel.SomeImpossibleValue(benign=True)
-            return annmodel.SomeImpossibleValue()
+            # the function didn't reach any return statement so far.
+            # (some functions actually never do, they always raise exceptions)
+            # interrupt the annotation of the caller in a 'soft' way.
+            raise CanOnlyRaise
 
     def reflowfromposition(self, position_key):
         fn, block, index = position_key
@@ -309,6 +306,8 @@
             if annmodel.DEBUG:
                 import sys
                 self.why_not_annotated[block] = sys.exc_info()
+        except CanOnlyRaise:
+            pass   # end of the block not annotated, but it's not an error
         except Exception, e:
             # hack for debug tools only
             if not hasattr(e, '__annotator_block'):
@@ -359,19 +358,32 @@
 
     def flowin(self, fn, block):
         #print 'Flowing', block, [self.binding(a) for a in block.inputargs]
-        for i in range(len(block.operations)):
-            try:
-                self.bookkeeper.enter((fn, block, i))
-                self.consider_op(block.operations[i])
-            finally:
-                self.bookkeeper.leave()
-        # dead code removal: don't follow all exits if the exitswitch is known
-        exits = block.exits
-        if isinstance(block.exitswitch, Variable):
-            s_exitswitch = self.bindings[block.exitswitch]
-            if s_exitswitch.is_constant():
-                exits = [link for link in exits
-                              if link.exitcase == s_exitswitch.const]
+        i = -1
+        try:
+            for i in range(len(block.operations)):
+                try:
+                    self.bookkeeper.enter((fn, block, i))
+                    self.consider_op(block.operations[i])
+                finally:
+                    self.bookkeeper.leave()
+        except (BlockedInference, CanOnlyRaise):
+            if (i != len(block.operations)-1 or
+                block.exitswitch != Constant(last_exception)):
+                raise
+            # this is the case where the last operation of the block can
+            # only raise an exception, which is caught by an exception
+            # handler.  we only follow the exceptional branches.
+            exits = [link for link in block.exits
+                     if link.exitcase is not None]
+        else:
+            # dead code removal: don't follow all exits if the exitswitch
+            # is known
+            exits = block.exits
+            if isinstance(block.exitswitch, Variable):
+                s_exitswitch = self.bindings[block.exitswitch]
+                if s_exitswitch.is_constant():
+                    exits = [link for link in exits
+                                  if link.exitcase == s_exitswitch.const]
         knownvars, knownvarvalue = getattr(self.bindings.get(block.exitswitch),
                                           "knowntypedata", (None, None))
         for link in exits:
@@ -430,14 +442,12 @@
         argcells = [self.binding(a) for a in op.args]
         consider_meth = getattr(self,'consider_op_'+op.opname,
                                 self.default_consider_op)
-        # because benign SomeImpossibleValues are meant to propagate without leaving
-        # dangling blocked blocks around, and because of the None case below,
         # let's be careful about avoiding propagated SomeImpossibleValues
         # to enter an op; the latter can result in violations of the
         # more general results invariant: e.g. if SomeImpossibleValue enters is_
         #  is_(SomeImpossibleValue, None) -> SomeBool
         #  is_(SomeInstance(not None), None) -> SomeBool(const=False) ...
-        # boom
+        # boom -- in the assert of setbinding()
         for arg in argcells:
             if isinstance(arg, annmodel.SomeImpossibleValue):
                 raise BlockedInference(self, info=op)
@@ -519,3 +529,10 @@
         return "<BlockedInference break_at %s %s>" %(break_at, info)
 
     __str__ = __repr__
+
+
+class CanOnlyRaise(Exception):
+    """A soft version of BlockedInference: the inference should not continue
+    in the current block, but this not necessarily an error: if the current
+    block never progresses past this point, then it means that the current
+    operation will always raise an exception at run-time."""

Modified: pypy/dist/pypy/translator/test/test_annrpython.py
==============================================================================
--- pypy/dist/pypy/translator/test/test_annrpython.py	(original)
+++ pypy/dist/pypy/translator/test/test_annrpython.py	Wed Apr 20 17:53:43 2005
@@ -3,7 +3,7 @@
 import py.test
 from pypy.tool.udir import udir
 
-from pypy.translator.annrpython import RPythonAnnotator, annmodel
+from pypy.translator.annrpython import annmodel
 from pypy.translator.translator import Translator
 from pypy.annotation.listdef import ListDef
 from pypy.annotation.dictdef import DictDef
@@ -34,6 +34,8 @@
 class TestAnnonateTestCase:
     objspacename = 'flow'
 
+    from pypy.translator.annrpython import RPythonAnnotator
+
     def make_fun(self, func):
         import inspect
         try:
@@ -64,7 +66,7 @@
         fun = FunctionGraph("f", block)
         block.operations.append(op)
         block.closeblock(Link([result], fun.returnblock))
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         a.build_types(fun, [int])
         assert a.gettype(fun.getreturnvar()) == int
 
@@ -91,7 +93,7 @@
         whileblock.operations.append(decop)
         whileblock.closeblock(Link([i], headerblock))
 
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         a.build_types(fun, [int])
         assert a.gettype(fun.getreturnvar()) == int
 
@@ -126,54 +128,54 @@
         whileblock.operations.append(decop)
         whileblock.closeblock(Link([i, sum], headerblock))
 
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         a.build_types(fun, [int])
         assert a.gettype(fun.getreturnvar()) == int
 
     def test_f_calls_g(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(f_calls_g, [int])
         # result should be an integer
         assert s.knowntype == int
 
     def test_lists(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         end_cell = a.build_types(snippet.poor_man_rev_range, [int])
         # result should be a list of integers
         assert listitem(end_cell).knowntype == int
 
     def test_factorial(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.factorial, [int])
         # result should be an integer
         assert s.knowntype == int
 
     def test_factorial2(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.factorial2, [int])
         # result should be an integer
         assert s.knowntype == int
 
     def test_build_instance(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.build_instance, [])
         # result should be a snippet.C instance
         assert s.knowntype == snippet.C
 
     def test_set_attr(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.set_attr, [])
         # result should be an integer
         assert s.knowntype == int
 
     def test_merge_setattr(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.merge_setattr, [int])
         # result should be an integer
         assert s.knowntype == int
 
     def test_inheritance1(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.inheritance1, [])
         # result should be exactly:
         assert s == annmodel.SomeTuple([
@@ -182,7 +184,7 @@
                                 ])
 
     def test_inheritance2(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet._inheritance_nonrunnable, [])
         # result should be exactly:
         assert s == annmodel.SomeTuple([
@@ -191,13 +193,13 @@
                                 ])
 
     def test_poor_man_range(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.poor_man_range, [int])
         # result should be a list of integers
         assert listitem(s).knowntype == int
 
     def test_methodcall1(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet._methodcall1, [int])
         # result should be a tuple of (C, positive_int)
         assert s.knowntype == tuple
@@ -207,7 +209,7 @@
         assert s.items[1].nonneg == True
 
     def test_classes_methodcall1(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         a.build_types(snippet._methodcall1, [int])
         # the user classes should have the following attributes:
         classes = a.bookkeeper.userclasses
@@ -219,31 +221,31 @@
 
     def DISABLED_test_knownkeysdict(self):
         # disabled, SomeDict() is now a general {s_key: s_value} dict
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.knownkeysdict, [int])
         # result should be an integer
         assert s.knowntype == int
 
     def test_generaldict(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.generaldict, [str, int, str, int])
         # result should be an integer
         assert s.knowntype == int
 
     def test_somebug1(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet._somebug1, [int])
         # result should be a built-in method
         assert isinstance(s, annmodel.SomeBuiltin)
 
     def test_with_init(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.with_init, [int])
         # result should be an integer
         assert s.knowntype == int
 
     def test_with_more_init(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.with_more_init, [int, bool])
         # the user classes should have the following attributes:
         classes = a.bookkeeper.userclasses
@@ -256,26 +258,26 @@
                           annmodel.SomeBool())
 
     def test_global_instance(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.global_instance, [])
         # currently this returns the constant 42.
         # XXX not sure this is the best behavior...
         assert s == a.bookkeeper.immutablevalue(42)
 
     def test_call_five(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.call_five, [])
         # returns should be a list of constants (= 5)
         assert listitem(s) == a.bookkeeper.immutablevalue(5)
 
     def test_call_five_six(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.call_five_six, [])
         # returns should be a list of positive integers
         assert listitem(s) == annmodel.SomeInteger(nonneg=True)
 
     def test_constant_result(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.constant_result, [])
         #a.translator.simplify()
         # must return "yadda"
@@ -292,12 +294,12 @@
         #a.translator.view()
 
     def test_call_pbc(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.call_cpbc, [])
         assert s == a.bookkeeper.immutablevalue(42)
 
     def test_flow_type_info(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.flow_type_info, [object])
         a.translator.simplify()
         a.simplify()
@@ -305,7 +307,7 @@
         assert s.knowntype == int
 
     def test_flow_type_info_2(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.flow_type_info,
                           [annmodel.SomeInteger(nonneg=True)])
         # this checks that isinstance(i, int) didn't loose the
@@ -313,19 +315,19 @@
         assert s == annmodel.SomeInteger(nonneg=True)
 
     def test_flow_usertype_info(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.flow_usertype_info, [object])
         #a.translator.view()
         assert s.knowntype == snippet.WithInit
 
     def test_flow_usertype_info2(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.flow_usertype_info, [snippet.WithMoreInit])
         #a.translator.view()
         assert s.knowntype == snippet.WithMoreInit
 
     def test_flow_identity_info(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.flow_identity_info, [object, object])
         a.translator.simplify()
         a.simplify()
@@ -333,27 +335,27 @@
         assert s == a.bookkeeper.immutablevalue((None, None))
 
     def test_mergefunctions(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.mergefunctions, [int])
         # the test is mostly that the above line hasn't blown up
         # but let's at least check *something*
         assert isinstance(s, annmodel.SomePBC)
 
     def test_func_calls_func_which_just_raises(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.funccallsex, [])
         # the test is mostly that the above line hasn't blown up
         # but let's at least check *something*
         #self.assert_(isinstance(s, SomeCallable))
 
     def test_tuple_unpack_from_const_tuple_with_different_types(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.func_arg_unpack, [])
         assert isinstance(s, annmodel.SomeInteger) 
         assert s.const == 3 
 
     def test_pbc_attr_preserved_on_instance(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.preserve_pbc_attr_on_instance, [bool])
         #a.simplify()
         #a.translator.view()
@@ -361,14 +363,14 @@
         #self.assertEquals(s.__class__, annmodel.SomeInteger) 
 
     def test_is_and_knowntype_data(self): 
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.is_and_knowntype, [bool])
         #a.simplify()
         #a.translator.view()
         assert s == a.bookkeeper.immutablevalue(None)
 
     def test_isinstance_and_knowntype_data(self): 
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         x = annmodel.SomePBC({snippet.apbc: True}) 
         s = a.build_types(snippet.isinstance_and_knowntype, [x]) 
         #a.simplify()
@@ -376,12 +378,12 @@
         assert s == x
 
     def test_somepbc_simplify(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         # this example used to trigger an AssertionError
         a.build_types(snippet.somepbc_simplify, [])
 
     def test_builtin_methods(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         iv = a.bookkeeper.immutablevalue
         # this checks that some built-in methods are really supported by
         # the annotator (it doesn't check that they operate property, though)
@@ -400,7 +402,7 @@
             assert isinstance(s_constmeth, annmodel.SomeBuiltin)
 
     def test_simple_slicing0(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.simple_slice, [list])
         g = a.translator.getflowgraph(snippet.simple_slice)
         for thing in flatten(g):
@@ -411,23 +413,23 @@
                                           annmodel.SomeSlice)
 
     def test_simple_slicing(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.simple_slice, [list])
         assert isinstance(s, annmodel.SomeList)
 
     def test_simple_iter_list(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.simple_iter, [list])
         assert isinstance(s, annmodel.SomeIterator)
         
     def test_simple_iter_dict(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         t = somedict(annmodel.SomeInteger(), annmodel.SomeInteger())
         s = a.build_types(snippet.simple_iter, [t])
         assert isinstance(s, annmodel.SomeIterator)
 
     def test_simple_zip(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         x = somelist(annmodel.SomeInteger())
         y = somelist(annmodel.SomeString())
         s = a.build_types(snippet.simple_zip, [x,y])
@@ -437,45 +439,45 @@
         assert listitem(s).items[1].knowntype == str
         
     def test_dict_copy(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         t = somedict(annmodel.SomeInteger(), annmodel.SomeInteger())
         s = a.build_types(snippet.dict_copy, [t])
         assert isinstance(dictkey(s), annmodel.SomeInteger)
         assert isinstance(dictvalue(s), annmodel.SomeInteger)
 
     def test_dict_update(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.dict_update, [int])
         assert isinstance(dictkey(s), annmodel.SomeInteger)
         assert isinstance(dictvalue(s), annmodel.SomeInteger)
 
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.dict_update, [str])
         assert not isinstance(dictkey(s), annmodel.SomeString)
         assert not isinstance(dictvalue(s), annmodel.SomeString)
 
     def test_dict_keys(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.dict_keys, [])
         assert isinstance(listitem(s), annmodel.SomeString)
 
     def test_dict_keys2(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.dict_keys2, [])
         assert not isinstance(listitem(s), annmodel.SomeString)
 
     def test_dict_values(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.dict_values, [])
         assert isinstance(listitem(s), annmodel.SomeString)
     
     def test_dict_values2(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.dict_values2, [])
         assert not isinstance(listitem(s), annmodel.SomeString)
 
     def test_dict_items(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.dict_items, [])
         assert isinstance(listitem(s), annmodel.SomeTuple)
         s_key, s_value = listitem(s).items
@@ -483,19 +485,19 @@
         assert isinstance(s_value, annmodel.SomeInteger)
 
     def test_exception_deduction(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.exception_deduction, [])
         assert isinstance(s, annmodel.SomeInstance)
         assert s.knowntype is snippet.Exc
         
     def test_exception_deduction_we_are_dumb(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.exception_deduction_we_are_dumb, [])
         assert isinstance(s, annmodel.SomeInstance)
         assert s.knowntype is snippet.Exc
         
     def test_nested_exception_deduction(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.nested_exception_deduction, [])
         assert isinstance(s, annmodel.SomeTuple)
         assert isinstance(s.items[0], annmodel.SomeInstance)
@@ -504,22 +506,33 @@
         assert s.items[1].knowntype is snippet.Exc2
 
     def test_exc_deduction_our_exc_plus_others(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.exc_deduction_our_exc_plus_others, [])
         assert isinstance(s, annmodel.SomeInteger)
 
     def test_exc_deduction_our_excs_plus_others(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.exc_deduction_our_excs_plus_others, [])
         assert isinstance(s, annmodel.SomeInteger)
 
+    def test_operation_always_raising(self):
+        def operation_always_raising(n):
+            lst = []
+            try:
+                return lst[n]
+            except IndexError:
+                return 24
+        a = self.RPythonAnnotator()
+        s = a.build_types(operation_always_raising, [int])
+        assert s == a.bookkeeper.immutablevalue(24)
+
     def test_slice_union(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.slice_union, [int])
         assert isinstance(s, annmodel.SomeSlice)
 
     def test_bltin_code_frame_confusion(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         a.build_types(snippet.bltin_code_frame_confusion,[])
         f_flowgraph = a.translator.getflowgraph(snippet.bltin_code_frame_f)
         g_flowgraph = a.translator.getflowgraph(snippet.bltin_code_frame_g)
@@ -528,7 +541,7 @@
         assert a.binding(g_flowgraph.getreturnvar()).__class__ is annmodel.SomeObject
 
     def test_bltin_code_frame_reorg(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         a.build_types(snippet.bltin_code_frame_reorg,[])
         f_flowgraph = a.translator.getflowgraph(snippet.bltin_code_frame_f)
         g_flowgraph = a.translator.getflowgraph(snippet.bltin_code_frame_g)
@@ -538,12 +551,12 @@
                           annmodel.SomeString)
 
     def test_propagation_of_fresh_instances_through_attrs(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.propagation_of_fresh_instances_through_attrs, [int])
         assert s is not None
 
     def test_propagation_of_fresh_instances_through_attrs_rec_0(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.make_r, [int])
         assert s.knowntype == snippet.R
         Rdef = a.getuserclasses()[snippet.R]
@@ -553,7 +566,7 @@
     
         
     def test_propagation_of_fresh_instances_through_attrs_rec_eo(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.make_eo, [int])
         assert s.knowntype == snippet.B
         Even_def = a.getuserclasses()[snippet.Even]
@@ -564,13 +577,13 @@
         assert listitem(Odd_def.attrs['y'].s_value).knowntype == snippet.Odd        
 
     def test_flow_rev_numbers(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.flow_rev_numbers, [])
         assert s.knowntype == int
         assert not s.is_constant() # !
 
     def test_methodcall_is_precise(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.methodcall_is_precise, [])
         classes = a.bookkeeper.userclasses
         assert 'x' not in classes[snippet.CBase].attrs
@@ -581,26 +594,26 @@
         assert s == a.bookkeeper.immutablevalue(42)
 
     def test_class_spec(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.class_spec, [])
         assert s.items[0].knowntype == int
         assert s.items[1].knowntype == str
 
     def test_exception_deduction_with_raise1(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.exception_deduction_with_raise1, [bool])
         assert isinstance(s, annmodel.SomeInstance)
         assert s.knowntype is snippet.Exc
 
 
     def test_exception_deduction_with_raise2(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.exception_deduction_with_raise2, [bool])
         assert isinstance(s, annmodel.SomeInstance)
         assert s.knowntype is snippet.Exc
 
     def test_exception_deduction_with_raise3(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.exception_deduction_with_raise3, [bool])
         assert isinstance(s, annmodel.SomeInstance)
         assert s.knowntype is snippet.Exc
@@ -612,14 +625,14 @@
             if type(x) is C:
                 return x
             raise Exception
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(f, [object])
         assert s.knowntype is C
 
     def test_ann_assert(self):
         def assert_(x):
             assert x,"XXX"
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(assert_, [])
         assert s.const is None
 
@@ -634,7 +647,7 @@
                 return 'y'
             else:
                 return None
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(f, [bool])
         assert s.knowntype == str
         assert not s.can_be_None
@@ -650,7 +663,7 @@
                 return e
             return None
 
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(f, [list])
         assert s.knowntype is LookupError
 
@@ -669,7 +682,7 @@
                 record_exc(e)
         def ann_record_exc(s_e):
             return a.bookkeeper.immutablevalue(None)
-        a = RPythonAnnotator(overrides={record_exc: ann_record_exc})
+        a = self.RPythonAnnotator(overrides={record_exc: ann_record_exc})
         s = a.build_types(f, [])
         assert s.const is None
 
@@ -682,12 +695,12 @@
                 self.called = True
                 return self.flag
         myobj = Stuff(True)
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(lambda: myobj, [])
         assert myobj.called
         assert s == annmodel.SomePBC({myobj: True})
         myobj = Stuff(False)
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(lambda: myobj, [])
         assert myobj.called
         assert s == annmodel.SomeInstance(a.bookkeeper.getclassdef(Stuff))
@@ -699,7 +712,7 @@
         c.x = c
         def f():
             return c.x
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(f, [])
         assert s.knowntype == C
 
@@ -709,33 +722,33 @@
             for i in range(n):
                 lst = [lst]
             return lst
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(f, [int])
         assert listitem(s) == s
 
     def test_harmonic(self):
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(snippet.harmonic, [int])
         assert s.knowntype == float
 
     def test_bool(self):
         def f(a,b):
             return bool(a) or bool(b)
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(f, [int,list])
         assert s.knowntype == bool
 
     def test_float(self):
         def f(n):
             return float(n)
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(f, [int])
         assert s.knowntype == float
 
     def test_r_uint(self):
         def f(n):
             return n + constant_unsigned_five
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(f, [r_uint])
         assert s == annmodel.SomeInteger(nonneg = True, unsigned = True)
 
@@ -766,7 +779,7 @@
             f2(l2, c3)
             return l1,l2
 
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(g,[])
         l1, l2 = s.items
         assert listitem(l1).knowntype == int
@@ -785,7 +798,7 @@
         assert acc1.attrs == {'v1': True, 'v2': True}
 
         assert access_sets[c1] is acc1
-        raises(KeyError, "access_sets[object()]")
+        py.test.raises(KeyError, "access_sets[object()]")
         
     def test_isinstance_usigned(self):
         from pypy.tool.rarithmetic import r_uint
@@ -794,7 +807,7 @@
         def g():
             v = r_uint(1)
             return f(v)
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(g, [])
         assert s.const == True
 
@@ -817,7 +830,7 @@
             c1 = alloc(C1)
             c2 = alloc(C2)
             return c1,c2
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(f, [])
         assert s.items[0].knowntype == C1
         assert s.items[1].knowntype == C2
@@ -831,7 +844,7 @@
         def f():
             l = [T()]
             return g(l)
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(f, [])
         assert listitem(s).knowntype == T
           
@@ -844,14 +857,14 @@
         def f():
             l = [T()]
             return g(l)
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(f, [])
         assert listitem(s).knowntype == T
 
     def test_int_str_mul(self):
         def f(x,a,b):
             return a*x+x*b
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(f, [str,int,int])
         assert s.knowntype == str
 
@@ -869,7 +882,7 @@
                 t = (2,)
             l3 = g1(t)
             return l1, l2, l3
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(f, [bool])
         assert listitem(s.items[0]) == annmodel.SomeImpossibleValue()
         assert listitem(s.items[1]).knowntype == int
@@ -885,11 +898,11 @@
             l.append(1)
             return x, bool(l)
         
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(f, [])
         assert s.const == False
 
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(g, [])
 
         assert s.items[0].knowntype == bool and not s.items[0].is_constant()
@@ -905,11 +918,11 @@
             d['a'] = 1
             return x, bool(d)
         
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(f, [])
         assert s.const == False
 
-        a = RPythonAnnotator()
+        a = self.RPythonAnnotator()
         s = a.build_types(g, [])
 
         assert s.items[0].knowntype == bool and not s.items[0].is_constant()

Modified: pypy/dist/pypy/translator/transform.py
==============================================================================
--- pypy/dist/pypy/translator/transform.py	(original)
+++ pypy/dist/pypy/translator/transform.py	Wed Apr 20 17:53:43 2005
@@ -10,6 +10,7 @@
 import types
 from pypy.objspace.flow.model import SpaceOperation
 from pypy.objspace.flow.model import Variable, Constant, Block, Link
+from pypy.objspace.flow.model import last_exception
 from pypy.translator.annrpython import CannotSimplify
 from pypy.annotation import model as annmodel
 
@@ -262,9 +263,50 @@
                 lst = list(block.exits)
                 lst.remove(link)
                 block.exits = tuple(lst)
-                if len(block.exits) == 1:
-                    block.exitswitch = None
-                    block.exits[0].exitcase = None
+                if not block.exits:
+                    # oups! cannot reach the end of this block
+                    cutoff_alwaysraising_block(self, block)
+                elif block.exitswitch != Constant(last_exception):
+                    # non-exceptional exit
+                    if len(block.exits) == 1:
+                        block.exitswitch = None
+                        block.exits[0].exitcase = None
+                else:
+                    # exceptional exit
+                    if block.exits[0].exitcase is not None:
+                        # killed the non-exceptional path!
+                        cutoff_alwaysraising_block(self, block)
+
+def cutoff_alwaysraising_block(self, block):
+    "Fix a block whose end can never be reached at run-time."
+    # search the operation that cannot succeed
+    can_succeed    = [op for op in block.operations
+                         if op.result in self.bindings]
+    cannot_succeed = [op for op in block.operations
+                         if op.result not in self.bindings]
+    n = len(can_succeed)
+    # check consistency
+    assert can_succeed == block.operations[:n]
+    assert cannot_succeed == block.operations[n:]
+    assert 0 <= n < len(block.operations)
+    # chop off the unreachable end of the block
+    del block.operations[n+1:]
+    s_impossible = annmodel.SomeImpossibleValue()
+    self.bindings[block.operations[n].result] = s_impossible
+    # insert the equivalent of 'raise SystemError'
+    # XXX no sane way to get the graph from the block!
+    fn = self.annotated[block]
+    assert fn in self.translator.flowgraphs, (
+        "Cannot find the graph that this block belong to! "
+        "fn=%r" % (fn,))
+    graph = self.translator.flowgraphs[fn]
+    c1 = Constant(SystemError)
+    c2 = Constant(SystemError(
+        "Call to %r should have raised an exception" % (fn,)))
+    errlink = Link([c1, c2], graph.exceptblock)
+    block.recloseblock(errlink)
+    # XXX do something about the annotation of the
+    #     exceptblock.inputargs
 
 
 def transform_graph(ann):



More information about the Pypy-commit mailing list