Skip to content
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

Panics can be caught from TCO loops #9705

Merged
merged 8 commits into from
May 1, 2024
Merged

Conversation

Akirathan
Copy link
Member

@Akirathan Akirathan commented Apr 15, 2024

Fixes #9251

Pull Request Description

In certain cases, when the action of Panic.catch is tail-call-optimized (via @Tail_Call) annotation, the panic is not caught. Fixed by ensuring that the action of Panic.catch is executed as NOT_TAIL rather than TAIL_DIRECT.

Important Notes

The handler parameter of Panic.catch is executed as NOT_TAIL as well, just to be sure.

Checklist

Please ensure that the following checklist has been satisfied before submitting the PR:

  • The documentation has been updated, if necessary.
  • Screenshots/screencasts have been attached, if there are any visual changes. For interactive or animated visual changes, a screencast is preferred.
  • All code follows the
    Scala,
    Java,
    and
    Rust
    style guides. In case you are using a language not listed above, follow the Rust style guide.
  • All code has been tested:
    • Unit tests have been written where possible.
    • If GUI codebase was changed, the GUI was tested when built using ./run ide build.

@Akirathan Akirathan self-assigned this Apr 15, 2024
p . should_equal "fn_with_tco"

# The same test as the one before, but it does not use the `<|` function.
group_builder.specify "should be caught in a TCO loop with a wrapper fn" <|
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As suggested by @JaroslavTulach, I have added this test. And as expected, this test succeeds, but the former ("should be caught in a TCO loop") fails. It seems that your suspicion, @JaroslavTulach, was right - this is probably caused by the fact that the <| function is inlineable and therefore there is no frame for it.

Copy link
Member Author

@Akirathan Akirathan Apr 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JaroslavTulach EDIT: The test added in cce3c03 suggests otherwise. In that commit, I have introduced a test that doesn't use the <| method, but uses a method defined in a top scope, and it fails as well.

@Akirathan
Copy link
Member Author

The only place where a TailCallException (thrown when a method call annotated with @Tail_Call is called) is caught, is in SimpleCallOptimiserNode.executeDispatch.

SimpleCallOptimiserNode is created in CurryNode.initializeCallNodes based on its TailStatus which is determined in TailCall compiler pass.

The two failing tests fail, because the TailCallException is caught in the stack above CatchPanicNode.doExecute thus, effectively discarding the CatchPanicNode.doExecute (which is the only place where a PanicException is caught) from the stack.

It is all about looking at the stack trace at the moment when TailCallException and PanicException are thrown.

@Akirathan
Copy link
Member Author

Evaluating the following tmp.enso:

from Standard.Base import all

fn_tail x =
    if x == 1 then Panic.throw "my panic" else
        @Tail_Call fn_tail x+1

handler caught =
    IO.println <| "handler: caught = " + caught.to_text

main =
    Panic.catch Any handler=handler <| fn_tail 0

@@ -59,7 +59,7 @@ Object doExecute(
@Cached BranchProfile otherExceptionBranchProfile,
@CachedLibrary(limit = "3") InteropLibrary interop) {
try {
return thunkExecutorNode.executeThunk(frame, action, state, BaseNode.TailStatus.TAIL_DIRECT);
return thunkExecutorNode.executeThunk(frame, action, state, BaseNode.TailStatus.NOT_TAIL);
Copy link
Member

@JaroslavTulach JaroslavTulach May 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Panic.catch cannot be in tail call position. I believe it has to be NOT_TAIL. All the tests in Error_Spec are fixed. Let's see what other collateral damage this change may have created. Btw. I have a feeling @hubertp was fighting with some similar issue a year back or so...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What a good observation! At the end, it seems that we will not have to dig in the IR phases. I have just added some comments and made sure that even the handler callback is not in a tail call position, just to be sure - in commit 8539997.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On contrary to the action invocation, handler can probably be in tail position. There is nothing in the CatchPanicNode that needs to run after handler...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good note. Add a comment about that in d86c7b5 . handler is invoked with TAIL_DIRECT.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw. I have a feeling @hubertp was fighting with some similar issue a year back or so...

It's been a while so I can't remember but maybe you are referring to #7116

@Akirathan Akirathan added the CI: No changelog needed Do not require a changelog entry for this PR. label May 1, 2024
@Akirathan Akirathan marked this pull request as ready for review May 1, 2024 09:24
@Akirathan Akirathan added the CI: Ready to merge This PR is eligible for automatic merge label May 1, 2024
@@ -59,7 +59,7 @@ Object doExecute(
@Cached BranchProfile otherExceptionBranchProfile,
@CachedLibrary(limit = "3") InteropLibrary interop) {
try {
return thunkExecutorNode.executeThunk(frame, action, state, BaseNode.TailStatus.TAIL_DIRECT);
return thunkExecutorNode.executeThunk(frame, action, state, BaseNode.TailStatus.NOT_TAIL);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw. I have a feeling @hubertp was fighting with some similar issue a year back or so...

It's been a while so I can't remember but maybe you are referring to #7116

@mergify mergify bot merged commit 6b0361c into develop May 1, 2024
37 checks passed
@mergify mergify bot deleted the wip/akirathan/9251-panic-tco branch May 1, 2024 11:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CI: No changelog needed Do not require a changelog entry for this PR. CI: Ready to merge This PR is eligible for automatic merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Problems catching a Panic thrown within a TCO loop
4 participants