|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
When a return in a finalizer was reached through a return within the try
block, the backend ignored the return in the finalizer:
try {
try { return 1 }
finally { return 2 }
} finally { println() }
This expression should evaluate to 2 (it does in 2.11.8), but in 2.12.0
it the result is 1.
The Scala spec is currently incomplete, it does not say that a finalizer
should be exectuted if a return occurs within a try block, and it does
not specify what happens if also the finally block has a return.
So we follow the Java spec, which basically says: if the finally blocks
completes abruptly for reason S, then the entire try statement completes
abruptly with reason S. An abrupt termination of the try block for a
different reason R is discarded.
Abrupt completion is basically returning or throwing.
|
|
Return statements within `try` or `catch` blocks need special treatement
if there's also a `finally`
try { return 1 } finally { println() }
For the return, the code generator emits a store to a local and a jump
to a "cleanup" version of the finally block. There will be 3 versions
of the finally block:
- One reached through a handler, if the code in the try block
throws; re-throws at the end
- A "cleanup" version reached from returns within the try; reads the
local and returns the value at the end
- One reached for ordinary control flow, if there's no return and no
exception within the try
If there are multiple enclosing finally blocks, a "cleanup" version is
emitted for each of them. The nested ones jump to the enclosing ones,
the outermost one reads the local and returns.
A global variable `shouldEmitCleanup` stores whether cleanup versions
are required for the curren finally blocks. By mistake, this variable
was not reset to `false` when emitting a `try-finally` nested within a
`finally`:
try {
try { return 1 }
finally { println() } // need cleanup version
} finally { // need cleanup version
try { println() }
finally { println() } // no cleanup version needed!
}
In this commit we ensure that the variable is reset when emitting
nested `try-finally` blocks.
|