fsharp icon indicating copy to clipboard operation
fsharp copied to clipboard

"FS3511: This state machine is not statically compilable." for large records in complex task

Open pleaseletmesearch opened this issue 7 months ago • 5 comments

Repro steps The following compiles in Debug mode but warns in Release mode, with "error FS3511: This state machine is not statically compilable. A resumable code invocation at '(26,8--26,12)' could not be reduced. An alternative dynamic implementation will be used, which may be slower. Consider adjusting your code to ensure this state machine is statically compilable, or else suppress this warning.".

namespace Foo

type Thing =
        {
            A : int
            B : int
            C : int
            D : int
            E : int
            F : int
            G : int
            H : int
            I : int
            J : int
            K : int
            L : int
            M : int
            N : int
            O : int
        }


module TestIt =

    let thing () =
        task {
            match failwith "" with
            | None -> return failwith ""
            | Some _ ->

            let blah =
                task {
                    return failwith ""
                }

            printfn "hi"

            return
                {
                    A = failwith ""
                    B = failwith ""
                    C = failwith ""
                    D = failwith ""
                    H = failwith ""
                    F = failwith ""
                    G = failwith ""
                    I = failwith ""
                    E = failwith ""
                    J = failwith ""
                    K = failwith ""
                    L = failwith ""
                    M = failwith ""
                    N = failwith ""
                    O = failwith ""
                }
                |> Ok
        }

This appears to be very sensitive to the details of this example. For example, removing a field from the record, it compiles cleanly. Reordering the E field to be in its alphabetical order also compiles cleanly. Removing the printfn compiles cleanly, and replacing the sub-task with a Task.FromResult compiles cleanly.

Expected behavior

Compilation succeeds identically in Release and Debug modes.

Actual behavior

Compilation fails in Release mode.

Known workarounds

Just ignore the warning and fall back to the dynamic version.

Related information

Provide any related information (optional):

$ dotnet --info
.NET SDK:
 Version:           9.0.203
 Commit:            dc7acfa194
 Workload version:  9.0.200-manifests.9df47798
 MSBuild version:   17.13.20+a4ef1e90f

Runtime Environment:
 OS Name:     ubuntu
 OS Version:  22.04
 OS Platform: Linux
 RID:         linux-x64
 Base Path:   /usr/share/dotnet/sdk/9.0.203/

.NET workloads installed:
There are no installed workloads to display.
Configured to use loose manifests when installing new manifests.

Host:
  Version:      9.0.4
  Architecture: x64
  Commit:       f57e6dc747

.NET SDKs installed:
  6.0.400 [/usr/share/dotnet/sdk]
  8.0.408 [/usr/share/dotnet/sdk]
  9.0.203 [/usr/share/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 6.0.36 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.15 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 9.0.4 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 6.0.36 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.15 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 9.0.4 [/usr/share/dotnet/shared/Microsoft.NETCore.App]

Other architectures found:
  None

Environment variables:
  DOTNET_ROOT       [/usr/share/dotnet]

I'm using FSharp.Core 8.0.100, if that's relevant.

pleaseletmesearch avatar May 14 '25 14:05 pleaseletmesearch

It seems, I can't reproduce it on a new class lib project.

cat ./Library.fs

namespace Foo

type Thing =
        {
            A : int
            B : int
            C : int
            D : int
            E : int
            F : int
            G : int
            H : int
            I : int
            J : int
            K : int
            L : int
            M : int
            N : int
            O : int
        }


module TestIt =

    let thing () =
        task {
            match failwith "" with
            | None -> return failwith ""
            | Some _ ->

            let blah =
                task {
                    return failwith ""
                }

            printfn "hi"

            return
                {
                    A = failwith ""
                    B = failwith ""
                    C = failwith ""
                    D = failwith ""
                    H = failwith ""
                    F = failwith ""
                    G = failwith ""
                    I = failwith ""
                    E = failwith ""
                    J = failwith ""
                    K = failwith ""
                    L = failwith ""
                    M = failwith ""
                    N = failwith ""
                    O = failwith ""
                }
                |> Ok
        }

cat ./global.json

{
  "sdk": {
    "version": "9.0.202"
  }
}

dotnet build -c Release

Restore complete (0.2s)
  resumable succeeded (0.1s) → bin/Release/net8.0/resumable.dll

Build succeeded in 0.5s

vzarytovskii avatar May 14 '25 16:05 vzarytovskii

Same here. I also tried sdk 9.0.203 and FSharp.Core 8.0.100. Compiles for both Debug and Release.

Martin521 avatar May 14 '25 17:05 Martin521

Sorry for the incomplete report. I didn't realise there was a Directory.Build.props file applying; it turns out that --crossoptimize- is also a critical part of the repro. I don't actually know why --crossoptimize- is set here, or whether it's expected that the static compilation fails under that condition; currently reading code and docs to try and find out.

Here is a repro from a completely different machine:

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFrameworks>net8.0</TargetFrameworks>
        <OtherFlags>--crossoptimize- $(OtherFlags)</OtherFlags>
    </PropertyGroup>

    <ItemGroup>
        <Compile Include="Program.fs"/>
    </ItemGroup>
</Project>
namespace Foo

type Thing =
        {
            A : int
            B : int
            C : int
            D : int
            E : int
            F : int
            G : int
            H : int
            I : int
            J : int
            K : int
            L : int
            M : int
            N : int
            O : int
        }


module TestIt =

    let thing () =
        task {
            match failwith "" with
            | None -> return failwith ""
            | Some _ ->

            let blah =
                task {
                    return failwith ""
                }

            printfn "hi"

            return
                {
                    A = failwith ""
                    B = failwith ""
                    C = failwith ""
                    D = failwith ""
                    H = failwith ""
                    F = failwith ""
                    G = failwith ""
                    I = failwith ""
                    E = failwith ""
                    J = failwith ""
                    K = failwith ""
                    L = failwith ""
                    M = failwith ""
                    N = failwith ""
                    O = failwith ""
                }
                |> Ok
        }

Output of dotnet --info:

/nix/store/j2ppnz8jdvglmkaslwr4p8jvnij0pd72-dotnet-sdk-wrapped-9.0.203/bin/dotnet --info                                                                                      ~/Documents/GitHub/Resumable
.NET SDK:
 Version:           9.0.203
 Commit:            dc7acfa194
 Workload version:  9.0.200-manifests.9df47798
 MSBuild version:   17.13.20+a4ef1e90f

Runtime Environment:
 OS Name:     Mac OS X
 OS Version:  15.4
 OS Platform: Darwin
 RID:         osx-arm64
 Base Path:   /nix/store/4gc3gsfn90b3izf40cxclwriqkm7z9yq-dotnet-sdk-9.0.203/share/dotnet/sdk/9.0.203/

.NET workloads installed:
There are no installed workloads to display.
Configured to use loose manifests when installing new manifests.

Host:
  Version:      9.0.4
  Architecture: arm64
  Commit:       b7deac6d42

.NET SDKs installed:
  9.0.203 [/nix/store/4gc3gsfn90b3izf40cxclwriqkm7z9yq-dotnet-sdk-9.0.203/share/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 9.0.4 [/nix/store/4gc3gsfn90b3izf40cxclwriqkm7z9yq-dotnet-sdk-9.0.203/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 9.0.4 [/nix/store/4gc3gsfn90b3izf40cxclwriqkm7z9yq-dotnet-sdk-9.0.203/share/dotnet/shared/Microsoft.NETCore.App]

Other architectures found:
  None

Environment variables:
  Not set

global.json file:
  Not found

Smaug123 avatar May 14 '25 17:05 Smaug123

This I can reproduce for both sdk 8 and 9

Martin521 avatar May 14 '25 18:05 Martin521

Duplicate https://github.com/dotnet/fsharp/issues/12839

kerams avatar May 15 '25 09:05 kerams