Skip to content

Commit 72790ef

Browse files
committed
Also restore in finally and with blocks.
1 parent 4db57bc commit 72790ef

File tree

7 files changed

+125
-4
lines changed

7 files changed

+125
-4
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_raise-try.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,53 @@ def test_exception_restoring():
7373
assert trace == [1, 2, 3, 4, 5]
7474

7575

76+
def test_exception_restoring_finally():
77+
import sys
78+
trace = []
79+
try:
80+
try:
81+
assert sys.exc_info() == (None, None, None)
82+
trace.append(1)
83+
raise ValueError("1")
84+
except ValueError:
85+
assert sys.exc_info()[0] == ValueError
86+
trace.append(2)
87+
raise KeyError("2")
88+
finally:
89+
assert sys.exc_info()[0] == KeyError, "was: %s" % sys.exc_info()[0]
90+
trace.append(3)
91+
except KeyError:
92+
assert sys.exc_info()[0] == KeyError, "was: %s" % sys.exc_info()[0]
93+
trace.append(4)
94+
assert trace == [1, 2, 3, 4]
95+
96+
97+
def test_exception_restoring_raise_finally():
98+
import sys
99+
trace = []
100+
try:
101+
try:
102+
try:
103+
assert sys.exc_info() == (None, None, None)
104+
trace.append(1)
105+
raise ValueError("1")
106+
except ValueError:
107+
assert sys.exc_info()[0] == ValueError
108+
trace.append(2)
109+
raise KeyError("2")
110+
finally:
111+
assert sys.exc_info()[0] == KeyError, "was: %s" % sys.exc_info()[0]
112+
trace.append(3)
113+
raise TypeError
114+
finally:
115+
assert sys.exc_info()[0] == TypeError, "was: %s" % sys.exc_info()[0]
116+
trace.append(4)
117+
except TypeError:
118+
assert sys.exc_info()[0] == TypeError, "was: %s" % sys.exc_info()[0]
119+
trace.append(5)
120+
assert trace == [1, 2, 3, 4, 5]
121+
122+
76123
def test_exception_restoring_with_return():
77124
import sys
78125
trace = []
@@ -98,6 +145,6 @@ def handler():
98145
trace.append(4)
99146
raise
100147
except ValueError:
101-
assert sys.exc_info()[0] == ValueError, "IS: %s" % sys.exc_info()[0]
148+
assert sys.exc_info()[0] == ValueError
102149
trace.append(5)
103150
assert trace == [1, 2, 3, 4, 5]

graalpython/com.oracle.graal.python.test/src/tests/test_with.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,47 @@ def test_with_return_and_exception():
127127
"value: None",
128128
"a = 11",
129129
], "was: " + str(LOG3)
130+
131+
132+
def test_with_restore():
133+
import sys
134+
log = []
135+
try:
136+
log.append("raise")
137+
raise ValueError("1")
138+
except:
139+
assert sys.exc_info()[0] == ValueError
140+
with Context(log, True, False) as sample:
141+
assert sys.exc_info()[0] == ValueError
142+
log.append("with body")
143+
assert sys.exc_info()[0] == ValueError
144+
log.append("except exit")
145+
assert log == [ "raise"
146+
, "__enter__"
147+
, "with body"
148+
, "type: None"
149+
, "value: None"
150+
, "except exit"], "was: %s" % log
151+
152+
153+
def test_with_restore_raise():
154+
import sys
155+
log = []
156+
try:
157+
log.append("raise")
158+
raise ValueError("1")
159+
except:
160+
assert sys.exc_info()[0] == ValueError
161+
with Context(log, True, False) as sample:
162+
assert sys.exc_info()[0] == ValueError
163+
log.append("with body")
164+
raise TypeError
165+
log.append("INVALID")
166+
assert sys.exc_info()[0] == ValueError
167+
log.append("except exit")
168+
assert log == [ "raise"
169+
, "__enter__"
170+
, "with body"
171+
, "type: <class 'TypeError'>"
172+
, "value: "
173+
, "except exit"], "was: %s" % log

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/generator/GeneratorTryExceptNode.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import com.oracle.graal.python.runtime.exception.ExceptionHandledException;
4848
import com.oracle.graal.python.runtime.exception.PException;
4949
import com.oracle.truffle.api.frame.VirtualFrame;
50+
import com.oracle.truffle.api.nodes.ControlFlowException;
5051
import com.oracle.truffle.api.nodes.ExplodeLoop;
5152

5253
public class GeneratorTryExceptNode extends TryExceptNode implements GeneratorControlNode {
@@ -127,17 +128,19 @@ private void catchException(VirtualFrame frame, PException exception, PException
127128
// we tried and haven't found a matching except node
128129
throw exception;
129130
}
131+
getContext().setCurrentException(exceptionState);
130132
}
131133

132134
private void runExceptionHandler(VirtualFrame frame, PException exception, ExceptNode exceptNode, PException exceptionState) {
133135
try {
134136
exceptNode.executeExcept(frame, exception);
135137
} catch (ExceptionHandledException e) {
136138
return;
137-
} finally {
139+
} catch (ControlFlowException e) {
138140
// restore previous exception state, this won't happen if the except block raises an
139141
// exception
140142
getContext().setCurrentException(exceptionState);
143+
throw e;
141144
}
142145
}
143146

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/generator/GeneratorTryFinallyNode.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public GeneratorTryFinallyNode(PNode body, PNode finalbody, int finallyFlag) {
5656

5757
@Override
5858
public Object execute(VirtualFrame frame) {
59+
PException exceptionState = getContext().getCurrentException();
5960
PException exception = null;
6061
if (isActive(frame, finallyFlag)) {
6162
getFinalbody().execute(frame);
@@ -72,6 +73,7 @@ public Object execute(VirtualFrame frame) {
7273
if (exception != null) {
7374
throw exception;
7475
}
76+
getContext().setCurrentException(exceptionState);
7577
return PNone.NONE;
7678
}
7779

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/TryExceptNode.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,14 @@
4242
import com.oracle.truffle.api.interop.TruffleObject;
4343
import com.oracle.truffle.api.nodes.ControlFlowException;
4444
import com.oracle.truffle.api.nodes.ExplodeLoop;
45+
import com.oracle.truffle.api.profiles.ValueProfile;
4546

4647
public class TryExceptNode extends StatementNode implements TruffleObject {
4748
@Child private PNode body;
4849
@Children private final ExceptNode[] exceptNodes;
4950
@Child private PNode orelse;
5051
@CompilationFinal private TryExceptNodeMessageResolution.CatchesFunction catchesFunction;
52+
@CompilationFinal private ValueProfile exceptionStateProfile;
5153

5254
@CompilationFinal boolean seenException;
5355

@@ -111,17 +113,21 @@ private void catchException(VirtualFrame frame, PException exception, PException
111113
exceptNode.executeExcept(frame, exception);
112114
} catch (ExceptionHandledException e) {
113115
wasHandled = true;
114-
} finally {
116+
} catch (ControlFlowException e) {
115117
// restore previous exception state, this won't happen if the except block
116118
// raises an exception
117119
getContext().setCurrentException(exceptionState);
120+
throw e;
118121
}
119122
}
120123
}
121124
}
122125
if (!wasHandled) {
123126
throw exception;
124127
}
128+
// restore previous exception state, this won't happen if the except block
129+
// raises an exception
130+
getContext().setCurrentException(exceptionState);
125131
}
126132

127133
public PNode getBody() {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/TryFinallyNode.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@
2727

2828
import com.oracle.graal.python.builtins.objects.PNone;
2929
import com.oracle.graal.python.nodes.PNode;
30+
import com.oracle.graal.python.runtime.PythonContext;
31+
import com.oracle.graal.python.runtime.exception.PException;
3032
import com.oracle.truffle.api.frame.VirtualFrame;
33+
import com.oracle.truffle.api.nodes.ControlFlowException;
3134

3235
public class TryFinallyNode extends StatementNode {
3336

@@ -41,10 +44,24 @@ public TryFinallyNode(PNode body, PNode finalbody) {
4144

4245
@Override
4346
public Object execute(VirtualFrame frame) {
47+
PythonContext context = getContext();
48+
PException exceptionState = context.getCurrentException();
4449
try {
4550
body.execute(frame);
51+
} catch (PException e) {
52+
// any thrown Python exception is visible in the finally block
53+
context.setCurrentException(e);
54+
throw e;
4655
} finally {
47-
finalbody.execute(frame);
56+
try {
57+
finalbody.execute(frame);
58+
} catch (ControlFlowException e) {
59+
// restore
60+
context.setCurrentException(exceptionState);
61+
throw e;
62+
}
63+
// restore
64+
context.setCurrentException(exceptionState);
4865
}
4966
return PNone.NONE;
5067
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/WithNode.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ protected Object runWith(VirtualFrame frame, Object withObject,
8989
@Cached("create()") IsCallableNode isCallableNode,
9090
@Cached("create()") IsCallableNode isExitCallableNode) {
9191

92+
PException exceptionState = getContext().getCurrentException();
9293
boolean gotException = false;
9394
// CPython first looks up '__exit__
9495
Object exitCallable = exitGetter.executeObject(withObject, "__exit__");
@@ -113,6 +114,7 @@ protected Object runWith(VirtualFrame frame, Object withObject,
113114
throw raise(TypeError, "%p is not callable", exitCallable);
114115
}
115116
}
117+
getContext().setCurrentException(exceptionState);
116118
}
117119
return PNone.NONE;
118120
}

0 commit comments

Comments
 (0)