Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions src/Compiler/Optimize/LowerStateMachines.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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 { .. }
Expand All @@ -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 =
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace Language

open Xunit
open FSharp.Test.Compiler
open FSharp.Test

module StateMachineTests =

Expand Down Expand Up @@ -160,4 +161,83 @@ let main _ =
|> ignoreWarnings
|> withOptimize
|> compileExeAndRun
|> shouldSucceed
|> shouldSucceed

[<Fact>]
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

[<Fact>]
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<int32> TestStateMachine/test@3::Data
IL_000d: ldc.i4.s 42
IL_000f: stfld !0 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1<int32>::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<int32> TestStateMachine/test@3::Data
IL_001f: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<!0> valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1<int32>::MethodBuilder
IL_0024: ldarg.0
IL_0025: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1<int32> TestStateMachine/test@3::Data
IL_002a: ldfld !0 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1<int32>::Result
IL_002f: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::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<int32> TestStateMachine/test@3::Data
IL_004e: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<!0> valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1<int32>::MethodBuilder
IL_0053: ldloc.3
IL_0054: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::SetException(class [netstandard]System.Exception)
IL_0059: ret
}
""" ]
13 changes: 13 additions & 0 deletions tests/fsharp/core/state-machines/test.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<int, int>
(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
Expand Down
Loading