[pypy-svn] r25965 - in pypy/dist/pypy: annotation objspace/flow objspace/flow/test rpython rpython/test translator
pedronis at codespeak.net
pedronis at codespeak.net
Wed Apr 19 01:13:32 CEST 2006
Author: pedronis
Date: Wed Apr 19 01:13:26 2006
New Revision: 25965
Modified:
pypy/dist/pypy/annotation/annrpython.py
pypy/dist/pypy/annotation/binaryop.py
pypy/dist/pypy/objspace/flow/objspace.py
pypy/dist/pypy/objspace/flow/test/test_objspace.py
pypy/dist/pypy/rpython/rdict.py
pypy/dist/pypy/rpython/rtuple.py
pypy/dist/pypy/rpython/test/test_objectmodel.py
pypy/dist/pypy/rpython/test/test_rdict.py
pypy/dist/pypy/rpython/test/test_rlist.py
pypy/dist/pypy/rpython/test/test_rtuple.py
pypy/dist/pypy/translator/simplify.py
Log:
fix propagation of exception out r_dict operations.
Notice that this required having the flow space assume that getitem/setitem/delitem can raise any exceptions.
Changes with some tests at various levels to cope with this.
Notice that the pruning of excepts links when a getitem appears in an unrelated try/except is less strong as a
consequence.
Now {}[[]] fails with a TypeError as expected in a translated PyPy.
Modified: pypy/dist/pypy/annotation/annrpython.py
==============================================================================
--- pypy/dist/pypy/annotation/annrpython.py (original)
+++ pypy/dist/pypy/annotation/annrpython.py Wed Apr 19 01:13:26 2006
@@ -516,11 +516,11 @@
arg1 = self.binding(op.args[0])
arg2 = self.binding(op.args[1])
binop = getattr(pair(arg1, arg2), op.opname, None)
- can_only_throw = getattr(binop, "can_only_throw", None)
+ can_only_throw = read_can_only_throw(binop, arg1, arg2)
elif op.opname in annmodel.UNARY_OPERATIONS:
arg1 = self.binding(op.args[0])
unop = getattr(arg1, op.opname, None)
- can_only_throw = getattr(unop, "can_only_throw", None)
+ can_only_throw = read_can_only_throw(unop, arg1)
else:
can_only_throw = None
@@ -722,3 +722,9 @@
return "<BlockedInference break_at %s [%s]>" %(break_at, self.op)
__str__ = __repr__
+
+def read_can_only_throw(opimpl, *args):
+ can_only_throw = getattr(opimpl, "can_only_throw", None)
+ if can_only_throw is None or isinstance(can_only_throw, list):
+ return can_only_throw
+ return can_only_throw(*args)
Modified: pypy/dist/pypy/annotation/binaryop.py
==============================================================================
--- pypy/dist/pypy/annotation/binaryop.py (original)
+++ pypy/dist/pypy/annotation/binaryop.py Wed Apr 19 01:13:26 2006
@@ -400,22 +400,27 @@
class __extend__(pairtype(SomeDict, SomeObject)):
+ def _can_only_throw(dic1, *ignore):
+ if dic1.dictdef.dictkey.custom_eq_hash:
+ return None
+ return [KeyError]
+
def getitem((dic1, obj2)):
getbookkeeper().count("dict_getitem", dic1)
dic1.dictdef.generalize_key(obj2)
return dic1.dictdef.read_value()
- getitem.can_only_throw = [KeyError]
+ getitem.can_only_throw = _can_only_throw
def setitem((dic1, obj2), s_value):
getbookkeeper().count("dict_setitem", dic1)
dic1.dictdef.generalize_key(obj2)
dic1.dictdef.generalize_value(s_value)
- setitem.can_only_throw = [KeyError]
+ setitem.can_only_throw = _can_only_throw
def delitem((dic1, obj2)):
getbookkeeper().count("dict_delitem", dic1)
dic1.dictdef.generalize_key(obj2)
- delitem.can_only_throw = [KeyError]
+ delitem.can_only_throw = _can_only_throw
class __extend__(pairtype(SomeSlice, SomeSlice)):
Modified: pypy/dist/pypy/objspace/flow/objspace.py
==============================================================================
--- pypy/dist/pypy/objspace/flow/objspace.py (original)
+++ pypy/dist/pypy/objspace/flow/objspace.py Wed Apr 19 01:13:26 2006
@@ -460,6 +460,12 @@
int: [ValueError], # built-ins that can always raise exceptions
chr: [ValueError],
unichr: [ValueError],
+ # specifying IndexError, and KeyError beyond Exception,
+ # allows the annotator to be more precise, see test_reraiseAnything/KeyError in
+ # the annotator tests
+ 'getitem': [IndexError, KeyError, Exception],
+ 'setitem': [IndexError, KeyError, Exception],
+ 'delitem': [IndexError, KeyError, Exception],
}
def _add_exceptions(names, exc):
@@ -477,13 +483,13 @@
lis.append(OverflowError)
implicit_exceptions[name+"_ovf"] = lis
-for _err in IndexError, KeyError:
- _add_exceptions("""getitem setitem delitem""", _err)
+#for _err in IndexError, KeyError:
+# _add_exceptions("""getitem setitem delitem""", _err)
for _name in 'getattr', 'delattr':
_add_exceptions(_name, AttributeError)
for _name in 'iter', 'coerce':
_add_exceptions(_name, TypeError)
-del _name, _err
+del _name#, _err
_add_exceptions("""div mod divmod truediv floordiv pow
inplace_div inplace_mod inplace_divmod inplace_truediv
Modified: pypy/dist/pypy/objspace/flow/test/test_objspace.py
==============================================================================
--- pypy/dist/pypy/objspace/flow/test/test_objspace.py (original)
+++ pypy/dist/pypy/objspace/flow/test/test_objspace.py Wed Apr 19 01:13:26 2006
@@ -248,15 +248,32 @@
self.show(x)
#__________________________________________________________
- def implicitIndexError(lst):
+ def implicitException(lst):
try:
x = lst[5]
- except IndexError:
+ except Exception:
return 'catch'
return lst[3] # not caught
- def test_implicitIndexError(self):
- x = self.codetest(self.implicitIndexError)
+ def test_implicitException(self):
+ x = self.codetest(self.implicitException)
+ simplify_graph(x)
+ self.show(x)
+ def cannot_reach_exceptblock(link):
+ if isinstance(link, Link):
+ assert link.target is not x.exceptblock
+ traverse(cannot_reach_exceptblock, x)
+
+
+ def implicitAttributeError(x):
+ try:
+ x = getattr(x, "y")
+ except AttributeError:
+ return 'catch'
+ return getattr(x, "z") # not caught
+
+ def test_implicitAttributeError(self):
+ x = self.codetest(self.implicitAttributeError)
simplify_graph(x)
self.show(x)
def cannot_reach_exceptblock(link):
@@ -296,32 +313,72 @@
assert d == {None: True, OSError: True, Exception: True}
#__________________________________________________________
- def reraiseKeyError(dic):
+ def reraiseAttributeError(v):
+ try:
+ x = getattr(v, "y")
+ except AttributeError:
+ raise
+
+ def test_reraiseAttributeError(self):
+ x = self.codetest(self.reraiseAttributeError)
+ simplify_graph(x)
+ self.show(x)
+ found_AttributeError = []
+ def only_raise_AttributeError(link):
+ if isinstance(link, Link):
+ if link.target is x.exceptblock:
+ assert link.args[0] == Constant(AttributeError)
+ found_AttributeError.append(link)
+ traverse(only_raise_AttributeError, x)
+ assert found_AttributeError
+
+ def reraiseTypeError(dic):
try:
x = dic[5]
- except KeyError:
+ except TypeError:
raise
- def test_reraiseKeyError(self):
- x = self.codetest(self.reraiseKeyError)
+ def test_reraiseTypeError(self):
+ x = self.codetest(self.reraiseTypeError)
simplify_graph(x)
self.show(x)
- found_KeyError = []
- def only_raise_KeyError(link):
+ found = []
+ def can_reach_exceptblock(link):
if isinstance(link, Link):
if link.target is x.exceptblock:
- assert link.args[0] == Constant(KeyError)
- found_KeyError.append(link)
- traverse(only_raise_KeyError, x)
- assert found_KeyError
+ found.append(link)
+ traverse(can_reach_exceptblock, x)
+ assert found
+
#__________________________________________________________
- def reraiseAnything(dic):
+ def reraiseAnythingDicCase(dic):
try:
dic[5]
except:
raise
+ def test_reraiseAnythingDicCase(self):
+ x = self.codetest(self.reraiseAnythingDicCase)
+ simplify_graph(x)
+ self.show(x)
+ found = {}
+ def find_exceptions(link):
+ if isinstance(link, Link):
+ if link.target is x.exceptblock:
+ if isinstance(link.args[0], Constant):
+ found[link.args[0].value] = True
+ else:
+ found[link.exitcase] = None
+ traverse(find_exceptions, x)
+ assert found == {IndexError: True, KeyError: True, Exception: None}
+
+ def reraiseAnything(x):
+ try:
+ pow(x, 5)
+ except:
+ raise
+
def test_reraiseAnything(self):
x = self.codetest(self.reraiseAnything)
simplify_graph(x)
@@ -333,7 +390,7 @@
assert isinstance(link.args[0], Constant)
found[link.args[0].value] = True
traverse(find_exceptions, x)
- assert found == {KeyError: True, IndexError: True}
+ assert found == {ValueError: True, ZeroDivisionError: True, OverflowError: True}
#__________________________________________________________
def freevar(self, x):
Modified: pypy/dist/pypy/rpython/rdict.py
==============================================================================
--- pypy/dist/pypy/rpython/rdict.py (original)
+++ pypy/dist/pypy/rpython/rdict.py Wed Apr 19 01:13:26 2006
@@ -329,19 +329,25 @@
def rtype_getitem((r_dict, r_key), hop):
v_dict, v_key = hop.inputargs(r_dict, r_dict.key_repr)
- hop.has_implicit_exception(KeyError) # record that we know about it
+ if not r_dict.custom_eq_hash:
+ hop.has_implicit_exception(KeyError) # record that we know about it
hop.exception_is_here()
v_res = hop.gendirectcall(ll_dict_getitem, v_dict, v_key)
return r_dict.recast_value(hop.llops, v_res)
def rtype_delitem((r_dict, r_key), hop):
v_dict, v_key = hop.inputargs(r_dict, r_dict.key_repr)
- hop.has_implicit_exception(KeyError) # record that we know about it
+ if not r_dict.custom_eq_hash:
+ hop.has_implicit_exception(KeyError) # record that we know about it
hop.exception_is_here()
return hop.gendirectcall(ll_dict_delitem, v_dict, v_key)
def rtype_setitem((r_dict, r_key), hop):
v_dict, v_key, v_value = hop.inputargs(r_dict, r_dict.key_repr, r_dict.value_repr)
+ if r_dict.custom_eq_hash:
+ hop.exception_is_here()
+ else:
+ hop.exception_cannot_occur()
hop.gendirectcall(ll_dict_setitem, v_dict, v_key, v_value)
def rtype_contains((r_dict, r_key), hop):
Modified: pypy/dist/pypy/rpython/rtuple.py
==============================================================================
--- pypy/dist/pypy/rpython/rtuple.py (original)
+++ pypy/dist/pypy/rpython/rtuple.py Wed Apr 19 01:13:26 2006
@@ -139,6 +139,8 @@
v_tuple, v_index = hop.inputargs(r_tup, Signed)
if not isinstance(v_index, Constant):
raise TyperError("non-constant tuple index")
+ if hop.has_implicit_exception(IndexError):
+ hop.exception_cannot_occur()
index = v_index.value
v = r_tup.getitem(hop.llops, v_tuple, index)
return hop.llops.convertvar(v, r_tup.items_r[index], r_tup.external_items_r[index])
Modified: pypy/dist/pypy/rpython/test/test_objectmodel.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_objectmodel.py (original)
+++ pypy/dist/pypy/rpython/test/test_objectmodel.py Wed Apr 19 01:13:26 2006
@@ -149,19 +149,44 @@
def test_rtype_r_dict_exceptions():
def raising_hash(obj):
- if id(obj) % 2 == 0:
+ if obj.startswith("bla"):
raise TypeError
return 1
def eq(obj1, obj2):
return obj1 is obj2
def f():
d1 = r_dict(eq, raising_hash)
+ d1['xxx'] = 1
try:
x = d1["blabla"]
except Exception:
- return 1
+ return 42
return x
res = interpret(f, [])
+ assert res == 42
+
+ def f():
+ d1 = r_dict(eq, raising_hash)
+ d1['xxx'] = 1
+ try:
+ x = d1["blabla"]
+ except TypeError:
+ return 42
+ return x
+ res = interpret(f, [])
+ assert res == 42
+
+ def f():
+ d1 = r_dict(eq, raising_hash)
+ d1['xxx'] = 1
+ try:
+ d1["blabla"] = 2
+ except TypeError:
+ return 42
+ return 0
+ res = interpret(f, [])
+ assert res == 42
+
def test_rtype_keepalive():
from pypy.rpython import objectmodel
@@ -183,3 +208,36 @@
assert res == 5
+def test_access_in_try():
+ h = lambda x: 1
+ eq = lambda x,y: x==y
+ def f(d):
+ try:
+ return d[2]
+ except ZeroDivisionError:
+ return 42
+ return -1
+ def g(n):
+ d = r_dict(eq, h)
+ d[1] = n
+ d[2] = 2*n
+ return f(d)
+ res = interpret(g, [3])
+ assert res == 6
+
+def test_access_in_try_set():
+ h = lambda x: 1
+ eq = lambda x,y: x==y
+ def f(d):
+ try:
+ d[2] = 77
+ except ZeroDivisionError:
+ return 42
+ return -1
+ def g(n):
+ d = r_dict(eq, h)
+ d[1] = n
+ f(d)
+ return d[2]
+ res = interpret(g, [3])
+ assert res == 77
Modified: pypy/dist/pypy/rpython/test/test_rdict.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_rdict.py (original)
+++ pypy/dist/pypy/rpython/test/test_rdict.py Wed Apr 19 01:13:26 2006
@@ -680,3 +680,30 @@
assert res == 2
res = interpret(f, [6])
assert res == 0
+
+def test_access_in_try():
+ def f(d):
+ try:
+ return d[2]
+ except ZeroDivisionError:
+ return 42
+ return -1
+ def g(n):
+ d = {1: n, 2: 2*n}
+ return f(d)
+ res = interpret(g, [3])
+ assert res == 6
+
+def test_access_in_try_set():
+ def f(d):
+ try:
+ d[2] = 77
+ except ZeroDivisionError:
+ return 42
+ return -1
+ def g(n):
+ d = {1: n}
+ f(d)
+ return d[2]
+ res = interpret(g, [3])
+ assert res == 77
Modified: pypy/dist/pypy/rpython/test/test_rlist.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_rlist.py (original)
+++ pypy/dist/pypy/rpython/test/test_rlist.py Wed Apr 19 01:13:26 2006
@@ -1104,6 +1104,32 @@
assert r_A_list.lowleveltype == r_B_list.lowleveltype
+ def test_access_in_try(self):
+ def f(sq):
+ try:
+ return sq[2]
+ except ZeroDivisionError:
+ return 42
+ return -1
+ def g(n):
+ l = [1] * n
+ return f(l)
+ res = self.interpret(g, [3])
+ assert res == 1
+
+ def test_access_in_try_set(self):
+ def f(sq):
+ try:
+ sq[2] = 77
+ except ZeroDivisionError:
+ return 42
+ return -1
+ def g(n):
+ l = [1] * n
+ f(l)
+ return l[2]
+ res = self.interpret(g, [3])
+ assert res == 77
class TestLltypeRtyping(BaseTestListRtyping):
Modified: pypy/dist/pypy/rpython/test/test_rtuple.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_rtuple.py (original)
+++ pypy/dist/pypy/rpython/test/test_rtuple.py Wed Apr 19 01:13:26 2006
@@ -224,6 +224,18 @@
res = self.interpret(f, [0])
assert self.class_name(res) == "B"
+ def test_access_in_try(self):
+ def f(sq):
+ try:
+ return sq[2]
+ except ZeroDivisionError:
+ return 42
+ return -1
+ def g(n):
+ t = (1,2,n)
+ return f(t)
+ res = self.interpret(g, [3])
+ assert res == 3
class TestLLTuple(AbstractTestRTuple):
Modified: pypy/dist/pypy/translator/simplify.py
==============================================================================
--- pypy/dist/pypy/translator/simplify.py (original)
+++ pypy/dist/pypy/translator/simplify.py Wed Apr 19 01:13:26 2006
@@ -214,15 +214,17 @@
def visit(block):
if not (isinstance(block, Block)
- and block.exitswitch == clastexc and len(block.exits) == 2
- and block.exits[1].exitcase is Exception):
+ and block.exitswitch == clastexc
+ and block.exits[-1].exitcase is Exception):
return
+ covered = [link.exitcase for link in block.exits[1:-1]]
seen = []
- norm, exc = block.exits
+ preserve = list(block.exits[:-1])
+ exc = block.exits[-1]
last_exception = exc.last_exception
last_exc_value = exc.last_exc_value
query = exc.target
- switches = [ (None, norm) ]
+ switches = []
# collect the targets
while len(query.exits) == 2:
newrenaming = {}
@@ -238,7 +240,13 @@
lno, lyes = query.exits
assert lno.exitcase == False and lyes.exitcase == True
if case not in seen:
- switches.append( (case, lyes) )
+ is_covered = False
+ for cov in covered:
+ if issubclass(case, cov):
+ is_covered = True
+ break
+ if not is_covered:
+ switches.append( (case, lyes) )
seen.append(case)
exc = lno
query = exc.target
@@ -248,20 +256,20 @@
exits = []
for case, oldlink in switches:
link = oldlink.copy(rename)
- if case is not None:
- link.last_exception = last_exception
- link.last_exc_value = last_exc_value
- # make the above two variables unique
- renaming2 = {}
- def rename2(v):
- return renaming2.get(v, v)
- for v in link.getextravars():
- renaming2[v] = Variable(v)
- link = link.copy(rename2)
+ assert case is not None
+ link.last_exception = last_exception
+ link.last_exc_value = last_exc_value
+ # make the above two variables unique
+ renaming2 = {}
+ def rename2(v):
+ return renaming2.get(v, v)
+ for v in link.getextravars():
+ renaming2[v] = Variable(v)
+ link = link.copy(rename2)
link.exitcase = case
link.prevblock = block
exits.append(link)
- block.exits = tuple(exits)
+ block.exits = tuple(preserve + exits)
traverse(visit, graph)
More information about the Pypy-commit
mailing list