Skip to content

Deforest rewriting improvements#499

Merged
LPTK merged 17 commits into
hkust-taco:hkmc2from
ychenfo:deforest-rewriting-improvements
Jun 1, 2026
Merged

Deforest rewriting improvements#499
LPTK merged 17 commits into
hkust-taco:hkmc2from
ychenfo:deforest-rewriting-improvements

Conversation

@ychenfo
Copy link
Copy Markdown
Member

@ychenfo ychenfo commented May 24, 2026

This PR fixes a deforestation bug where the rewriter wrongly turns implicit returns to explicit returns. Turning implicit returns to explicit ones is needed for branch-body and the continuation "rest" functions whose bodies are originated from top level blocks, but wrong for rewriting blocks like class constructors: it could produce explicit return super() and made code after super() unreachable, which causes bugs. This is now fixed.

This PR also avoids traversing the program when there is no fusion, and adds some high level comments for the rewriting process.


TODO here and in following PRs

  • Temporarily revert the use of irDefn to re-expose the bug
  • Update classCtorSymbol to use ClassCtorSymbol
  • Remove the special method-body deforestation logic (even tually, we'll do most optimization at the top level); also, this logic would likely break when we make the analysis understand methods
  • Fix this – only support it if doing so does not incur significant extra complexity
    module Test with
      module Test2 with
        let x = 1
        fun foo(a) = if a is
          A(y) then x + y
    Test.Test2.foo(A(2))
    From the meeting discussion:
    • reconstruct paths based on owner chains that are rooted in toplevel symbols
    • this also changes in Rewrite's handling of FVs
  • As part of the compiler cache's Artifact computation, store the polymorphic analysis types of each top-level-like definition
  • Scope patmat branches, now that we use proper LetSplit and shouldn't share variables across splits as before

@ychenfo ychenfo mentioned this pull request May 24, 2026
// marks if a function or lambda is affine, i.e. called at most once.
// for functions with multiple parameter lists, `whichParamList` is the zero-based parameter-list index.
// marks if a function or lambda is one-shot, i.e. called at most once.
// `whichParamList` is the zero-based index of the parameter list for functions with multiple parameter lists.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I still don't get it, from this comment. Why is there a parameter list index?!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I've tried to further clarify this comment in b4e9fb6

@LPTK
Copy link
Copy Markdown
Contributor

LPTK commented May 25, 2026

Turning implicit returns to explicit ones is needed for branch-body and the continuation "rest" functions whose bodies are originated from top level blocks, but wrong for rewriting blocks like class constructors: it could produce explicit return super() and made code after super() unreachable, which causes bugs. This is now fixed.

Wow... If I'd known the so-called "implicit returns" would cause such problems, I would have pushed for removing them earlier. They're mostly a legacy piece of design that should probably go. They should certainly not be the cause of such extra complexity.

# Conflicts:
#	hkmc2/shared/src/main/scala/hkmc2/codegen/deforest/Rewrite.scala
@LPTK
Copy link
Copy Markdown
Contributor

LPTK commented May 25, 2026

I'd known the so-called "implicit returns" would cause such problems, I would have pushed for removing them earlier.

Ok, done. And I've merged this branch with the help of Codex, so please do review your own diff, making sure all the important relevant changes are still in.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refines the deforestation (fusion) rewriting pass to avoid incorrectly converting non-returning contexts into value-returning return ... statements (notably in class/module constructor-like blocks), which could make subsequent constructor code unreachable (e.g., return super()).

Changes:

  • Make the rewriter conditional: skip program rewriting when the solver reports no fusions.
  • Introduce context-sensitive tail rewriting (returnsFromCurrentBlock) so “tail” fused calls are either emitted as Return(...) (function/lambda bodies) or as discarded statements (constructor/module bodies).
  • Add/clarify high-level comments and rename a comment in Annot.Affine to describe “one-shot” usage.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
hkmc2/shared/src/main/scala/hkmc2/semantics/Term.scala Updates Annot.Affine doc comment to describe one-shot semantics more clearly.
hkmc2/shared/src/main/scala/hkmc2/codegen/deforest/Rewrite.scala Adds context-sensitive tail rewriting to avoid value-returning return ... in constructor-like blocks; skips rewriting when there is no fusion.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread hkmc2/shared/src/main/scala/hkmc2/codegen/deforest/Rewrite.scala Outdated
Comment thread hkmc2/shared/src/main/scala/hkmc2/codegen/deforest/Rewrite.scala
Copy link
Copy Markdown
Contributor

@LPTK LPTK left a comment

Choose a reason for hiding this comment

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

Is the PR otherwise ready to merge?

Comment thread hkmc2/shared/src/main/scala/hkmc2/codegen/flowAnalysis/FlowAnalysis.scala Outdated
:deforest
:expect 5
:noInline
:fixme
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You should add the logic to treat self-references as free variables, right?

Will you fix this as part of this PR, or a follow-up? I'm fine with both options.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

You should add the logic to treat self-references as free variables, right?

Yes.

Will you fix this as part of this PR, or a follow-up? I'm fine with both options.

I currently plan to fix this in a follow-up, maybe it's also better to fix this after #505 is merged?

Comment thread hkmc2/shared/src/test/mlscript/deforest/relaxedPrograms.mls Outdated
ychenfo and others added 2 commits May 31, 2026 04:29
@LPTK LPTK force-pushed the deforest-rewriting-improvements branch from df3f951 to 3b039bb Compare May 31, 2026 06:47
@LPTK
Copy link
Copy Markdown
Contributor

LPTK commented May 31, 2026

@ychenfo Pls fix the conflicts again.

ychenfo added 3 commits June 1, 2026 00:34
…mprovements

 Conflicts:
	hkmc2/shared/src/main/scala/hkmc2/codegen/deforest/Rewrite.scala
	hkmc2/shared/src/test/mlscript/deforest/fusibility.mls
Comment thread hkmc2/shared/src/main/scala/hkmc2/codegen/flowAnalysis/FlowAnalysis.scala Outdated
Comment thread hkmc2/shared/src/main/scala/hkmc2/codegen/flowAnalysis/FlowAnalysis.scala Outdated
Comment thread hkmc2/shared/src/main/scala/hkmc2/codegen/flowAnalysis/FlowAnalysis.scala Outdated
Comment thread hkmc2/shared/src/main/scala/hkmc2/codegen/flowAnalysis/FlowAnalysis.scala Outdated
Comment thread hkmc2/shared/src/main/scala/hkmc2/codegen/flowAnalysis/FlowAnalysis.scala Outdated
Comment thread hkmc2/shared/src/test/mlscript/backlog/ToTriage.mls Outdated
Comment thread hkmc2/shared/src/main/scala/hkmc2/semantics/Term.scala Outdated
- remove error raising in extractor
- uses `MemberRefTo` instead
- update `Annot.Affine` documentation
Comment thread hkmc2/shared/src/main/scala/hkmc2/codegen/flowAnalysis/FlowAnalysis.scala Outdated
Copy link
Copy Markdown
Contributor

@LPTK LPTK left a comment

Choose a reason for hiding this comment

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

Net-negative PR despite added tests & documentation – nice!

@LPTK LPTK merged commit 7e080c5 into hkust-taco:hkmc2 Jun 1, 2026
1 check passed
@LPTK LPTK deleted the deforest-rewriting-improvements branch June 1, 2026 13:11
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.

3 participants