Improve static compilation of state machines#19297
Improve static compilation of state machines#19297majocha wants to merge 30 commits intodotnet:mainfrom
Conversation
|
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.
|
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. |
|
Another observation: Lack of FS3511 warning does not mean the state machine actually compiled statically. Sometimes the fallback to dynamic implementation gives no warning. |
tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/NestedTaskFailures.fs
Show resolved
Hide resolved
|
I tried to include in tests as many old repros as I could find across the issues. Turns out a lot of those repros already compile statically. If not in sharplab (no idea what version it uses) than with current compiler from main. 3 cases remained that are fixed specifically by this PR: |
|
Is it right to close #12839 with this ? It looks like an umbrella issue for all sorts of problems. I am also thinking if there is a way we could add an end2end test here, e.g. using the library regression testing pipeline? |
As far as I can tell all of them are resolved now, few have been resolved for some time.
I have nothing apart from the few tests I added :) One thing that comes to mind is to disable some of the #nowarn 3511 we have in this repo, or at least make them scoped to the exact place, like using |
|
OK, it seems removing nowarn 3511 in this repo uncovers some more cases that need fixing. |
…es not have a definition.") consider a Run(code: ResumableCode<...>) method. In some cases code can get optimized away resulting in warning 3511 "The resumable code value(s) 'code' does not have a definition."
… into resumable-fix-19296
|
I removed the few catch all nowarns 3511. This revealed a nice small repro of
Let's see if it's fixed. |
|
Removing the nowarns here is good dogfooding 👍 . IcedTasks have 3 of them in tests https://github.com/search?q=repo%3ATheAngryByrd%2FIcedTasks%203511&type=code that appear to be intentionally dynamic (for testing), otherwise I do not see it - all good ( I will just check the regression pipeline outputs if there are any warnings from it) |
|
There's an odd timeout, but there is no information which test hanged. Previously we got this info with |
Pull request was converted to draft
| module ``Check simple task compiles to state machine`` = | ||
|
|
||
| let test1() = | ||
| let test1 = |
There was a problem hiding this comment.
The restriction of top level values is no longer, #18817. BTW the tests in this file currently run only in DESKTOP in FSharpSuite. Would be good to have them migrated.
There was a problem hiding this comment.
Indeed, I have that on my radar once we have the existing suite stabilized and sharded 👍 (we need macOS to get under timing limits before growing it further).
There was a problem hiding this comment.
So most of these tests just compare runtime provided CurrentMethod and compare that against MoveNext .
If I am going to migrate these tests, is this the most solid assertion?
(i.e. not attempting to assert at type check level, but really going via full compileAndRun and checking if inside MoveNext just as well?)
There was a problem hiding this comment.
Lines 135 to 170 in 242bedb
Yes, just singleNegTest and compileAndRun would probably do. Not sure what to do about the peverify step.
There was a problem hiding this comment.
The closest we can do is replace it with ilverify on the compiled program, that shall be possible.
( like a 'compileAndVerifyAndRun' -style helper into the test framework. Possibly we could have an |> verifyNotUsesDynamicInvocation or similar, but maybe the reflection based runtime check is really the best)

Fixes #19296, #12839 also includes test cases from #14930.
Also fixes FS3511
The resumable code value(s) 'code' does not have a definition.we have no issue open for it, but it was suppressed in this repo.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:
LowerStateMachines.fsto correctly handle resumable code bindings found inside debug points, ensuring that nested resumable code constructs are properly expanded.if __useResumableCode.Test suite enhancements:
FailingInlinedHelper) and test case to verify that inlined helpers containingif __useResumableCodeare expanded correctly, addressing a real-world bug. [1] [2]Documentation/test comments:
NestedTaskFailures.fstest to reflect that certain state machine failures are now fixed, clarifying the status of known issues.Fixes State machines: low-level resumable code not always expanded correctly, without warning #19296, also includes test cases from Try fix static compilation of state machines #14930