-
Notifications
You must be signed in to change notification settings - Fork 786
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unexpected warning '[FS3511] This state machine is not statically compilable' #12839
Comments
I experience something similar. Here is my repro. Let me know if I should post a separate issue for this. type T = {
A: string
B: string
C: int64
}
let f () =
task {
// No warning if removing outer or inner match
match Error "" with
| Error _ -> ()
| Ok _ ->
match Error "" with
| Error _ -> return failwith "" // No warning if replacing with () as above
| Ok _ ->
match Some (Unchecked.defaultof<T>, Unchecked.defaultof<unit>) with // No warning if using literal () or removing second tuple element
| None -> return failwith ""
| Some (info, _a) -> // No warning if renaming '_a' to '_'
printfn $"{info.A}" // No warning if removing
printfn $"{info.B}" // No warning if removing
printfn $"{info.C}" // No warning if removing
printfn $"{2 + 2}" // No warning if removing or replacing with constant string
return failwith "" // No warning if removing or replacing with 'return ()' or '()'
} In reducing this repro, it seemed extremely arbitrary to me what caused the problem and what doesn't. For the original code (which is a Giraffe HttpHandler for serving file downloads), I am left with no apparent recourse other than to ignore FS3511 for the whole project, and live with whatever the performance impacts are. |
Probably related with #12038. |
Just for the record: In that issue, @dsyme said:
Note that points 2 and 3 don't apply here. |
Chiming in with my repro. let getDeckWithSchema cs (requester: UserId option) (deckId: DeckId) includeSections now = task {
use cmd = getDeckWithSchemaCmd cs
let! res = cmd.TaskAsyncExecute (defNeg1 requester, %deckId, toDbTime now, includeSections)
match res.ResultSet1 with
| [| r |] ->
let deck = mapDeck r
let atts = Array.map mapAttributeDefinition res.ResultSet3
let cols = Array.map mapColumnDefinition res.ResultSet4
let sections = Array.map mapSection res.ResultSet2
return ValueSome (deck, atts, cols, sections)
| _ ->
return ValueNone }
|
@kerams, can you make the repro reproducible, please? I.e., by adding stubs for the functions that you omitted? That will make it easier to analyze what's going on. |
… A resumable code invocation at` See dotnet/fsharp#12839
… A resumable code invocation at` See dotnet/fsharp#12839
… A resumable code invocation at` See dotnet/fsharp#12839
Another one. To reproduce it, get this PR,
The type of |
We keep bumping into that issue every now and again, often when there are let writeToZipOutputStreamTask (level: Deflater.CompressionLevel) outputStream (source: (string * byte array) seq) =
task {
use zipOutputStream = new ZipOutputStream(outputStream)
zipOutputStream.SetLevel(int32 level)
for name, bytes in source do
let zipEntry = ZipEntry(name=name)
do! zipOutputStream.PutNextEntryAsync(zipEntry)
do! zipOutputStream.WriteAsync(bytes)
} The workaround that has worked for us is to simply leverage the relevant enumerator + let writeToZipOutputStreamTask (level: Deflater.CompressionLevel) outputStream (source: (string * byte array) seq) =
task {
use zipOutputStream = new ZipOutputStream(outputStream)
zipOutputStream.SetLevel(int32 level)
use sourceEnumerator = source.GetEnumerator()
while sourceEnumerator.MoveNext() do
let name, bytes = sourceEnumerator.Current
let zipEntry = ZipEntry(name=name)
do! zipOutputStream.PutNextEntryAsync(zipEntry)
do! zipOutputStream.WriteAsync(bytes)
} |
@natalie-o-perret in your first snippet you have From the looks of it, it appears that it has something to do with the combination of disposable types. What library are you referencing? Maybe we can dumb this sample down even further and do some more investigation. Not sure all cases here are related, though. We should also emphasise that there’s no danger to this warning. In certain cases it may not even perform so much noticeably slower (it depends, I know). It merely means you get the ‘old style’ binding that would’ve been used were Still, would be nice if we could solve this :). |
Thanks, it was a bad copy-paste hiccup when submitting my comment at the time. Here is a full sample for repro purposes: open System.IO
open System.Text
open System.Threading.Tasks
open FSharpPlus
open FSharp.Collections
open ICSharpCode.SharpZipLib.Zip
open ICSharpCode.SharpZipLib.Zip.Compression
[<RequireQualifiedAccess>]
module ZipOutputStream =
let writeToTask1 (level: Deflater.CompressionLevel) outputStream (source: (string * byte array) seq) =
task {
use zipOutputStream = new ZipOutputStream(outputStream)
zipOutputStream.SetLevel(int32 level)
for name, bytes in source do
let zipEntry = ZipEntry(name=name)
do! zipOutputStream.PutNextEntryAsync(zipEntry)
do! zipOutputStream.WriteAsync(bytes)
}
let writeToTask2 (level: Deflater.CompressionLevel) outputStream (source: (string * byte array) seq) =
task {
use zipOutputStream = new ZipOutputStream(outputStream)
zipOutputStream.SetLevel(int32 level)
use sourceEnumerator = source.GetEnumerator()
while sourceEnumerator.MoveNext() do
let name, bytes = sourceEnumerator.Current
let zipEntry = ZipEntry(name=name)
do! zipOutputStream.PutNextEntryAsync(zipEntry)
do! zipOutputStream.WriteAsync(bytes)
}
[<RequireQualifiedAccess>]
module Task =
let getAwaiterResult (t: Task<'T>) = t.GetAwaiter().GetResult()
[<EntryPoint>]
let main _ =
use ms1 = new MemoryStream()
use ms2 = new MemoryStream()
let pseudoFiles = seq {
for c in 'a' .. 'z' do
let s = string c
yield s, Encoding.UTF8.GetBytes(s)
}
ZipOutputStream.writeToTask1 Deflater.CompressionLevel.BEST_COMPRESSION ms1 pseudoFiles |> Task.getAwaiterResult
ZipOutputStream.writeToTask2 Deflater.CompressionLevel.BEST_COMPRESSION ms2 pseudoFiles |> Task.getAwaiterResult
0 Notes about dependencies:
Building it with the release configuration flag:
Note about the .NET version in use:
|
I just ran into this issue with FsToolkit.Errorhandling dealing with using multiple cancellableTaskValidation {
let! a = Ok 3
and! b = Choice1Of2 2
and! c = CancellableTaskValidation.ok 1
return a + b - c
} I ended up looking into it and came to the same fix as in #14930 of if the It'll take a while to get a log of the expression it's trying to reduce, but it's effectively the same problem as listed in the PR:
Logs from my fork:
|
We can probably make this change as a ad-hoc fix for these cases. Problem is that to properly fix majority of those issues, it will take a deeper investigation. |
We have a number of problems where tasks are not being statically compiled.
for...in
in task CE with .NET SDK 6.0.400 in Release builds #13657See also demetrixbio/Plough.WebApi#5 as an example where a library hit this.
Repro steps
I had this problem in more complicated code, however it boils down to something like this:
Then compile it in release mode.
Original code doesn't have
Unchecked.defaultof
and getsFoo
from another function but I wasn't able to create minimal example without it. I guess, it doesn't really matter and root cause is the same.Expected behavior
No warning or better explanation of the problem and how to fix it.
Actual behavior
When compiling in Release mode:
dotnet build -c Release
Program.fs(46, 5): [FS3511] This state machine is not statically compilable. A resumable code invocation at '(46,4--46,8)' 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.
Known workarounds
In original code I had to create another function that works with
d
and inline usagelet d = { bigRecord with a37Optional = None }
variable at line 51:Related information
.NET SDK (reflecting any global.json):
Version: 6.0.201
Commit: ef40e6aa06
Runtime Environment:
OS Name: Windows
OS Version: 10.0.19044
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\6.0.201\
Host (useful for support):
Version: 6.0.3
Commit: c24d9a9c91
The text was updated successfully, but these errors were encountered: