[pypy-commit] pypy anntype: Improve exception analysis.
rlamy
noreply at buildbot.pypy.org
Wed Nov 18 11:43:55 EST 2015
Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: anntype
Changeset: r80763:da3a7fd425fb
Date: 2015-11-18 16:44 +0000
http://bitbucket.org/pypy/pypy/changeset/da3a7fd425fb/
Log: Improve exception analysis.
Reframe except clause handling in terms of annotations.
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,8 @@
from rpython.flowspace.model import Variable, Constant, checkgraph
from rpython.translator import simplify, transform
from rpython.annotator import model as annmodel, signature
-from rpython.annotator.model import SomeTypeOf
+from rpython.annotator.model import (
+ SomeTypeOf, SomeException, s_ImpossibleValue)
from rpython.annotator.bookkeeper import Bookkeeper
from rpython.rtyper.normalizecalls import perform_normalizations
@@ -210,7 +211,7 @@
for graph in newgraphs:
v = graph.getreturnvar()
if v.annotation is None:
- self.setbinding(v, annmodel.s_ImpossibleValue)
+ self.setbinding(v, s_ImpossibleValue)
def validate(self):
"""Check that the annotation results are valid"""
@@ -282,7 +283,7 @@
except KeyError:
# the function didn't reach any return statement so far.
# (some functions actually never do, they always raise exceptions)
- return annmodel.s_ImpossibleValue
+ return s_ImpossibleValue
def reflowfromposition(self, position_key):
graph, block, index = position_key
@@ -493,15 +494,21 @@
# filter out those exceptions which cannot
# occur for this specific, typed operation.
candidates = can_only_throw
+ s_exception = SomeException(set(can_only_throw))
for link in exits:
case = link.exitcase
+ s_case = SomeException({case})
if case is None:
self.follow_link(graph, link, {})
continue
- covered = [c for c in candidates if issubclass(c, case)]
- if covered:
- self.follow_raise_link(graph, link, {})
- candidates = [c for c in candidates if c not in covered]
+ if s_exception == s_ImpossibleValue:
+ break
+ s_matching_exc = s_exception.intersection(s_case)
+ if s_matching_exc != s_ImpossibleValue:
+ self.follow_raise_link(graph, link,
+ constraints={link.last_exc_value:
+ s_matching_exc.as_SomeInstance(self.bookkeeper)})
+ s_exception = s_exception.difference(s_case)
else:
for link in exits:
if link.exitcase is None:
@@ -543,7 +550,7 @@
s_constraint = constraints[v_out]
s_out = pair(s_out, s_constraint).improve()
# ignore links that try to pass impossible values
- if s_out == annmodel.s_ImpossibleValue:
+ if s_out == s_ImpossibleValue:
ignore_link = True
s_out = self.apply_renaming(s_out, renaming)
inputs_s.append(s_out)
@@ -588,7 +595,7 @@
s_constraint = constraints[v_out]
s_out = pair(s_out, s_constraint).improve()
# ignore links that try to pass impossible values
- if s_out == annmodel.s_ImpossibleValue:
+ if s_out == s_ImpossibleValue:
ignore_link = True
s_out = self.apply_renaming(s_out, renaming)
inputs_s.append(s_out)
@@ -612,8 +619,8 @@
raise BlockedInference(self, op, -1)
resultcell = op.consider(self)
if resultcell is None:
- resultcell = annmodel.s_ImpossibleValue
- elif resultcell == annmodel.s_ImpossibleValue:
+ resultcell = s_ImpossibleValue
+ elif resultcell == s_ImpossibleValue:
raise BlockedInference(self, op, -1) # the operation cannot succeed
assert isinstance(resultcell, annmodel.SomeObject)
assert isinstance(op.result, Variable)
diff --git a/rpython/annotator/model.py b/rpython/annotator/model.py
--- a/rpython/annotator/model.py
+++ b/rpython/annotator/model.py
@@ -445,6 +445,29 @@
def noneify(self):
return SomeInstance(self.classdef, can_be_None=True)
+class SomeException(SomeObject):
+ def __init__(self, classes):
+ self.classes = classes
+
+ def intersection(self, other):
+ classes = {c for c in self.classes
+ if any(issubclass(c, c2) for c2 in other.classes)}
+ if classes:
+ return SomeException(classes)
+ else:
+ return s_ImpossibleValue
+
+ def difference(self, other):
+ classes = {c for c in self.classes
+ if not any(issubclass(c, c2) for c2 in other.classes)}
+ if classes:
+ return SomeException(classes)
+ else:
+ return s_ImpossibleValue
+
+ def as_SomeInstance(self, bk):
+ return unionof(*[bk.valueoftype(cls) for cls in self.classes])
+
class SomePBC(SomeObject):
"""Stands for a global user instance, built prior to the analysis,
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
@@ -698,6 +698,19 @@
s = a.build_types(snippet.exc_deduction_our_excs_plus_others, [])
assert isinstance(s, annmodel.SomeInteger)
+ def test_method_exception_specialization(self):
+ def f(l):
+ try:
+ return l.pop()
+ except Exception:
+ raise
+ a = self.RPythonAnnotator()
+ s = a.build_types(f, [[int]])
+ graph = graphof(a, f)
+ etype, evalue = graph.exceptblock.inputargs
+ assert evalue.annotation.classdef.shortname == 'IndexError'
+ #assert etype.const == IndexError
+
def test_operation_always_raising(self):
def operation_always_raising(n):
lst = []
More information about the pypy-commit
mailing list