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

Exceptions refactoring and try-finally transform #171

Merged
merged 14 commits into from
Jun 14, 2021

Conversation

alaviss
Copy link
Contributor

@alaviss alaviss commented Jun 13, 2021

As usual, the compiler blocks our transform: nim-lang/Nim#18254 Worked around that bug

Blocked by: nim-lang/Nim#18247

So main changes:

  • Moved a few things around
  • try-except is now implemented by merging all except branches into one then turn that into a continuation. This should help with implementing an unwinding system for cps.
  • try-finally is implemented by turning the finally leg into a continuation taking a generic parameter pointing to where to go next. then specialize it to each exit legs.

Known issues:

  • try-except doesn't work with except branches matching multiple exception types: except ValueError, IOError.
  • try-finally doesn't handle early returns, but this is fixable by improving isScopeExit and making early return an annotation.

alaviss and others added 7 commits June 12, 2021 11:49
Nim has a "exception stack" system where inner except branches will
push a new exception to the stack then pop it after it's done.

To replicate this accurately in CPS, we use one local per cps `try`
instead of a single field like how it is done currently. This is
because we set the global exception to whatever the stored exception
was in our continuation leg, so to prevent inner cps `try`s from overriding
what is perceived to be the "current" exception of the outer branch, we
simply give them different locals.

Ideally we can tap right into Nim's exception `up` field, but it's not
exported.
Not sure what I thought of when I wrote that code, but we can just
run filter on the outer node and don't have to think about the bugs
this `for` would cause us.
Instead of creating a continuation leg for each except branch, we
merge all except branches into one, then turn that into a continuation.

That way we only have one continuation for all handlers, allow for
a better implementation of cps exceptions in the future.
Implements try-finally transformation for CPS by generating
finally as a continuation leg with a static generic for where
it will continues after.

Untested because the compiler broke.

Known issues:
- Early returns are not handled, which can be fixed by improving
  isScopeExit and making early termination an annotation.

Fixes #80.
Instead of waiting for nim-lang/Nim#18254
and any other templates bug to be fix. We take the initiative and
write our own continuation templater. It appears to work well enough
to use as an alternative until a better alternative become available.

I've also added an extra test that verify the exception re-raise property.
We ended up not needing it for finally
We implement early returns as `cpsTerminate` then tie them up at the
end via `cpsResolver`. This way try-finally can capture early termination and
specialize to those.

Need @disruptek to review this stuff.
Copy link
Contributor

@disruptek disruptek left a comment

Choose a reason for hiding this comment

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

Really great advancement. I also think this stuff should go into its own file; it can be imported into transform, right?

Comment on lines 422 to 424
# The key is the symbol need updating and the value is what to update
# it to
var replacements: Table[NimNode, NimNode]
Copy link
Contributor

Choose a reason for hiding this comment

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

Rather than a comment, I'd just use a type declaration. 😁

result = copyNimTree(replacements[n])

replacements[replace] = replacement
templ.filter(generator)
Copy link
Contributor

Choose a reason for hiding this comment

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

eh do we ever use it like this? I think we prefer result = filter(templ, generator) right?

@alaviss alaviss marked this pull request as ready for review June 14, 2021 00:28
@alaviss alaviss requested a review from disruptek June 14, 2021 00:38
@alaviss alaviss merged commit f5fc646 into master Jun 14, 2021
@alaviss alaviss deleted the leorize/except-refactoring branch June 14, 2021 01:16
@alaviss alaviss restored the leorize/except-refactoring branch June 14, 2021 01:17
@disruptek disruptek added enhancement New feature or request refactoring the noblest of deeds labels Jul 12, 2021
@disruptek disruptek deleted the leorize/except-refactoring branch December 1, 2022 22:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request refactoring the noblest of deeds
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bug in try-except rewrite of except T as e Incorrect rewrite for defer
2 participants