Skip to content

Commit d3a98e2

Browse files
committed
Support 'terminating return' opt in TryExceptNode
1 parent f082eb4 commit d3a98e2

File tree

3 files changed

+86
-5
lines changed

3 files changed

+86
-5
lines changed

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

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,58 @@ def method(v):
5151

5252
assert method(10) is None
5353
assert method("value") is None
54+
55+
def test_return_in_finally():
56+
def override_explicit():
57+
try:
58+
return 0
59+
finally:
60+
return 42
61+
62+
def override_implicit():
63+
try:
64+
pass
65+
finally:
66+
return 'correct'
67+
68+
assert override_explicit() == 42
69+
assert override_implicit() == 'correct'
70+
71+
def test_return_in_try():
72+
def basic(arg):
73+
try:
74+
if arg:
75+
raise ValueError()
76+
return 1 # can be 'terminating'
77+
except ValueError as e:
78+
return 2 # can be 'terminating'
79+
80+
assert basic(True) == 2
81+
assert basic(False) == 1
82+
83+
def with_orelse(arg):
84+
try:
85+
if arg:
86+
return 'try'
87+
except:
88+
pass
89+
else:
90+
return 'else'
91+
92+
assert with_orelse(True) == 'try'
93+
assert with_orelse(False) == 'else'
94+
95+
96+
def test_return_in_try_finally():
97+
def foo(arg):
98+
try:
99+
if arg:
100+
raise ValueError()
101+
return 'try'
102+
except ValueError as e:
103+
return 'except'
104+
finally:
105+
return 'finally'
106+
107+
assert foo(True) == 'finally'
108+
assert foo(False) == 'finally'

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ public Object returnExecute(VirtualFrame frame) {
5353
return PNone.NONE;
5454
}
5555

56+
// Helper method
57+
protected final Object genericExecute(VirtualFrame frame, boolean isReturnExecute) {
58+
if (isReturnExecute) {
59+
return returnExecute(frame);
60+
} else {
61+
executeVoid(frame);
62+
return null;
63+
}
64+
}
65+
5666
public void markAsTryBlock() {
5767
isTryBlock = true;
5868
}

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

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.util.ArrayList;
2929

3030
import com.oracle.graal.python.PythonLanguage;
31+
import com.oracle.graal.python.builtins.objects.PNone;
3132
import com.oracle.graal.python.builtins.objects.exception.PBaseException;
3233
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
3334
import com.oracle.graal.python.nodes.PNode;
@@ -86,24 +87,39 @@ public TryExceptNode(StatementNode body, ExceptNode[] exceptNodes, StatementNode
8687

8788
@Override
8889
public void executeVoid(VirtualFrame frame) {
90+
executeImpl(frame, false);
91+
}
92+
93+
@Override
94+
public Object returnExecute(VirtualFrame frame) {
95+
return executeImpl(frame, true);
96+
}
97+
98+
private Object executeImpl(VirtualFrame frame, boolean isReturn) {
8999
// The following statement is a no-op, but it helps graal to optimize the exception handler
90100
// by moving the cast to PException to the beginning
91101
saveExceptionState(frame);
92102

93103
try {
94-
body.executeVoid(frame);
104+
if (isReturn && orelse == null) {
105+
return body.returnExecute(frame);
106+
} else {
107+
body.executeVoid(frame);
108+
}
95109
} catch (PException ex) {
96110
if (!catchPException(frame, ex)) {
97111
throw ex;
98112
}
99-
return;
113+
// To keep it simple do not run the exception handlers with "terminating return" opt
114+
// If we reach here, no explicit return could have happened as it would throw
115+
return PNone.NONE;
100116
} catch (AbstractTruffleException e) {
101117
if (excLib == null) {
102118
CompilerDirectives.transferToInterpreterAndInvalidate();
103119
excLib = insert(InteropLibrary.getFactory().createDispatched(3));
104120
}
105121
if (excLib.isException(e) && catchTruffleException(frame, e)) {
106-
return;
122+
return PNone.NONE;
107123
}
108124
throw e;
109125
} catch (ControlFlowException e) {
@@ -113,14 +129,14 @@ public void executeVoid(VirtualFrame frame) {
113129
if (pe != null) {
114130
boolean handled = catchPException(frame, pe);
115131
if (handled) {
116-
return;
132+
return PNone.NONE;
117133
} else {
118134
throw pe.getExceptionForReraise();
119135
}
120136
}
121137
throw e;
122138
}
123-
orelse.executeVoid(frame);
139+
return orelse.genericExecute(frame, isReturn);
124140
}
125141

126142
@ExplodeLoop(kind = LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN)

0 commit comments

Comments
 (0)