Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upfinally blocks and tail calls #754
Comments
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
bakkot
Dec 15, 2016
Contributor
Finally blocks in general do not re-throw pending exceptions when they exit in a way other than control flow leaving the end of the block:
(function() {
"use strict";
try {
throw "A";
} finally {
return 0;
}
})(); // returns 0, does not throwIf this is the case when returning a tail call, I think that's consistent.
|
Finally blocks in general do not re-throw pending exceptions when they exit in a way other than control flow leaving the end of the block: (function() {
"use strict";
try {
throw "A";
} finally {
return 0;
}
})(); // returns 0, does not throwIf this is the case when returning a tail call, I think that's consistent. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
AnnotationMark
Dec 15, 2016
OK, that's right. I forgot that the return statement basically overwrites the Completion record (https://tc39.github.io/ecma262/#sec-return-statement-runtime-semantics-evaluation). Hence, it is supposed to eat the exception.
AnnotationMark
commented
Dec 15, 2016
|
OK, that's right. I forgot that the return statement basically overwrites the Completion record (https://tc39.github.io/ecma262/#sec-return-statement-runtime-semantics-evaluation). Hence, it is supposed to eat the exception. |
AnnotationMark commentedDec 15, 2016
Here are some details from the spec:
The semantics for HasProductionInTailPosition (https://tc39.github.io/ecma262/#sec-static-semantics-hasproductionintailposition) says that HasProductionInTailPosition of a "TryStatement: try Block Finally" and "TryStatement: try Block Catch Finally" is determined to be HasProductionInTailPosition of Finally with argument nonterminal. This implies that HasProductionInTailPosition can be true from a finally block.
The runtime semantics for EvaluateDirectCall (https://tc39.github.io/ecma262/#sec-evaluatedirectcall) step 6 states that "Assert: If tailPosition is true, the above call will not return here, but instead evaluation will continue as if the following return has already occurred." This implies that if we encountered a tail call in the preceding step 5, the steps thereafter will not be executed.
The runtime semantics evaluation of try-finally blocks (https://tc39.github.io/ecma262/#sec-try-statement-runtime-semantics-evaluation) says that we need to evaluate the result of the finally block "F" (step 4) and then return the "Completion(UpdateEmpty(F, undefined))" (step 6).
Now consider this scenario:
function test() {
"use strict";
try {
throw "A";
} finally {
return someFunctionInTailPosition();
}
}
Would you interpret the spec to mean that the tail call in test() above would cause "A" to not be re-thrown at the end of that finally block?
My thinking is that finally blocks should always reliably re-throw any pending exceptions, and that potential tail calls should not be able to eat the exception. If so, then the spec should be clarified to indicate this. Perhaps (1) above is wrong, and HasProductionInTailPosition of finally blocks should always be false.
Any thoughts?