diff --git a/src/Compiler/Optimize/LowerStateMachines.fs b/src/Compiler/Optimize/LowerStateMachines.fs index 7a6dd553f65..eb7f6135064 100644 --- a/src/Compiler/Optimize/LowerStateMachines.fs +++ b/src/Compiler/Optimize/LowerStateMachines.fs @@ -103,8 +103,7 @@ let RepresentBindingAsStateVar g (bind: Binding) (resBody: StateMachineConversio stateVars = vref :: resBody.stateVars } let isExpandVar g (v: Val) = - isReturnsResumableCodeTy g v.TauType && - not v.IsCompiledAsTopLevel + isReturnsResumableCodeTy g v.TauType // We allow a prefix of bindings prior to the state machine, e.g. // task { .. } @@ -114,8 +113,7 @@ let isExpandVar g (v: Val) = let isStateMachineBindingVar g (v: Val) = isExpandVar g v || (let nm = v.LogicalName - (nm.StartsWithOrdinal("builder@") || v.IsMemberThisVal) && - not v.IsCompiledAsTopLevel) + (nm.StartsWithOrdinal("builder@") || v.IsMemberThisVal)) type env = { diff --git a/tests/FSharp.Compiler.ComponentTests/Language/StateMachineTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/StateMachineTests.fs index c4aed123505..86e11cf2029 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/StateMachineTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/StateMachineTests.fs @@ -4,6 +4,7 @@ namespace Language open Xunit open FSharp.Test.Compiler +open FSharp.Test module StateMachineTests = @@ -160,4 +161,83 @@ let main _ = |> ignoreWarnings |> withOptimize |> compileExeAndRun - |> shouldSucceed \ No newline at end of file + |> shouldSucceed + + [] + let ``State machine defined as top level value is statically compiled`` () = + Fsx """ +let test = task { return 42 } +if test.Result <> 42 then failwith "expected 42" + +task { printfn "Hello, World!"; return 42 } +""" + |> runFsi + |> shouldSucceed + + [] + let ``State machine defined as top level has a generated MoveNext method`` () = + FSharp """ +module TestStateMachine +let test = task { return 42 } +""" + |> compile + |> verifyIL [ """ +.method public strict virtual instance void MoveNext() cil managed +{ + .override [runtime]System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext + + .maxstack 4 + .locals init (int32 V_0, + class [runtime]System.Exception V_1, + bool V_2, + class [runtime]System.Exception V_3) + IL_0000: ldarg.0 + IL_0001: ldfld int32 TestStateMachine/test@3::ResumptionPoint + IL_0006: stloc.0 + .try + { + IL_0007: ldarg.0 + IL_0008: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 TestStateMachine/test@3::Data + IL_000d: ldc.i4.s 42 + IL_000f: stfld !0 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::Result + IL_0014: ldc.i4.1 + IL_0015: stloc.2 + IL_0016: ldloc.2 + IL_0017: brfalse.s IL_0036 + + IL_0019: ldarg.0 + IL_001a: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 TestStateMachine/test@3::Data + IL_001f: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_0024: ldarg.0 + IL_0025: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 TestStateMachine/test@3::Data + IL_002a: ldfld !0 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::Result + IL_002f: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetResult(!0) + IL_0034: leave.s IL_0042 + + IL_0036: leave.s IL_0042 + + } + catch [runtime]System.Object + { + IL_0038: castclass [runtime]System.Exception + IL_003d: stloc.3 + IL_003e: ldloc.3 + IL_003f: stloc.1 + IL_0040: leave.s IL_0042 + + } + IL_0042: ldloc.1 + IL_0043: stloc.3 + IL_0044: ldloc.3 + IL_0045: brtrue.s IL_0048 + + IL_0047: ret + + IL_0048: ldarg.0 + IL_0049: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 TestStateMachine/test@3::Data + IL_004e: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_0053: ldloc.3 + IL_0054: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetException(class [netstandard]System.Exception) + IL_0059: ret +} +""" ] diff --git a/tests/fsharp/core/state-machines/test.fsx b/tests/fsharp/core/state-machines/test.fsx index f171bfdbe7b..7e502839d6d 100644 --- a/tests/fsharp/core/state-machines/test.fsx +++ b/tests/fsharp/core/state-machines/test.fsx @@ -656,6 +656,19 @@ module ``Check after code may include closures`` = f 3)) check "vwelvewl" (makeStateMachine 3) -2 +module ``Check simple state machine as top level value`` = + let stateMachine = + __stateMachine + (MoveNextMethodImpl<_>(fun sm -> + if __useResumableCode then + sm.Data <- 42 // we expect this result for successful resumable code compilation + else + sm.Data <- 0xdeadbeef // if we get this result it means we've failed to compile as resumable code + )) + (SetStateMachineMethodImpl<_>(fun sm state -> ())) + (AfterCode<_,_>(fun sm -> MoveOnce(&sm))) + check "top_level_value" stateMachine 42 + #if TESTS_AS_APP let RUN() = !failures #else