Skip to content

Using computation builder TryWith with a non-Exception parameter generates invalid IL #19061

@IS4Code

Description

@IS4Code

When a computation builder defines a TryWith method whose exception handler does not actually take an Exception as its parameter, an invalid CIL is produced from such a try/with construction.

Repro steps

type ResultBuilder() =
  member _.Delay(f : _ -> Result<_, _>) = f
  member _.Run(f : _ -> Result<_, _>) = f()

  member _.Zero() = Ok()
  member _.Return(value) = Ok value
  member _.ReturnFrom(result : Result<_, _>) = result
  member _.Bind(result : Result<_, _>, f) = Result.bind f result
  member _.Combine(result : Result<_, _>, f) = Result.bind f result
  
  member _.TryWith(f : unit -> _, fail : _ -> _) =
    let result = f()
    match result with
    | Ok _ -> result
    | Error _ -> fail result

let result = ResultBuilder()

let test() =
 result { 
   try 
    do! Error "test"
   with
   | Error msg -> System.Console.WriteLine msg
 }

let _ = test()

Expected behavior

The code should either fail to compile, or compile to a program that runs and behaves as expected, i.e. prints "test".

Actual behavior

The code compiles but fails at runtime with:

System.InvalidProgramException: Common Language Runtime detected an invalid program.

This is caused by the construction of ExceptionDispatchInfo in case the "exception" is not matched:

ldarg.1 // valuetype [FSharp.Core]Microsoft.FSharp.Core.FSharpResult`2<class [FSharp.Core]Microsoft.FSharp.Core.Unit, string>
call class [System.Runtime]System.Runtime.ExceptionServices.ExceptionDispatchInfo [System.Runtime]System.Runtime.ExceptionServices.ExceptionDispatchInfo::Capture(class [System.Runtime]System.Exception)
callvirt instance void [System.Runtime]System.Runtime.ExceptionServices.ExceptionDispatchInfo::Throw()

This attempts to use a Result argument instead of Exception, resulting in an invalid program.

Known workarounds

Using actual exceptions for this purpose.

Related information

Environment: .NET 9.0.303, sharplab.io

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area-ComputationExpressionsEnd-to-end experience for computation expressions (except async and state machine compilation)Bug

    Type

    Projects

    Status

    New

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions