dotnet / fsharp

The F# compiler, F# core library, F# language service, and F# tooling integration for Visual Studio
https://dotnet.microsoft.com/languages/fsharp
MIT License
3.91k stars 785 forks source link

"try with" within seq fails to capture exception variable #17930

Open Gradi opened 1 week ago

Gradi commented 1 week ago

F# code like

seq {
    try
        ...
    with
    | :? SomeException as exc when (exc.InnerException :? Some2Exception)
}

fails to be compiled because exc is not available in (exc.InnerException :? Some2Exception) environment.

This probably happens somewhere within part of compiler which transforms computational expressions into calls to builder.

Repro steps

Here is minimal source code with bug.

module Program

open System

// This is OK
let sample () =
    try
        printfn "Hi"
    with
    | :? AggregateException as exc when (exc.InnerException :? OperationCanceledException) ->
        ()

// This is OK
let asyncSample () : Async<unit> =
    async {
        try
            printfn "Hi"
        with
        | :? AggregateException as exc when (exc.InnerException :? OperationCanceledException) -> ()
    }

(*
** This fails with
** 0>Program.fs(26,9): Error FS0971 : Undefined value 'exc'
** 0>Program.fs(26,9): Error FS0971 : Undefined value 'exc'
** 0>Program.fs(26,9): Error FS0971 : Undefined value 'exc'
** 0>Program.fs(26,9): Error FS0971 : Undefined value 'exc'
** 0>Program.fs(26,9): Error FS0971 : Undefined value 'exc'
*)
let seqSample () : int seq =
    seq {
        try
            printfn "Hi"
        with
        | :? AggregateException as exc when (exc.InnerException :? OperationCanceledException) -> ()
    }

// This is OK
let seqSample2 () : int seq =
    seq {
        try
            printfn "Hi"
        with
        | :? AggregateException as exc when (true) -> ()
    }

[<EntryPoint>]
let main argv =
    0

Expected behavior

Actual behavior

Compilation fails with Undefined value 'exc'.

Related information

T-Gro commented 6 days ago

This is indeed a bug related to how try-with in seq gets lowered during compilation into a state machine.

As a workaround, you can accomplish the goal by abstracting the check into an active pattern:

open System

let (|AggCanceled|_|) (exn:Exception) =
    match exn with
    | :? AggregateException as exc  when (exc.InnerException :? OperationCanceledException)  -> Some exc
    | _ -> None

let seqSample () : int seq =
    seq {
        try
            printfn "Hi"
        with
        | AggCanceled ac  -> yield ac.InnerExceptions.GetHashCode()
    }

https://sharplab.io/#v2:DYLgZgzgPg9gDgUwHYAIDKBPCAXBBbAWAChjjgFsUAKKAQQHN6BhAQyQGMFyATKAfSgBKaggAeSEAFFRnONgCWMJMIC8xFBpR4W2dgAsUY1AHd52Pes1QUIAPwoG9AE4J6OhNNkKlKFhEMyGsZ6yCIyAHQAkkhICE6eCHKKqHYoAPKITjrJrBxcCNwJSUrCKAC0AHzoMHgIAeyWGtZ85VUAckoIpETklBAIAI5oLHhw5NTCICjySH2DKGpEmij9AygA3o3LKNhOGFvbmnBOM9hgqABEABLyFweapub3TQ6MuZw8vuwalSgY8lxuF8ojE4kVvEgIOEAOIUK5+PRMGDcBBUQRbAC+QA===

Will this help in your use case?

Gradi commented 6 days ago

@T-Gro This probably can help me, but I have already rewrote code to something different to get job done. But this is still a bug which will be fixed at some point in time, right?

T-Gro commented 6 days ago

Yes, it is a bug and needs fixing.

vzarytovskii commented 6 days ago

Disregard my (now deleted) comment.

In .NET 6 we had the following:

dotnet build
MSBuild version 17.3.2+561848881 for .NET
  Determining projects to restore...
  Restored /Users/u/code/issues/gh/17930/17930.fsproj (in 134 ms).
/Users/u/code/issues/gh/17930/Program.fs(33,9): error FS0796: 'try'/'with' cannot be used within sequence expressions [/Users/u/code/issues/gh/17930/17930.fsproj]
/Users/u/code/issues/gh/17930/Program.fs(43,9): error FS0796: 'try'/'with' cannot be used within sequence expressions [/Users/u/code/issues/gh/17930/17930.fsproj]

Build FAILED.

/Users/u/code/issues/gh/17930/Program.fs(33,9): error FS0796: 'try'/'with' cannot be used within sequence expressions [/Users/u/code/issues/gh/17930/17930.fsproj]
/Users/u/code/issues/gh/17930/Program.fs(43,9): error FS0796: 'try'/'with' cannot be used within sequence expressions [/Users/u/code/issues/gh/17930/17930.fsproj]
    0 Warning(s)
    2 Error(s)

Time Elapsed 00:00:01.58

Which has changed in https://github.com/dotnet/fsharp/pull/14540

In rc2 we fail to bind exc