ionide / ionide-vscode-fsharp

VS Code plugin for F# development
http://ionide.io
MIT License
859 stars 277 forks source link

Stack overflow in FCS after upgrading to Ionide 6 #1699

Closed samritchie closed 2 years ago

samritchie commented 2 years ago

Describe the bug

Ionide is logging a stack overflow on project open (appears to originate from FCS), Ionide launches and solution explorer is visible, but intellisense etc does not work.

Top of the stack is:

Stack overflow.
   at FSharp.Compiler.CheckComputationExpressions.|JoinExpr|_|@579(TcFileState, UnscopedTyparEnv, System.Collections.Generic.IDictionary`2<System.String,Microsoft.FSharp.Collections.FSharpList`1<System.Tuple`8<System.String,Boolean,Boolean,Boolean,Boolean,Boolean,Boolean,System.Tuple`2<Microsoft.FSharp.Core.FSharpOption`1<System.String>,MethInfo>>>>, System.Collections.Generic.IDictionary`2<System.String,Microsoft.FSharp.Collections.FSharpList`1<System.Tuple`8<System.String,Boolean,Boolean,Boolean,Boolean,Boolean,Boolean,System.Tuple`2<Microsoft.FSharp.Core.FSharpOption`1<System.String>,MethInfo>>>>, Microsoft.FSharp.Core.FSharpFunc`2<FSharp.Compiler.Syntax.Ident,Boolean>, TcEnv, FSharp.Compiler.Syntax.SynExpr)
...

Steps to reproduce

Looks like it just affects one of my projects so is probably related to specific code. FSAC used to have issues with large CEs in this project so it’s possible this is a regression related to that. I can spend some time narrowing this down to confirm if needed.

Machine info

Let me know if there’s somewhere more appropriate to raise this issue, I'm never clear where FCS/FSAC problems are meant to go.

baronfel commented 2 years ago

This is likely something that should be looked into in FCS itself - if you have a specific sample I could check it in more detail and confirm this.

samritchie commented 2 years ago

Narrowed it down to the same file that used to have issues with early versions of netcore FSAC - the following code repros for me in a minimal project. 37 seems to be the magic number but it’s possible this varies by environment.

open Chiron

type LargeRecord =
    {
        Property1: string
        Property2: string
        Property3: string
        Property4: string
        Property5: string
        Property6: string
        Property7: string
        Property8: string
        Property9: string
        Property10: string
        Property11: string
        Property12: string
        Property13: string
        Property14: string
        Property15: string
        Property16: string
        Property17: string
        Property18: string
        Property19: string
        Property20: string
        Property21: string
        Property22: string
        Property23: string
        Property24: string
        Property25: string
        Property26: string
        Property27: string
        Property28: string
        Property29: string
        Property30: string
        Property31: string
        Property32: string
        Property33: string
        Property34: string
        Property35: string
        Property36: string
        Property37: string
    }
    with
    static member ToJson(x: LargeRecord) = json {
        do! Json.write "property1" x.Property1
        do! Json.write "property2" x.Property2
        do! Json.write "property3" x.Property3
        do! Json.write "property4" x.Property4
        do! Json.write "property5" x.Property5
        do! Json.write "property6" x.Property6
        do! Json.write "property7" x.Property7
        do! Json.write "property8" x.Property8
        do! Json.write "property9" x.Property9
        do! Json.write "property10" x.Property10
        do! Json.write "property11" x.Property11
        do! Json.write "property12" x.Property12
        do! Json.write "property13" x.Property13
        do! Json.write "property14" x.Property14
        do! Json.write "property15" x.Property15
        do! Json.write "property16" x.Property16
        do! Json.write "property17" x.Property17
        do! Json.write "property18" x.Property18
        do! Json.write "property19" x.Property19
        do! Json.write "property20" x.Property20
        do! Json.write "property21" x.Property21
        do! Json.write "property22" x.Property22
        do! Json.write "property23" x.Property23
        do! Json.write "property24" x.Property24
        do! Json.write "property25" x.Property25
        do! Json.write "property26" x.Property26
        do! Json.write "property27" x.Property27
        do! Json.write "property28" x.Property28
        do! Json.write "property29" x.Property29
        do! Json.write "property30" x.Property30
        do! Json.write "property31" x.Property31
        do! Json.write "property32" x.Property32
        do! Json.write "property33" x.Property33
        do! Json.write "property34" x.Property34
        do! Json.write "property35" x.Property35
        do! Json.write "property36" x.Property36
        do! Json.write "property37" x.Property37
    }
baronfel commented 2 years ago

This sounds a lot like the kinds of work that was mitigated by https://github.com/dotnet/fsharp/issues/9231 and https://github.com/dotnet/fsharp/issues/6636. Light evidence for this is that this script works great in the latest Ionide on my Windows machine. Can you try setting COMPlus_DefaultStackSize=180000 code . or the equivalent in a shell to launch Ionide in one of your projects and see if that changes the ability of FSAC to typecheck your file? If it does then we're looking at needed more optimization work done on the compiler upstream.

samritchie commented 2 years ago

@baronfel yes, the increased stack size allowed FSAC to complete typechecking the above file - it took about 50s on a new M1 Max though

samritchie commented 2 years ago

I should clarify I'm running the arm64 dotnet, not x86 via Rosetta.

.NET SDK (reflecting any global.json):
 Version:   6.0.201
 Commit:    ef40e6aa06

Runtime Environment:
 OS Name:     Mac OS X
 OS Version:  12.3
 OS Platform: Darwin
 RID:         osx.12-arm64
 Base Path:   /usr/local/share/dotnet/sdk/6.0.201/

Host (useful for support):
  Version: 6.0.3
  Commit:  c24d9a9c91

.NET SDKs installed:
  6.0.201 [/usr/local/share/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 6.0.3 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 6.0.3 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
samritchie commented 2 years ago

Tracing through the versions, it looks like there must have been a performance regression between FCS 41.0.1 and 41.0.3 - Ionide 5.12.0 with FSAC v0.51.0 has no problem with the code.

baronfel commented 2 years ago

That's compelling enough evidence to warrant an issue upstream at dotnet/fsharp. If you like I can do so, or you can. Let me know which you prefer. The sample code you've given here is a perfectly fine repro (though I'd suggest making it a standalone FSX script by adding #r "nuget: Chiron" to the top of it).

samritchie commented 2 years ago

Thanks @baronfel, I can raise the issue.

samritchie commented 2 years ago

Raised https://github.com/dotnet/fsharp/issues/13084