Skip to content

Improve static compilation of state machines#19297

Open
majocha wants to merge 16 commits intodotnet:mainfrom
majocha:resumable-fix-19296
Open

Improve static compilation of state machines#19297
majocha wants to merge 16 commits intodotnet:mainfrom
majocha:resumable-fix-19296

Conversation

@majocha
Copy link
Contributor

@majocha majocha commented Feb 16, 2026

Fixes #19296, also includes test cases from #14930, brazenly vibecoded.

However I think the risk of changes here is under control, given that we have quite a few relevant projects and their tests in the regression matrix.

OK here goes AI summary:

This pull request improves the F# compiler's handling of state machine lowering, especially for cases involving resumable code and control flow constructs like if __useResumableCode. It fixes issues where inlined helpers or nested resumable code constructs could incorrectly fall back to dynamic branches at runtime, and adds comprehensive test coverage for these scenarios. The main focus is on ensuring that statically-compilable state machines are correctly recognized and optimized, and that code generation remains robust for complex patterns.

Key changes include:

Compiler logic improvements:

  • Enhanced the lowering pass in LowerStateMachines.fs to correctly handle resumable code bindings found inside debug points, ensuring that nested resumable code constructs are properly expanded.
  • Updated the reduction logic to track locally-bound resumable code continuations in the environment, allowing correct resolution and inlining of these continuations during optimization. [1] [2]
  • Modified the rewrite environment to avoid recursing into nested state machine expressions, preventing unintended modification of their internal logic and ensuring that only the appropriate static branches are taken for if __useResumableCode.

Test suite enhancements:

  • Added a new test module (FailingInlinedHelper) and test case to verify that inlined helpers containing if __useResumableCode are expanded correctly, addressing a real-world bug. [1] [2]
  • Expanded tests to cover additional scenarios involving for-loops over tuples and various statically-compilable task patterns, ensuring robust handling of these constructs.

Documentation/test comments:

@github-actions
Copy link
Contributor

github-actions bot commented Feb 16, 2026

❗ Release notes required


✅ Found changes and release notes in following paths:

Change path Release notes path Description
src/Compiler docs/release-notes/.FSharp.Compiler.Service/10.0.300.md

Improve reduction of resumable code in state machines

Enhance application reduction in state machine lowering for F# computation expressions by tracking let-bound resumable code in the environment and resolving references during reduction. This enables correct handling of optimizer-generated continuations and deeper reduction of nested applications. Also, update test comments to reflect resolved state machine compilation issues.
@majocha
Copy link
Contributor Author

majocha commented Feb 16, 2026

Looks like this now to some point reinvents #14930. I'll try to include some of the relevant repros in tests. Too bad they are scattered across issues and comments.

@majocha
Copy link
Contributor Author

majocha commented Feb 16, 2026

Another observation: Lack of FS3511 warning does not mean the state machine actually compiled statically. Sometimes the fallback to dynamic implementation gives no warning.

@majocha majocha changed the title Resumable state machines: fix #19296 Improve static compilation of state machines Feb 17, 2026
@majocha majocha marked this pull request as ready for review February 17, 2026 09:56
@majocha majocha requested a review from a team as a code owner February 17, 2026 09:56
// The tasks below used to fail state machine compilation. This failure was causing subsequent problems in code generation.
// See https://github.com/dotnet/fsharp/issues/13404

#nowarn "3511" // state machine not statically compilable - this is a separate issue, see https://github.com/dotnet/fsharp/issues/13404
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This issue is fixed now.

}
"""
|> compile
|> verifyIL [ ".override [runtime]System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext" ]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

State machines sometimes fallback to dynamic implmentation without FS3511 warning. Checking for generated MoveNext is more reliable.

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

Labels

None yet

Projects

Status: New

Development

Successfully merging this pull request may close these issues.

State machines: low-level resumable code not always expanded correctly, without warning

1 participant