New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

finally blocks and tail calls #754

Closed
AnnotationMark opened this Issue Dec 15, 2016 · 2 comments

Comments

Projects
None yet
2 participants
@AnnotationMark

AnnotationMark commented Dec 15, 2016

Here are some details from the spec:

  1. 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.

  2. 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.

  3. 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?

@bakkot

This comment has been minimized.

Show comment
Hide comment
@bakkot

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 throw

If this is the case when returning a tail call, I think that's consistent.

Contributor

bakkot commented Dec 15, 2016

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 throw

If this is the case when returning a tail call, I think that's consistent.

@AnnotationMark

This comment has been minimized.

Show comment
Hide comment
@AnnotationMark

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment