Skip to content
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

breakpoints doesnt work with anonymous records in .net core sdk #6512

Closed
enricosada opened this issue Apr 12, 2019 · 36 comments · Fixed by #6608
Closed

breakpoints doesnt work with anonymous records in .net core sdk #6512

enricosada opened this issue Apr 12, 2019 · 36 comments · Fixed by #6608
Assignees
Labels
Milestone

Comments

@enricosada
Copy link
Contributor

enricosada commented Apr 12, 2019

Setting breakpoint if the code contains anonymous records, doesnt work

I not yet tried in VS, but with latest .net core debugger and latest .net core sdks affect vscode
Ionide doesnt matter, the debugger is in MS code and i am using the VSCode Debug tab with tasks.json and launch.json

Repro steps

create a simple program with dotnet new console -lang f#

[<EntryPoint>]
let main argv =
    printfn "Hello World from F#!"

    // let a = {| A = 1 |}

    printfn "A"

    // printfn "%A" a

    0 // return an integer exit code

and set some breakpoint at the instructions.
Running in debug, it stop on breakpoint and debug works

if i uncomment the lines, the debugger doesnt stop on any breakpoint (not just anon records)

if i set debugger to stop at entry point, it stop an entry and i can step by step, but breakpoint are not enabled

image

the debug info show it cannot bind the line to breakpoint

Breakpoint warning: No executable code of the debugger’s target code type is associated with this line.
Possible causes include: conditional compilation, compiler optimizations, or the target architecture of this line is not supported by the current debugger code type. - e:\temp\pwa\Program.fs:6

Expected behavior

breakpoints works

Actual behavior

breakpoints doesnt works

Known workarounds

stop at entry point maybe, in vscode is done at launch.json

            "stopAtEntry": true,

Related information

can repro in .NET Core 2.1.603 and 3.0.100-preview3-010431

.NET Core SDK (reflecting any global.json):
 Version:   2.1.603
 Commit:    ae71c68742

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.17134
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\2.1.603\

Host (useful for support):
  Version: 3.0.0-preview3-27503-5
  Commit:  3844df9537

.NET Core SDKs installed:
  2.1.603 [C:\Program Files\dotnet\sdk]
  3.0.100-preview3-010431 [C:\Program Files\dotnet\sdk]

.NET Core runtimes installed:

  Microsoft.NETCore.App 2.1.8 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.10 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.0.0-preview3-27503-5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.0.0-preview3-27504-2 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

C# VSCode extension (who contains the debugger stuff)

Name: C#
Id: ms-vscode.csharp
Description: C# for Visual Studio Code (powered by OmniSharp).
Version: 1.18.0
Publisher: Microsoft
VS Marketplace Link: https://marketplace.visualstudio.com/items?itemName=ms-vscode.csharp
@enricosada
Copy link
Contributor Author

enricosada commented Apr 12, 2019

/cc @Krzysztof-Cieslak FYI , because affect anon record debugging in vscode
/cc @auduchinok FYI, because affect Rider

@nimashoghi
Copy link

nimashoghi commented Apr 12, 2019

I can also reproduce this on Windows 10 with .NET Core 2.2.202, using both VSCode (with Ionide and Omnisharp) and Rider.

.NET Core SDK (reflecting any global.json):
 Version:   2.2.202
 Commit:    8a7ff6789d

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.17763
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\2.2.202\

Host (useful for support):
  Version: 2.2.3
  Commit:  6b8ad509b6

.NET Core SDKs installed:
  2.2.202 [C:\Program Files\dotnet\sdk]

.NET Core runtimes installed:
  Microsoft.AspNetCore.All 2.2.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.2.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 2.2.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]

To install additional .NET Core runtimes or SDKs:
  https://aka.ms/dotnet-download

@cartermp
Copy link
Contributor

Reproduced in VS as well. @dsyme @KevinRansom are we emitting the appropriate PDB info?

@cartermp
Copy link
Contributor

In VS any use of non-commented-out anonymous records breaks all ability to debug with breakpoints.

@cartermp cartermp added this to the 16.1 milestone Apr 12, 2019
@KevinRansom
Copy link
Member

@cartermp, great issue, it needs to be looked at for sure.

@cartermp
Copy link
Contributor

@dsyme @KevinRansom @TIHan this one is rather severe. It's impossible for me to debug anything if I use anonymous records. Example:

open System

[<EntryPoint>]
let main argv =
    printfn "Hey"

    let data = {| X = 1; Y = "abc" |}
    let result = data.X + data.Y.Length
    let newData = {| data with Z = data.X + 5 |}

    0 // return an integer exit code

Set a breakpoint on each line in VS and observe that none are ever hit (not even the first printfn). If I uncomment each of the anonymous record lines, it first breakpoint is hit.

@KevinRansom
Copy link
Member

I will look at it early next week, or perhaps even over the weekend.

@cartermp
Copy link
Contributor

@KevinRansom have you had a chance to look at this one?

@dsyme
Copy link
Contributor

dsyme commented Apr 22, 2019

I checked ValidateBreakpointLocationImpl and it has an entry:

                  | SynExpr.AnonRecd (_isStruct, copyExprOpt, fs, _) ->
                      match copyExprOpt with
                      | Some (e, _) -> yield! walkExpr true e
                      | None -> ()
                      yield! walkExprs (fs |> List.map snd)

so not yet sure what the cause of this could be

@cartermp
Copy link
Contributor

@dsyme IIRC that member is called when setting the breakpoint, but I'm not sure if it's called when you're actually debugging.

@lfr
Copy link

lfr commented May 29, 2019

It appears I'm still experiencing this issue after Visual Studio's 16.1.1 update with FSharp.Core 4.6.2, is there something else I need to update?

@cartermp cartermp reopened this May 29, 2019
@cartermp cartermp modified the milestones: 16.1, 16.2 May 29, 2019
@cartermp
Copy link
Contributor

Thanks @lfr, this is not resolved.

@KevinRansom @brettfo @TIHan Much of what we slated for 16.1 was never pulled in, see here: https://github.com/dotnet/fsharp/commits/Visual-Studio-2019-Version-16.1?after=42526fe359672a05fd562dc16a91a43d0fe047a7+34

@afshawnlotfi
Copy link

Is this problem fixed I still have unverified breakpoints in Vscode

@cartermp
Copy link
Contributor

cartermp commented Jun 4, 2019

@afshawnlotfi Yes, but the compiler with the fix has not be released yet.

@afshawnlotfi
Copy link

Alright well for now I guess I'll just keep everything not anonymous and put a TODO to change it later

@KevinRansom
Copy link
Member

@afshawnlotfi
Copy link

What if I want to use it with Vscode. Would I have to wait for the new version of dotnet CLI

@KevinRansom
Copy link
Member

A dotnet cli ships with the preview, and it matches the vs compiler.

@cartermp
Copy link
Contributor

@KevinRansom @brettfo @TIHan This is still not resolved in the VS 16.2 Preview 4 builds.

Can the fix get flowed into a release branch before we release?

@cartermp
Copy link
Contributor

Looks like the fix is in the branch. But it doesn't resolve anything.

@dsyme
Copy link
Contributor

dsyme commented Jun 24, 2019

@cartermp THe debugging is working for me with a fresh build of the compiler from master and running as .NET Framework program

a.fs:

[<EntryPoint>]
let main argv =
    printfn "Hello World from F#!"

    let a = {| A = 1 |}

    printfn "%A" a

    0 // return an integer exit code

then

artifacts\bin\fsc\Debug\net472\fsc -g --optimize- a.fs
devenv /debugexe a.exe

I can set break point and hit it.

I'll check .NET Core separately I suppose.

@cartermp
Copy link
Contributor

As mentioned offline we need to test netcoreapp (where it failed) and against a release branch, since master is not what is shipping

@dsyme
Copy link
Contributor

dsyme commented Jun 26, 2019

I looked at this and can repro that there is still a major problem on .NET Core. It is really surprising to have two blocking issues on this debugging.

Something about the very existence of any anon-record types in the assembly seems to hork debugging on .NET Core. I'm going to keep digging into it, but I'm quite concerned as I believe it must be something in the C# debug engine which is somehow failing for these specific types. But what that could be and why that would interfere with breakpoints specifically I really don't understand.

I'll list repro instructions here tomorrow.

@cartermp
Copy link
Contributor

Tagging @tmat as well - we'll need to dig into this for sure.

@dsyme
Copy link
Contributor

dsyme commented Jun 27, 2019

OK, I've confirmed this is something to do with portable PDB generation. I'm not sure what it could be but it's definitely the issue

If a.fs contains a use of an anonymous record then with this I can't set breakpoints:

artifacts\bin\fsc\Debug\net472\fsc.exe --debug:portable --optimize- a.fs
devenv /debugexe a.exe

but with old-fashioned PDB I can set breakpoints:

artifacts\bin\fsc\Debug\net472\fsc.exe --debug:full --optimize- a.fs
devenv /debugexe a.exe

This might be one for you @KevinRansom, or at least how do we proceed fro here - is there a tool to debug dump the portable PDB file generated

It's very odd as there's nothing that unusual about the code generated. For the record, other things I've investigated today:

  • It doesn't matter if the code containing the anonymous record isn't actually executed, the breakpoints still aren't hit if any anon recd exists in the assembly, even if it's in a different file

  • It doesn't matter if the name of the generated anon recd class is changed to be qqf__AnonymousType709851358`1 instead of <>f__AnonymousType709851358`1

  • It doesn't matter if the name of the generic type parameter for the anon recd class is Aj__TPar instead of <A>j__TPar

So what remains is pretty "normal" code for a record type really. I'm not sure why we would be failing to generate a correct portable PDB just because an anonymous record class is generated too.

@matthid
Copy link
Contributor

matthid commented Jun 28, 2019

  • Any reason why we emit a generic class for an anonymous record?
  • Maybe this is some weird bug in the debugger where it doesn't like that there is no type definition (source code reference) for one of the types and completely fails in some init code? (or something similar)

@lfr
Copy link

lfr commented Jun 28, 2019

There's been anonymous classes in C# for a while, don't F# anonymous records use the same mechanism underneath?

@matthid
Copy link
Contributor

matthid commented Jun 28, 2019

Is the debugger code itself open source? Can we somehow debug it? I couldn't find any useful documentation around that area (probably because Google fails me there). I assume it is because Omnisharp somehow seems to work on Ubuntu as well, or is that a false assumption? Maybe we can ping people who would know more?

@dsyme
Copy link
Contributor

dsyme commented Jul 2, 2019

There's been anonymous classes in C# for a while, don't F# anonymous records use the same mechanism underneath?

They do. We generate almost identical code. That's why this is so mysterious. Will try to dig into it again now.

@dsyme
Copy link
Contributor

dsyme commented Jul 2, 2019

Running pdb2xml on the portable PDB file seems to detect an error:

C:\GitHub\dsyme\visualfsharp>C:\Users\dsyme\Downloads\Pdb2Xml.1.1.0-roslyn-62714-01\tools\Pdb2Xml.exe a.exe
Invalid compressed integer.

I'll look into it more

@cartermp
Copy link
Contributor

cartermp commented Jul 2, 2019

@dsyme see here: #6728

Probably related issues then!

@afshawnlotfi
Copy link

Is this seriously still a problem now. This was reported in April. Just saying if this were C# this would have been patched the first week.

@cartermp cartermp modified the milestones: Backlog, 16.3 Jul 24, 2019
@renato04
Copy link

renato04 commented Aug 27, 2019

Hello!
I'm facing the same problem using VS2019 Community 16.2.1 targeting .net Core 2.2 using FSharp.Core 4.6.2 or VS Code

If I try to debug the following code it does not hit on printfn line

open System

[<EntryPoint>]
let main argv =
    printfn "Hello World from F#!"

    let a = {| A = 1 |}

    printfn "%A" a

    0 // return an integer exit code

But when I try to debug this code It works very well

open System
type Test =
    {A: int}
[<EntryPoint>]
let main argv =
    printfn "Hello World from F#!"

    let a = { A = 1 }

    printfn "%A" a

    0 // return an integer exit code

Do I have to install or update something?

@cartermp
Copy link
Contributor

@renato04 this will be in the compiler that corresponds to the VS 16.3 update. If you use the previews, it should already be in.

@deyanp
Copy link

deyanp commented Nov 28, 2019

@cartermp which .NET Core version works properly with F# anon records and debugger? Any 2.2.xxx?

Because of this I switched from 2.2.402 -> 3.0.100, however I am not able to migrate everything so quickly to 3.0, and wondering if there is any 2.2.xxx version which works properly ...

@cartermp
Copy link
Contributor

@deyanp it is in the 3.0.x SDK. .NET Core 2.2.x is now officially out of support, so I recommend switching to 3.0.x.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.