Skip to content

Fix a variable capture during optimization. #5744

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

Merged
merged 1 commit into from
Jun 4, 2025
Merged

Conversation

dolio
Copy link
Contributor

@dolio dolio commented Jun 4, 2025

As part of optimizing code to get handlers in shape for the affine handler transformation, we do inlining. One of these is a somewhat special inlining, where we take handler code, which looks like this:

  handler =
    let rec
      matcher <vs> = cases
        { ... } -> ... handler ...
    in ... matcher ...

And we (effectively) inline the body of the let rec into the recursive reference to handler inside of matcher. This avoids indirection and makes it easier to recognize things.

However, the variable matcher is free in the body, and cannot easily be renamed. So, it is important that matcher is not captured by the context into which it's inlined.

However, the variable names aren't really this distinct. They are like _anf5, and such variables are also used when normalizing terms to have no complex subexpressions (etc.). If the recursive handler call is not direct, but via another function that gets inlined, it may be that that other function uses redundant variables, because the _anf numbering starts at 0 for each term.

So, this change uses a beefed up form of renaming when doing inlining, which also freshens the term to avoid binding certain variables. This is used to ensure that the inlining, never captures the matcher variable.

Fixes #5737

As part of optimizing code to get handlers in shape for the affine
handler transformation, we do inlining. One of these is a somewhat
special inlining, where we take handler code, which looks like this:

  handler =
    let rec
      matcher <vs> = cases
        { ... } -> ... handler ...
    in ... matcher ...

And we (effectively) inline the _body_ of the let rec into the
recursive reference to `handler` inside of `matcher`. This avoids
indirection and makes it easier to recognize things.

However, the variable `matcher` is free in the body, and cannot easily
be renamed. So, it is important that `matcher` is not captured by the
context into which it's inlined.

However, the variable names aren't really this distinct. They are like
`_anf5`, and such variables are also used when normalizing terms to
have no complex subexpressions (etc.). If the recursive `handler` call
is not direct, but via _another_ function that gets inlined, it may be
that that other function uses redundant variables, because the `_anf`
numbering starts at 0 for each term.

So, this change uses a beefed up form of renaming when doing inlining,
which also freshens the term to avoid binding certain variables. This
is used to ensure that the inlining, never captures the `matcher`
variable.
@dolio dolio requested review from pchiusano, aryairani and ceedubs June 4, 2025 22:11
@aryairani
Copy link
Contributor

Thanks for the speedy fix

@dolio
Copy link
Contributor Author

dolio commented Jun 4, 2025

Benchmarks look good relative to last release. Apparently they were also bombing on this error, so I must not have run them on my last change.

At a guess, I would say that the bug I fixed yesterday was somehow cancelling out this bug and making things work that otherwise wouldn't have. But in general both were wrong.

@unison/base and @unison/http tests pass (Cody told me the latter were failing).

@aryairani aryairani merged commit 3766e89 into trunk Jun 4, 2025
31 checks passed
@aryairani aryairani deleted the fix/inlining-capture branch June 4, 2025 23:20
ceedubs added a commit to unisoncomputing/cloud-client-tests that referenced this pull request Jun 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

"unhandled closure" error in gen-racket-libs.md
2 participants