Skip to content

Debugger does not step into F# computation expressions definition in .NET Core 2.0 project #3555

@vasily-kirichenko

Description

@vasily-kirichenko
  1. Create a F# .NET Core 2.0 console project.
  2. Put the following code into Program.fs:
open System
open System.Diagnostics

[<Sealed>]
type MaybeBuilder () =
//    [<DebuggerStepThrough>]
    member inline __.Return value: 'T option =
        Some value

//    [<DebuggerStepThrough>]
    member inline __.ReturnFrom value: 'T option =
        value

//    [<DebuggerStepThrough>]
    member inline __.Zero (): unit option =
        Some ()

//    [<DebuggerStepThrough>]
    member __.Delay (f: unit -> 'T option): 'T option =
        f ()

//    [<DebuggerStepThrough>]
    member inline __.Combine (r1, r2: 'T option): 'T option =
        match r1 with
        | None ->
            None
        | Some () ->
            r2

    //[<DebuggerStepThrough>]
    member inline __.Bind (value, f: 'T -> 'U option): 'U option =
        Option.bind f value

//    [<DebuggerStepThrough>]
    member __.Using (resource: ('T :> System.IDisposable), body: _ -> _ option): _ option =
        try body resource
        finally
            if not <| obj.ReferenceEquals (null, box resource) then
                resource.Dispose ()

//    [<DebuggerStepThrough>]
    member x.While (guard, body: _ option): _ option =
        if guard () then
            // OPTIMIZE: This could be simplified so we don't need to make calls to Bind and While.
            x.Bind (body, (fun () -> x.While (guard, body)))
        else
            x.Zero ()

//    [<DebuggerStepThrough>]
    member x.For (sequence: seq<_>, body: 'T -> unit option): _ option =
        // OPTIMIZE: This could be simplified so we don't need to make calls to Using, While, Delay.
        x.Using (sequence.GetEnumerator (), fun enum ->
            x.While (
                enum.MoveNext,
                x.Delay (fun () ->
                    body enum.Current)))

[<AutoOpen>]
module Maybe =
    let maybe = MaybeBuilder()

[<EntryPoint>]
let main argv =
    let x =
        maybe {
            let! x = Some 1
            let! y = Some 2
            return x + y
        }

    printfn "%A" x
    Console.ReadKey() |> ignore
    0
  1. Put a breakpoint on let! x = Some 1 line.
  2. Start debugging and wait until it stops on the breakpoint.
  3. Perform "Step into (F11)" action.

Expected result: the debugger goes into MaybeBuilder.Bind method.
Actual result: the debugger moves to let! y = Some 2 line.

Note: this would be expected behavior if all the commented out [<DebuggerStepThrough>] attributes were uncommented.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions