diff --git a/VisualFSharp.sln b/VisualFSharp.sln index a243905a780..df0b6fe31ce 100644 --- a/VisualFSharp.sln +++ b/VisualFSharp.sln @@ -192,12 +192,15 @@ EndProject Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "MicroPerf", "tests\benchmarks\CompiledCodeBenchmarks\MicroPerf\MicroPerf.fsproj", "{601CD5C1-EAFA-4AE3-8FB9-F667B5728213}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MicroPerfCSharp", "tests\benchmarks\CompiledCodeBenchmarks\MicroPerf\CS\MicroPerfCSharp.csproj", "{9F9DD315-37DA-4413-928E-1CFC6924B64F}" +EndProject Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.LanguageServer", "src\FSharp.Compiler.LanguageServer\FSharp.Compiler.LanguageServer.fsproj", "{D72F6593-DB2D-47AC-8E15-8DCE8527972E}" EndProject Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.LanguageServer.Tests", "tests\FSharp.Compiler.LanguageServer.Tests\FSharp.Compiler.LanguageServer.Tests.fsproj", "{1E83A6C8-FA4D-42BD-B4A5-B7F9AAD1B388}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FSharp.VisualStudio.Extension", "src\FSharp.VisualStudio.Extension\FSharp.VisualStudio.Extension.csproj", "{E1013576-6257-47BA-AAFB-F95B68DAB1FF}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CommonLanguageServerProtocol.Framework.Proxy", "src\Microsoft.CommonLanguageServerProtocol.Framework.Proxy\Microsoft.CommonLanguageServerProtocol.Framework.Proxy.csproj", "{FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1060,6 +1063,18 @@ Global {E1013576-6257-47BA-AAFB-F95B68DAB1FF}.Release|Any CPU.Build.0 = Release|Any CPU {E1013576-6257-47BA-AAFB-F95B68DAB1FF}.Release|x86.ActiveCfg = Release|Any CPU {E1013576-6257-47BA-AAFB-F95B68DAB1FF}.Release|x86.Build.0 = Release|Any CPU + {FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Debug|x86.ActiveCfg = Debug|Any CPU + {FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Debug|x86.Build.0 = Debug|Any CPU + {FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Proto|Any CPU.ActiveCfg = Debug|Any CPU + {FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Proto|Any CPU.Build.0 = Debug|Any CPU + {FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Proto|x86.ActiveCfg = Debug|Any CPU + {FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Proto|x86.Build.0 = Debug|Any CPU + {FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Release|Any CPU.Build.0 = Release|Any CPU + {FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Release|x86.ActiveCfg = Release|Any CPU + {FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/buildtools/AssemblyCheck/SkipVerifyEmbeddedPdb.txt b/buildtools/AssemblyCheck/SkipVerifyEmbeddedPdb.txt index 7af2a7f58cb..f7d25f2ca25 100644 --- a/buildtools/AssemblyCheck/SkipVerifyEmbeddedPdb.txt +++ b/buildtools/AssemblyCheck/SkipVerifyEmbeddedPdb.txt @@ -3,7 +3,8 @@ FSharp.Benchmarks.Common.dll FSharp.Compiler.Benchmarks.dll FSharp.Compiler.ComponentTests.dll FSharp.Test.Utilities.dll +FSharp.Compiler.LanguageServer.Tests.dll FSharp.Compiler.Private.Scripting.UnitTests.dll FSharp.Compiler.Service.Tests.dll FSharp.Core.UnitTests.dll -FSharpSuite.Tests.dll +FSharpSuite.Tests.dll \ No newline at end of file diff --git a/src/Compiler/Service/FSharpProjectSnapshot.fs b/src/Compiler/Service/FSharpProjectSnapshot.fs index 8b64a6be3a6..82f5e49804d 100644 --- a/src/Compiler/Service/FSharpProjectSnapshot.fs +++ b/src/Compiler/Service/FSharpProjectSnapshot.fs @@ -616,6 +616,7 @@ and [] FSha member _.OriginalLoadReferences = projectSnapshot.OriginalLoadReferences member _.Stamp = projectSnapshot.Stamp member _.OutputFileName = projectSnapshot.OutputFileName + member _.ProjectConfig = projectSnapshot.ProjectConfig static member Create ( diff --git a/src/Compiler/Service/FSharpWorkspace.fs b/src/Compiler/Service/FSharpWorkspace.fs index b250bce9c7b..ccde4b98fb1 100644 --- a/src/Compiler/Service/FSharpWorkspace.fs +++ b/src/Compiler/Service/FSharpWorkspace.fs @@ -22,6 +22,7 @@ open FSharpWorkspaceQuery /// Project references are discovered automatically as projects are added or updated. /// /// Updates to file contents are signaled through the `Files.Open`, `Files.Edit`, and `Files.Close` methods. +[] type FSharpWorkspace(checker: FSharpChecker) = let depGraph = LockOperatedDependencyGraph() :> IThreadSafeDependencyGraph<_, _> diff --git a/src/Compiler/Service/FSharpWorkspaceQuery.fs b/src/Compiler/Service/FSharpWorkspaceQuery.fs index 4a63655ebfd..b720608b27f 100644 --- a/src/Compiler/Service/FSharpWorkspaceQuery.fs +++ b/src/Compiler/Service/FSharpWorkspaceQuery.fs @@ -14,6 +14,7 @@ open FSharpWorkspaceState #nowarn "57" +[] type FSharpDiagnosticReport internal (diagnostics, resultId: int) = member _.Diagnostics = diagnostics @@ -21,6 +22,7 @@ type FSharpDiagnosticReport internal (diagnostics, resultId: int) = /// The result ID of the diagnostics. This needs to be unique for each version of the document in order to be able to clear old diagnostics. member _.ResultId = resultId.ToString() +[] type FSharpWorkspaceQuery internal (depGraph: IThreadSafeDependencyGraph<_, _>, checker: FSharpChecker) = let mutable resultIdCounter = 0 diff --git a/src/Compiler/Service/FSharpWorkspaceState.fs b/src/Compiler/Service/FSharpWorkspaceState.fs index 2227d03d478..cc3d3d8524d 100644 --- a/src/Compiler/Service/FSharpWorkspaceState.fs +++ b/src/Compiler/Service/FSharpWorkspaceState.fs @@ -228,6 +228,7 @@ module internal WorkspaceDependencyGraphExtensions = |> _.Unpack(WorkspaceNode.sourceFile) /// Interface for managing files in an F# workspace. +[] type FSharpWorkspaceFiles internal (depGraph: IThreadSafeDependencyGraph<_, _>) = /// Open files in the editor. @@ -255,6 +256,7 @@ type FSharpWorkspaceFiles internal (depGraph: IThreadSafeDependencyGraph<_, _>) | false, _ -> None /// Interface for managing with projects in an F# workspace. +[] type FSharpWorkspaceProjects internal (depGraph: IThreadSafeDependencyGraph<_, _>, files: FSharpWorkspaceFiles) = /// A map from project output path to project identifier. diff --git a/src/FSharp.Compiler.LanguageServer/Common/CapabilitiesManager.fs b/src/FSharp.Compiler.LanguageServer/Common/CapabilitiesManager.fs index 7632a80ce62..b8b50e95f33 100644 --- a/src/FSharp.Compiler.LanguageServer/Common/CapabilitiesManager.fs +++ b/src/FSharp.Compiler.LanguageServer/Common/CapabilitiesManager.fs @@ -15,8 +15,17 @@ type CapabilitiesManager(scOverrides: IServerCapabilitiesOverride seq) = TextDocumentSync = TextDocumentSyncOptions(OpenClose = true, Change = TextDocumentSyncKind.Full), DiagnosticOptions = DiagnosticOptions(WorkDoneProgress = true, InterFileDependencies = true, Identifier = "potato", WorkspaceDiagnostics = true), - CompletionProvider = CompletionOptions(TriggerCharacters = [| "."; " " |], ResolveProvider = true, WorkDoneProgress = true), - HoverProvider = SumType(HoverOptions(WorkDoneProgress = true)) + //CompletionProvider = CompletionOptions(TriggerCharacters = [| "."; " " |], ResolveProvider = true, WorkDoneProgress = true), + //HoverProvider = SumType(HoverOptions(WorkDoneProgress = true)) + SemanticTokensOptions = + SemanticTokensOptions( + Legend = + SemanticTokensLegend( + TokenTypes = (SemanticTokenTypes.AllTypes |> Seq.toArray), // XXX should be extended + TokenModifiers = (SemanticTokenModifiers.AllModifiers |> Seq.toArray) + ), + Range = false + ) ) interface IInitializeManager with diff --git a/src/FSharp.Compiler.LanguageServer/Common/FSharpRequestContext.fs b/src/FSharp.Compiler.LanguageServer/Common/FSharpRequestContext.fs index bef2d063d6e..85085a8bb8d 100644 --- a/src/FSharp.Compiler.LanguageServer/Common/FSharpRequestContext.fs +++ b/src/FSharp.Compiler.LanguageServer/Common/FSharpRequestContext.fs @@ -173,14 +173,15 @@ type ContextHolder(workspace, lspServices: ILspServices) = type FShapRequestContextFactory(lspServices: ILspServices) = - interface IRequestContextFactory with - - member _.CreateRequestContextAsync<'TRequestParam> - ( - queueItem: IQueueItem, - requestParam: 'TRequestParam, - cancellationToken: CancellationToken - ) = - lspServices.GetRequiredService() - |> _.GetContext() - |> Task.FromResult + inherit AbstractRequestContextFactory() + + override _.CreateRequestContextAsync<'TRequestParam> + ( + queueItem: IQueueItem, + methodHandler: IMethodHandler, + requestParam: 'TRequestParam, + cancellationToken: CancellationToken + ) = + lspServices.GetRequiredService() + |> _.GetContext() + |> Task.FromResult diff --git a/src/FSharp.Compiler.LanguageServer/Common/LifecycleManager.fs b/src/FSharp.Compiler.LanguageServer/Common/LifecycleManager.fs index cd033fc3d2f..13a97cf4a68 100644 --- a/src/FSharp.Compiler.LanguageServer/Common/LifecycleManager.fs +++ b/src/FSharp.Compiler.LanguageServer/Common/LifecycleManager.fs @@ -6,10 +6,12 @@ open StreamJsonRpc open System.Threading.Tasks open Microsoft.Extensions.DependencyInjection +#nowarn "3261" + type LspServiceLifeCycleManager() = interface ILifeCycleManager with - member this.ShutdownAsync(message: string) = + member _.ShutdownAsync(message: string) = task { try printfn "Shutting down" @@ -18,7 +20,7 @@ type LspServiceLifeCycleManager() = | :? ConnectionLostException -> () } - member this.ExitAsync() = Task.CompletedTask + member _.ExitAsync() = Task.CompletedTask type FSharpLspServices(serviceCollection: IServiceCollection) as this = @@ -27,15 +29,17 @@ type FSharpLspServices(serviceCollection: IServiceCollection) as this = let serviceProvider = serviceCollection.BuildServiceProvider() interface ILspServices with - member this.GetRequiredService<'T when 'T: not null>() : 'T = - serviceProvider.GetRequiredService<'T>() - - member this.TryGetService(t) = serviceProvider.GetService(t) + member _.GetRequiredService() = serviceProvider.GetRequiredService() - member this.GetRequiredServices() = serviceProvider.GetServices() + member _.GetService() = serviceProvider.GetService() - member this.GetRegisteredServices() = failwith "Not implemented" + member _.GetRequiredServices() = serviceProvider.GetServices() - member this.SupportsGetRegisteredServices() = false + member _.Dispose() = serviceProvider.Dispose() - member this.Dispose() = () + member _.TryGetService(``type``, service) = + match serviceProvider.GetService(``type``) with + | NonNull x -> + service <- x + true + | Null -> false diff --git a/src/FSharp.Compiler.LanguageServer/FSharp.Compiler.LanguageServer.fsproj b/src/FSharp.Compiler.LanguageServer/FSharp.Compiler.LanguageServer.fsproj index e2ea85b140c..1b5f7c99122 100644 --- a/src/FSharp.Compiler.LanguageServer/FSharp.Compiler.LanguageServer.fsproj +++ b/src/FSharp.Compiler.LanguageServer/FSharp.Compiler.LanguageServer.fsproj @@ -1,17 +1,17 @@ - + Exe net8.0 true + enable - - - - + + + @@ -32,20 +32,20 @@ + + - - - + + - \ No newline at end of file diff --git a/src/FSharp.Compiler.LanguageServer/FSharpLanguageServer.fs b/src/FSharp.Compiler.LanguageServer/FSharpLanguageServer.fs index 4af67d2100d..9d0d3ec4412 100644 --- a/src/FSharp.Compiler.LanguageServer/FSharpLanguageServer.fs +++ b/src/FSharp.Compiler.LanguageServer/FSharpLanguageServer.fs @@ -15,6 +15,8 @@ open Nerdbank.Streams open System.Diagnostics open FSharp.Compiler.CodeAnalysis.Workspace +#nowarn "57" + [] module Stuff = [] @@ -29,7 +31,9 @@ type Extensions = type FSharpLanguageServer (jsonRpc: JsonRpc, logger: ILspLogger, ?initialWorkspace: FSharpWorkspace, ?addExtraHandlers: Action) = - inherit AbstractLanguageServer(jsonRpc, logger) + + // TODO: Switch to SystemTextJsonLanguageServer + inherit NewtonsoftLanguageServer(jsonRpc, Newtonsoft.Json.JsonSerializer.CreateDefault(), logger) let initialWorkspace = defaultArg initialWorkspace (FSharpWorkspace()) @@ -39,8 +43,6 @@ type FSharpLanguageServer member _.JsonRpc: JsonRpc = jsonRpc - member private this.GetBaseHandlerProvider() = base.GetHandlerProvider() - override this.ConstructLspServices() = let serviceCollection = new ServiceCollection() @@ -53,8 +55,7 @@ type FSharpLanguageServer .AddSingleton() .AddSingleton() .AddSingleton(logger) - .AddSingleton, FShapRequestContextFactory>() - .AddSingleton(fun _ -> this.GetBaseHandlerProvider()) + .AddSingleton, FShapRequestContextFactory>() .AddSingleton, CapabilitiesManager>() .AddSingleton(this) .AddSingleton(new LspServiceLifeCycleManager()) @@ -68,7 +69,10 @@ type FSharpLanguageServer lspServices :> ILspServices static member Create() = - FSharpLanguageServer.Create(FSharpWorkspace(), (fun _ -> ())) + FSharpLanguageServer.Create(FSharpWorkspace()) + + static member Create(initialWorkspace) = + FSharpLanguageServer.Create(initialWorkspace, (fun _ -> ())) static member Create(initialWorkspace, addExtraHandlers: Action) = FSharpLanguageServer.Create(LspLogger System.Diagnostics.Trace.TraceInformation, initialWorkspace, addExtraHandlers) @@ -89,7 +93,7 @@ type FSharpLanguageServer jsonRpc.TraceSource.Listeners.Add(listener) |> ignore - jsonRpc.TraceSource.Switch.Level <- SourceLevels.Information + jsonRpc.TraceSource.Switch.Level <- SourceLevels.All let server = new FSharpLanguageServer(jsonRpc, logger, initialWorkspace, ?addExtraHandlers = addExtraHandlers) diff --git a/src/FSharp.Compiler.LanguageServer/Handlers/DocumentStateHandler.fs b/src/FSharp.Compiler.LanguageServer/Handlers/DocumentStateHandler.fs index e549b27a7c2..76135d84fe7 100644 --- a/src/FSharp.Compiler.LanguageServer/Handlers/DocumentStateHandler.fs +++ b/src/FSharp.Compiler.LanguageServer/Handlers/DocumentStateHandler.fs @@ -7,12 +7,14 @@ open FSharp.Compiler.LanguageServer.Common open System.Threading open System.Threading.Tasks +#nowarn "57" + type DocumentStateHandler() = interface IMethodHandler with member _.MutatesSolutionState = true interface IRequestHandler with - [] + [] member _.HandleRequestAsync ( request: DidOpenTextDocumentParams, @@ -26,7 +28,7 @@ type DocumentStateHandler() = Task.FromResult(SemanticTokensDeltaPartialResult()) interface IRequestHandler with - [] + [] member _.HandleRequestAsync ( request: DidChangeTextDocumentParams, @@ -40,7 +42,7 @@ type DocumentStateHandler() = Task.FromResult(SemanticTokensDeltaPartialResult()) interface INotificationHandler with - [] + [] member _.HandleNotificationAsync ( request: DidCloseTextDocumentParams, diff --git a/src/FSharp.Compiler.LanguageServer/Handlers/LanguageFeaturesHandler.fs b/src/FSharp.Compiler.LanguageServer/Handlers/LanguageFeaturesHandler.fs index d900fdfc3b8..a144cf1832b 100644 --- a/src/FSharp.Compiler.LanguageServer/Handlers/LanguageFeaturesHandler.fs +++ b/src/FSharp.Compiler.LanguageServer/Handlers/LanguageFeaturesHandler.fs @@ -2,21 +2,57 @@ open Microsoft.CommonLanguageServerProtocol.Framework open Microsoft.VisualStudio.LanguageServer.Protocol +open Microsoft.VisualStudio.FSharp.Editor.CancellableTasks open FSharp.Compiler.LanguageServer.Common +open FSharp.Compiler.LanguageServer open System.Threading.Tasks open System.Threading +open System.Collections.Generic +open Microsoft.VisualStudio.FSharp.Editor + +#nowarn "57" type LanguageFeaturesHandler() = interface IMethodHandler with member _.MutatesSolutionState = false - // TODO: this is not getting called interface IRequestHandler, FSharpRequestContext> with - [] + [] member _.HandleRequestAsync ( request: DocumentDiagnosticParams, context: FSharpRequestContext, cancellationToken: CancellationToken ) = - Task.FromResult(new RelatedUnchangedDocumentDiagnosticReport()) + cancellableTask { + + let! fsharpDiagnosticReport = context.Workspace.Query.GetDiagnosticsForFile request.TextDocument.Uri + + let report = + FullDocumentDiagnosticReport( + Items = (fsharpDiagnosticReport.Diagnostics |> Array.map (_.ToLspDiagnostic())), + ResultId = fsharpDiagnosticReport.ResultId + ) + + let relatedDocuments = Dictionary() + + relatedDocuments.Add( + request.TextDocument.Uri, + SumType report + ) + + return + SumType( + RelatedFullDocumentDiagnosticReport(RelatedDocuments = relatedDocuments) + ) + } + |> CancellableTask.start cancellationToken + + interface IRequestHandler with + [] + member _.HandleRequestAsync(request: SemanticTokensParams, context: FSharpRequestContext, cancellationToken: CancellationToken) = + cancellableTask { + let! tokens = context.GetSemanticTokensForFile(request.TextDocument.Uri) + return SemanticTokens(Data = tokens) + } + |> CancellableTask.start cancellationToken diff --git a/src/FSharp.Compiler.LanguageServer/Utils.fs b/src/FSharp.Compiler.LanguageServer/Utils.fs index abae720654e..2f19328a25f 100644 --- a/src/FSharp.Compiler.LanguageServer/Utils.fs +++ b/src/FSharp.Compiler.LanguageServer/Utils.fs @@ -1,25 +1,54 @@ -[] -module FSharp.Compiler.LanguageServer.Utils +namespace FSharp.Compiler.LanguageServer open Microsoft.CommonLanguageServerProtocol.Framework +open Microsoft.VisualStudio.LanguageServer.Protocol + +open FSharp.Compiler.Diagnostics +open System.Runtime.CompilerServices + +[] +module Utils = + + type LspRange = Microsoft.VisualStudio.LanguageServer.Protocol.Range + + let LspLogger (output: string -> unit) = + { new ILspLogger with + member this.LogEndContext(message: string, ``params``: obj array) : unit = + output $"EndContext :: {message} %A{``params``}" + + member this.LogError(message: string, ``params``: obj array) : unit = + output $"ERROR :: {message} %A{``params``}" + + member this.LogException(``exception``: exn, message: string, ``params``: obj array) : unit = + output $"EXCEPTION :: %A{``exception``} {message} %A{``params``}" + + member this.LogInformation(message: string, ``params``: obj array) : unit = + output $"INFO :: {message} %A{``params``}" -let LspLogger (output: string -> unit) = - { new ILspLogger with - member this.LogEndContext(message: string, ``params``: obj array) : unit = - output $"EndContext :: {message} %A{``params``}" + member this.LogStartContext(message: string, ``params``: obj array) : unit = + output $"StartContext :: {message} %A{``params``}" - member this.LogError(message: string, ``params``: obj array) : unit = - output $"ERROR :: {message} %A{``params``}" + member this.LogWarning(message: string, ``params``: obj array) : unit = + output $"WARNING :: {message} %A{``params``}" + } - member this.LogException(``exception``: exn, message: string, ``params``: obj array) : unit = - output $"EXCEPTION :: %A{``exception``} {message} %A{``params``}" + type FSharp.Compiler.Text.Range with - member this.LogInformation(message: string, ``params``: obj array) : unit = - output $"INFO :: {message} %A{``params``}" + member this.ToLspRange() = + LspRange( + Start = Position(Line = this.StartLine - 1, Character = this.StartColumn), + End = Position(Line = this.EndLine - 1, Character = this.EndColumn) + ) - member this.LogStartContext(message: string, ``params``: obj array) : unit = - output $"StartContext :: {message} %A{``params``}" +[] +type FSharpDiagnosticExtensions = - member this.LogWarning(message: string, ``params``: obj array) : unit = - output $"WARNING :: {message} %A{``params``}" - } + [] + static member ToLspDiagnostic(this: FSharpDiagnostic) = + Diagnostic( + Range = this.Range.ToLspRange(), + Severity = DiagnosticSeverity.Error, + Message = $"LSP: {this.Message}", + //Source = "Intellisense", + Code = SumType this.ErrorNumberText + ) diff --git a/src/FSharp.VisualStudio.Extension/ExtensionEntrypoint.cs b/src/FSharp.VisualStudio.Extension/ExtensionEntrypoint.cs index 7957511b29e..8fbaf39dc70 100644 --- a/src/FSharp.VisualStudio.Extension/ExtensionEntrypoint.cs +++ b/src/FSharp.VisualStudio.Extension/ExtensionEntrypoint.cs @@ -11,8 +11,6 @@ internal class ExtensionEntrypoint : Extension { - - /// public override ExtensionConfiguration ExtensionConfiguration => new() { diff --git a/src/FSharp.VisualStudio.Extension/FSharp.VisualStudio.Extension.csproj b/src/FSharp.VisualStudio.Extension/FSharp.VisualStudio.Extension.csproj index bef467713a0..1c946fbe71c 100644 --- a/src/FSharp.VisualStudio.Extension/FSharp.VisualStudio.Extension.csproj +++ b/src/FSharp.VisualStudio.Extension/FSharp.VisualStudio.Extension.csproj @@ -1,33 +1,33 @@  - - net8.0-windows - enable - 12 - en-US - - - - - - - - - - - - - - - - - - - - - - false - - - + + net8.0-windows + enable + 12 + en-US + + + + + + + + + + + + + + + + + + + + + + false + + + diff --git a/src/FSharp.VisualStudio.Extension/FSharpLanguageServerProvider.cs b/src/FSharp.VisualStudio.Extension/FSharpLanguageServerProvider.cs index 93bb5b39729..429570e917c 100644 --- a/src/FSharp.VisualStudio.Extension/FSharpLanguageServerProvider.cs +++ b/src/FSharp.VisualStudio.Extension/FSharpLanguageServerProvider.cs @@ -6,8 +6,6 @@ namespace FSharp.VisualStudio.Extension; using System; using System.Collections.Generic; using System.Diagnostics; -using System.IO; -using System.IO.Packaging; using System.IO.Pipelines; using System.Linq; using System.Threading; @@ -25,9 +23,6 @@ namespace FSharp.VisualStudio.Extension; using Microsoft.VisualStudio.ProjectSystem.Query; using Microsoft.VisualStudio.RpcContracts.LanguageServerProvider; using Nerdbank.Streams; -using Newtonsoft.Json.Linq; -using StreamJsonRpc; -using static FSharp.Compiler.CodeAnalysis.ProjectSnapshot; /// #pragma warning disable VSEXTPREVIEW_LSP // Type is for evaluation purposes only and is subject to change or removal in future updates. @@ -74,82 +69,48 @@ public ServerCapabilities OverrideServerCapabilities(ServerCapabilities value) { Legend = new() { - TokenTypes = [ ..SemanticTokenTypes.AllTypes], // XXX should be extended - TokenModifiers = [ ..SemanticTokenModifiers.AllModifiers] + TokenTypes = [.. SemanticTokenTypes.AllTypes], // XXX should be extended + TokenModifiers = [.. SemanticTokenModifiers.AllModifiers] }, Full = new SemanticTokensFullOptions() { Delta = false }, Range = false - }, - HoverProvider = new HoverOptions() - { - WorkDoneProgress = true } + //, + //HoverProvider = new HoverOptions() + //{ + // WorkDoneProgress = true + //} }; return capabilities; } } -internal class SemanticTokensHandler - : IRequestHandler -{ - public bool MutatesSolutionState => false; - - [LanguageServerEndpoint("textDocument/semanticTokens/full")] - public async Task HandleRequestAsync( - SemanticTokensParams request, - FSharpRequestContext context, - CancellationToken cancellationToken) - { - var tokens = await context.GetSemanticTokensForFile(request!.TextDocument!.Uri); - - return new SemanticTokens { Data = tokens }; - } -} - - internal class VsDiagnosticsHandler - : IRequestHandler, + : IRequestHandler, IRequestHandler { public bool MutatesSolutionState => false; - [LanguageServerEndpoint(VSInternalMethods.DocumentPullDiagnosticName)] - public async Task HandleRequestAsync(VSInternalDocumentDiagnosticsParams request, FSharpRequestContext context, CancellationToken cancellationToken) + [LanguageServerEndpoint(VSInternalMethods.DocumentPullDiagnosticName, LanguageServerConstants.DefaultLanguageName)] + public async Task HandleRequestAsync(VSInternalDiagnosticParams request, FSharpRequestContext context, CancellationToken cancellationToken) { - var report = await context.Workspace.Query.GetDiagnosticsForFile(request!.TextDocument!.Uri).Please(cancellationToken); + var report = await context.Workspace.Query.GetDiagnosticsForFile(request!.TextDocument!.Uri).Please(cancellationToken); - var vsReport = new VSInternalDiagnosticReport + var vsReport = new VSInternalDiagnosticReport { ResultId = report.ResultId, //Identifier = 1, //Version = 1, - - Diagnostics = - report.Diagnostics.Select(d => - - new Diagnostic - { - Range = new Microsoft.VisualStudio.LanguageServer.Protocol.Range - { - // F# uses 1-based indexing for lines, need to adjust - Start = new Position { Line = d.StartLine-1, Character = d.StartColumn }, - End = new Position { Line = d.EndLine-1, Character = d.EndColumn } - }, - Severity = DiagnosticSeverity.Error, - Message = $"LSP: {d.Message}", - //Source = "Intellisense", - Code = d.ErrorNumberText - } - ).ToArray() + Diagnostics = [.. report.Diagnostics.Select(FSharpDiagnosticExtensions.ToLspDiagnostic)] }; return [vsReport]; } - [LanguageServerEndpoint("textDocument/_vs_getProjectContexts")] + [LanguageServerEndpoint("textDocument/_vs_getProjectContexts", LanguageServerConstants.DefaultLanguageName)] public Task HandleRequestAsync(VSGetProjectContextsParams request, FSharpRequestContext context, CancellationToken cancellationToken) { return Task.FromResult(new VSProjectContextList() @@ -331,11 +292,10 @@ internal class FSharpLanguageServerProvider : LanguageServerProvider } - var ((clientStream, serverStream), _server) = FSharpLanguageServer.Create(workspace, (serviceCollection) => + var ((inputStream, outputStream), _server) = FSharpLanguageServer.Create(workspace, (serviceCollection) => { serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); }); var solutions = await ws.QuerySolutionAsync( @@ -352,10 +312,9 @@ internal class FSharpLanguageServerProvider : LanguageServerProvider .SubscribeAsync(new SolutionObserver(), CancellationToken.None); } - return new DuplexPipe( - PipeReader.Create(clientStream), - PipeWriter.Create(serverStream)); + PipeReader.Create(inputStream), + PipeWriter.Create(outputStream)); } /// diff --git a/src/Microsoft.CommonLanguageServerProtocol.Framework.Proxy/Microsoft.CommonLanguageServerProtocol.Framework.Proxy.csproj b/src/Microsoft.CommonLanguageServerProtocol.Framework.Proxy/Microsoft.CommonLanguageServerProtocol.Framework.Proxy.csproj new file mode 100644 index 00000000000..97ac5ccaebe --- /dev/null +++ b/src/Microsoft.CommonLanguageServerProtocol.Framework.Proxy/Microsoft.CommonLanguageServerProtocol.Framework.Proxy.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + + diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerService/FSharpWorkspace.fs b/tests/FSharp.Compiler.ComponentTests/CompilerService/FSharpWorkspace.fs index fbae320131d..8da785b92d8 100644 --- a/tests/FSharp.Compiler.ComponentTests/CompilerService/FSharpWorkspace.fs +++ b/tests/FSharp.Compiler.ComponentTests/CompilerService/FSharpWorkspace.fs @@ -7,35 +7,10 @@ open FSharp.Compiler.CodeAnalysis.ProjectSnapshot open TestFramework open FSharp.Compiler.IO open FSharp.Compiler.CodeAnalysis.Workspace +open FSharp.Test.ProjectGeneration.WorkspaceHelpers #nowarn "57" -type ProjectConfig with - - static member Minimal(?name, ?outputPath, ?referencesOnDisk) = - let name = defaultArg name "test" - let projectFileName = $"{name}.fsproj" - let outputPath = defaultArg outputPath $"{name}.dll" - let referencesOnDisk = defaultArg referencesOnDisk [] - ProjectConfig(projectFileName, Some outputPath, referencesOnDisk, []) - -let getReferencedSnapshot (projectIdentifier: FSharpProjectIdentifier) (projectSnapshot: FSharpProjectSnapshot) = - projectSnapshot.ReferencedProjects - |> Seq.pick (function - | FSharpReference(x, snapshot) when x = projectIdentifier.OutputFileName -> Some snapshot - | _ -> None) - -let sourceFileOnDisk (content: string) = - let path = getTemporaryFileName () + ".fs" - FileSystem.OpenFileForWriteShim(path).Write(content) - Uri(path) - -let assertFileHasContent filePath expectedContent (projectSnapshot: FSharpProjectSnapshot) = - let fileSnapshot = - projectSnapshot.SourceFiles |> Seq.find (_.FileName >> (=) filePath) - - Assert.Equal(expectedContent, fileSnapshot.GetSource().Result.ToString()) - [] let ``Add project to workspace`` () = let workspace = FSharpWorkspace() @@ -89,7 +64,7 @@ let ``Close file in workspace`` () = let fileOnDisk = sourceFileOnDisk contentOnDisk let _projectIdentifier = - workspace.Projects.AddOrUpdate(ProjectConfig.Minimal(), [ fileOnDisk.LocalPath ]) + workspace.Projects.AddOrUpdate(ProjectConfig.Empty(), [ fileOnDisk.LocalPath ]) workspace.Files.Open(fileOnDisk, contentOnDisk) @@ -123,7 +98,7 @@ let ``Change file in workspace`` () = let fileUri = Uri("file:///test.fs") let _projectIdentifier = - workspace.Projects.AddOrUpdate(ProjectConfig.Minimal(), [ fileUri.LocalPath ]) + workspace.Projects.AddOrUpdate(ProjectConfig.Empty(), [ fileUri.LocalPath ]) let initialContent = "let x = 2" @@ -177,17 +152,17 @@ let ``Propagate changes to snapshots`` () = let workspace = FSharpWorkspace() let file1 = sourceFileOnDisk "let x = 1" - let pid1 = workspace.Projects.AddOrUpdate(ProjectConfig.Minimal("p1"), [ file1.LocalPath ]) + let pid1 = workspace.Projects.AddOrUpdate(ProjectConfig.Empty("p1"), [ file1.LocalPath ]) let file2 = sourceFileOnDisk "let y = 2" let pid2 = - workspace.Projects.AddOrUpdate(ProjectConfig.Minimal("p2", referencesOnDisk = [ pid1.OutputFileName ]), [ file2.LocalPath ]) + workspace.Projects.AddOrUpdate(ProjectConfig.Empty("p2", referencesOnDisk = [ pid1.OutputFileName ]), [ file2.LocalPath ]) let file3 = sourceFileOnDisk "let z = 3" let pid3 = - workspace.Projects.AddOrUpdate(ProjectConfig.Minimal("p3", referencesOnDisk = [ pid2.OutputFileName ]), [ file3.LocalPath ]) + workspace.Projects.AddOrUpdate(ProjectConfig.Empty("p3", referencesOnDisk = [ pid2.OutputFileName ]), [ file3.LocalPath ]) let s3 = workspace.Query.GetProjectSnapshot(pid3).Value diff --git a/tests/FSharp.Compiler.LanguageServer.Tests/FSharp.Compiler.LanguageServer.Tests.fsproj b/tests/FSharp.Compiler.LanguageServer.Tests/FSharp.Compiler.LanguageServer.Tests.fsproj index dbffa2deb13..046357aafe6 100644 --- a/tests/FSharp.Compiler.LanguageServer.Tests/FSharp.Compiler.LanguageServer.Tests.fsproj +++ b/tests/FSharp.Compiler.LanguageServer.Tests/FSharp.Compiler.LanguageServer.Tests.fsproj @@ -15,7 +15,7 @@ - + @@ -37,6 +37,10 @@ + + + + diff --git a/tests/FSharp.Compiler.LanguageServer.Tests/LanguageServerTests.fs b/tests/FSharp.Compiler.LanguageServer.Tests/LanguageServerTests.fs deleted file mode 100644 index f1f633a4c0d..00000000000 --- a/tests/FSharp.Compiler.LanguageServer.Tests/LanguageServerTests.fs +++ /dev/null @@ -1,59 +0,0 @@ -module LanguageServerTests - -open System -open Xunit - -open FSharp.Compiler.LanguageServer -open StreamJsonRpc -open System.IO -open System.Diagnostics - -open Microsoft.VisualStudio.LanguageServer.Protocol -open Nerdbank.Streams - -[] -let ``The server can process the initialization message`` () = - - // Create a StringWriter to capture the output - let rpcTrace = new StringWriter() - - try - - let struct (clientStream, _serverStream) = FullDuplexStream.CreatePair() - - use formatter = new JsonMessageFormatter() - - use messageHandler = - new HeaderDelimitedMessageHandler(clientStream, clientStream, formatter) - - use jsonRpc = new JsonRpc(messageHandler) - - // Create a new TraceListener with the StringWriter - let listener = new TextWriterTraceListener(rpcTrace) - - // Add the listener to the JsonRpc TraceSource - jsonRpc.TraceSource.Listeners.Add(listener) |> ignore - - // Set the TraceLevel to Information to get all informational, warning and error messages - jsonRpc.TraceSource.Switch.Level <- SourceLevels.Information - - //jsonRpc.inv - - // Now all JsonRpc debug information will be written to the StringWriter - - let log = ResizeArray() - - let _s = new FSharpLanguageServer(jsonRpc, (LspLogger log.Add)) - - jsonRpc.StartListening() - - //let initializeParams = InitializeParams( - // ProcessId = System.Diagnostics.Process.GetCurrentProcess().Id, - // RootUri = Uri("file:///c:/temp"), - // InitializationOptions = None, - // RootPath = "file:///c:/temp") - - finally - - let _output = rpcTrace.ToString() - () diff --git a/tests/FSharp.Compiler.LanguageServer.Tests/Protocol.fs b/tests/FSharp.Compiler.LanguageServer.Tests/Protocol.fs new file mode 100644 index 00000000000..9072fbfb460 --- /dev/null +++ b/tests/FSharp.Compiler.LanguageServer.Tests/Protocol.fs @@ -0,0 +1,193 @@ +module LanguageServer.Protocol + +open System +open Xunit + +open FSharp.Compiler.LanguageServer +open StreamJsonRpc +open System.IO +open System.Diagnostics + +open Microsoft.VisualStudio.LanguageServer.Protocol +open Nerdbank.Streams + +open FSharp.Test.ProjectGeneration.WorkspaceHelpers +open FSharp.Compiler.CodeAnalysis.Workspace +open FSharp.Compiler.CodeAnalysis.ProjectSnapshot + +#nowarn "57" + +type TestRpcClient(jsonRpc, rpcTrace, workspace, initializeResult: InitializeResult) = + + member val JsonRpc = jsonRpc + member val RpcTraceWriter = rpcTrace + member val Workspace = workspace + member val Capabilities = initializeResult.Capabilities + + member _.RpcTrace = rpcTrace.ToString() + +let initializeLanguageServer (workspace) = + + let workspace = defaultArg workspace (FSharpWorkspace()) + + // Create a StringWriter to capture the output + let rpcTrace = new StringWriter() + + let (inputStream, outputStream), server = FSharpLanguageServer.Create(workspace) + + let formatter = new JsonMessageFormatter() + + let messageHandler = + new HeaderDelimitedMessageHandler(inputStream, outputStream, formatter) + + let jsonRpc = new JsonRpc(messageHandler) + + // Create a new TraceListener with the StringWriter + let listener = new TextWriterTraceListener(rpcTrace) + + // Add the listener to the JsonRpc TraceSource + server.JsonRpc.TraceSource.Listeners.Add(listener) |> ignore + + // Set the TraceLevel to Information to get all informational, warning and error messages + server.JsonRpc.TraceSource.Switch.Level <- SourceLevels.All + + let initializeParams = + InitializeParams( + ProcessId = System.Diagnostics.Process.GetCurrentProcess().Id, + RootUri = Uri("file:///c:/temp"), + InitializationOptions = None + ) + + jsonRpc.StartListening() + + task { + let! response = jsonRpc.InvokeAsync("initialize", initializeParams) + return TestRpcClient(jsonRpc, rpcTrace, workspace, response) + } + +[] +let ``The server can process the initialization message`` () = + task { + + let! client = initializeLanguageServer None + Assert.NotNull(client.Capabilities) + + } + +/// Initialize workspace, open a document, get diagnostics, edit the document, get diagnostics, close the document +[] +let ``Basic server workflow`` () = + task { + + let! client = initializeLanguageServer None + + let workspace = client.Workspace + + let contentOnDisk = "let x = 1" + let fileOnDisk = sourceFileOnDisk contentOnDisk + + let _projectIdentifier = + workspace.Projects.AddOrUpdate(ProjectConfig.Create(), [ fileOnDisk.LocalPath ]) + + do! + client.JsonRpc.NotifyAsync( + Methods.TextDocumentDidOpenName, + DidOpenTextDocumentParams( + TextDocument = TextDocumentItem(Uri = fileOnDisk, LanguageId = "F#", Version = 1, Text = contentOnDisk) + ) + ) + + let! diagnosticsResponse = + client.JsonRpc.InvokeAsync>( + Methods.TextDocumentDiagnosticName, + DocumentDiagnosticParams(TextDocument = TextDocumentIdentifier(Uri = fileOnDisk)) + ) + + Assert.Equal( + 0, + (diagnosticsResponse.First.RelatedDocuments + |> Seq.head + |> _.Value.First.Items.Length) + ) + + let contentEdit = $"{contentOnDisk}\nx <- 2" + + do! + client.JsonRpc.NotifyAsync( + Methods.TextDocumentDidChangeName, + DidChangeTextDocumentParams( + TextDocument = VersionedTextDocumentIdentifier(Uri = fileOnDisk, Version = 2), + ContentChanges = [| TextDocumentContentChangeEvent(Text = contentEdit) |] + ) + ) + + let! diagnosticsResponse = + client.JsonRpc.InvokeAsync>( + Methods.TextDocumentDiagnosticName, + DocumentDiagnosticParams(TextDocument = TextDocumentIdentifier(Uri = fileOnDisk)) + ) + + let diagnostics = + diagnosticsResponse.First.RelatedDocuments |> Seq.head |> _.Value.First.Items + + Assert.Equal(1, diagnostics.Length) + Assert.Contains("This value is not mutable", diagnostics[0].Message) + + do! + client.JsonRpc.NotifyAsync( + Methods.TextDocumentDidCloseName, + DidCloseTextDocumentParams(TextDocument = TextDocumentIdentifier(Uri = fileOnDisk)) + ) + + let! diagnosticsResponse = + client.JsonRpc.InvokeAsync>( + Methods.TextDocumentDiagnosticName, + DocumentDiagnosticParams(TextDocument = TextDocumentIdentifier(Uri = fileOnDisk)) + ) + + // We didn't save the file, so it should be again read from disk and have no diagnostics + Assert.Equal( + 0, + (diagnosticsResponse.First.RelatedDocuments + |> Seq.head + |> _.Value.First.Items.Length) + ) + } + +[] +let ``Full semantic tokens`` () = + + task { + let! client = initializeLanguageServer None + let workspace = client.Workspace + let contentOnDisk = "let x = 1" + let fileOnDisk = sourceFileOnDisk contentOnDisk + let _projectIdentifier = + workspace.Projects.AddOrUpdate(ProjectConfig.Create(), [ fileOnDisk.LocalPath ]) + do! + client.JsonRpc.NotifyAsync( + Methods.TextDocumentDidOpenName, + DidOpenTextDocumentParams( + TextDocument = TextDocumentItem(Uri = fileOnDisk, LanguageId = "F#", Version = 1, Text = contentOnDisk) + ) + ) + let! semanticTokensResponse = + client.JsonRpc.InvokeAsync( + Methods.TextDocumentSemanticTokensFullName, + SemanticTokensParams(TextDocument = TextDocumentIdentifier(Uri = fileOnDisk)) + ) + + let expected = [| 0; 0; 0; 1; 0; 0; 0; 3; 15; 0; 0; 4; 1; 17; 0; 0; 4; 1; 19; 0 |] + + Assert.Equal(expected, semanticTokensResponse.Data) + } + +[] +let ``Shutdown and exit`` () = + task { + let! client = initializeLanguageServer None + + let! _respone = client.JsonRpc.InvokeAsync<_>(Methods.ShutdownName) + + do! client.JsonRpc.NotifyAsync(Methods.ExitName) + } diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl index b66bebd1cbc..25e8adafbe9 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl @@ -2451,6 +2451,8 @@ FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Boolean get_ FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: FSharpProjectIdentifier Identifier FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: FSharpProjectIdentifier get_Identifier() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: FSharpProjectSnapshot Create(System.String, Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ReferenceOnDisk], Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot], Boolean, Boolean, System.DateTime, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet], Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`3[FSharp.Compiler.Text.Range,System.String,System.String]], Microsoft.FSharp.Core.FSharpOption`1[System.Int64]) +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: FSharpProjectSnapshot FromCommandLineArgs(System.String[], System.String, System.String) +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: FSharpProjectSnapshot FromResponseFile(System.IO.FileInfo, System.String) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: FSharpProjectSnapshot Replace(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot]) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot] SourceFiles FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot] get_SourceFiles() @@ -2473,6 +2475,8 @@ FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FS FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Core.FSharpOption`1[System.String] ProjectId FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Core.FSharpOption`1[System.String] get_OutputFileName() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Core.FSharpOption`1[System.String] get_ProjectId() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: ProjectConfig ProjectConfig +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: ProjectConfig get_ProjectConfig() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.DateTime LoadTime FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.DateTime get_LoadTime() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.String Label diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl index b66bebd1cbc..25e8adafbe9 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl @@ -2451,6 +2451,8 @@ FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Boolean get_ FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: FSharpProjectIdentifier Identifier FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: FSharpProjectIdentifier get_Identifier() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: FSharpProjectSnapshot Create(System.String, Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ReferenceOnDisk], Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot], Boolean, Boolean, System.DateTime, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet], Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`3[FSharp.Compiler.Text.Range,System.String,System.String]], Microsoft.FSharp.Core.FSharpOption`1[System.Int64]) +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: FSharpProjectSnapshot FromCommandLineArgs(System.String[], System.String, System.String) +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: FSharpProjectSnapshot FromResponseFile(System.IO.FileInfo, System.String) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: FSharpProjectSnapshot Replace(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot]) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot] SourceFiles FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot] get_SourceFiles() @@ -2473,6 +2475,8 @@ FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FS FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Core.FSharpOption`1[System.String] ProjectId FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Core.FSharpOption`1[System.String] get_OutputFileName() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Core.FSharpOption`1[System.String] get_ProjectId() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: ProjectConfig ProjectConfig +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: ProjectConfig get_ProjectConfig() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.DateTime LoadTime FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.DateTime get_LoadTime() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.String Label diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs index 197788b0e2e..2e5e5fd8961 100644 --- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs +++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs @@ -35,6 +35,8 @@ open FSharp.Test.Utilities open OpenTelemetry open OpenTelemetry.Resources open OpenTelemetry.Trace +open TestFramework +open FSharp.Compiler.IO #nowarn "57" // Experimental feature use @@ -94,7 +96,7 @@ module ReferenceHelpers = { Name = matches.Groups.[1].Value Version = version - Path = DirectoryInfo(Path.Combine(matches.Groups[3].Value, version)) }) + Path = DirectoryInfo(Path.Combine(matches.Groups[3].Value, version)) }) |> Seq.toList) let getFrameworkReference (reference: Reference) = @@ -263,7 +265,7 @@ type SyntheticProject = static member Create(name: string, [] sourceFiles: SyntheticSourceFile[]) = { SyntheticProject.Create(name) with SourceFiles = sourceFiles |> List.ofArray } - + static member CreateForScript(scriptFile: SyntheticSourceFile) = { SyntheticProject.Create() with SourceFiles = [scriptFile]; UseScriptResolutionRules = true } @@ -350,7 +352,7 @@ type SyntheticProject = OriginalLoadReferences = [] Stamp = None } - + OptionsCache.GetOrAdd(key, factory).Value @@ -484,14 +486,14 @@ let private writeFile (p: SyntheticProject) (f: SyntheticSourceFile) = let mkSyntheticProjectForResponseFile (responseFile: FileInfo) : SyntheticProject = if not responseFile.Exists then failwith $"%s{responseFile.FullName} does not exist" - + let compilerArgs = File.ReadAllLines responseFile.FullName let fsharpFileExtensions = set [| ".fs" ; ".fsi" ; ".fsx" |] let isFSharpFile (file : string) = Set.exists (fun (ext : string) -> file.EndsWith (ext, StringComparison.Ordinal)) fsharpFileExtensions - + let fsharpFiles = compilerArgs |> Array.choose (fun (line : string) -> @@ -516,7 +518,7 @@ let mkSyntheticProjectForResponseFile (responseFile: FileInfo) : SyntheticProjec implementationFiles |> List.map (fun implPath -> let id = - let fileNameWithoutExtension = Path.GetFileNameWithoutExtension implPath + let fileNameWithoutExtension = Path.GetFileNameWithoutExtension implPath let directoryOfFile = FileInfo(implPath).DirectoryName let relativeUri = Uri(responseFile.FullName).MakeRelativeUri(Uri(directoryOfFile)) let relativeFolderPath = Uri.UnescapeDataString(relativeUri.ToString()).Replace('/', Path.DirectorySeparatorChar) @@ -535,10 +537,10 @@ let mkSyntheticProjectForResponseFile (responseFile: FileInfo) : SyntheticProjec Source = File.ReadAllText implPath ExtraSource = "" EntryPoint = false - IsPhysicalFile = true + IsPhysicalFile = true } ) - + let otherOptions = compilerArgs |> Array.filter (fun line -> not (isFSharpFile line)) @@ -769,13 +771,13 @@ module ProjectOperations = |> Seq.toArray Assert.Equal<(string * int * int * int)[]>(expected |> Seq.sort |> Seq.toArray, actual) - + let expectNone x = if Option.isSome x then failwith "expected None, but was Some" - + let expectSome x = if Option.isNone x then failwith "expected Some, but was None" - + let rec saveProject (p: SyntheticProject) generateSignatureFiles checker = async { Directory.CreateDirectory(p.ProjectDir) |> ignore @@ -808,19 +810,19 @@ module ProjectOperations = let rec absorbAutoGeneratedSignatures checker (p: SyntheticProject) = async { do! saveProject p true checker - let files = [ + let files = [ for file in p.SourceFiles do if file.SignatureFile = AutoGenerated then let text = file |> getSignatureFilePath p |> File.ReadAllText { file with SignatureFile = Custom text } - else file + else file ] - let! projects = - p.DependsOn + let! projects = + p.DependsOn |> Seq.map (absorbAutoGeneratedSignatures checker) |> Async.Sequential - return - { p with + return + { p with SourceFiles = files AutoAddModules = false DependsOn = projects |> Array.toList } @@ -936,7 +938,7 @@ let SaveAndCheckProject project checker isExistingProject = Cursor = None } } -type MoveFileDirection = Up | Down +type MoveFileDirection = Up | Down type ProjectWorkflowBuilder ( @@ -1361,7 +1363,7 @@ type ProjectWorkflowBuilder if ex.IsSome then raise ex.Value return ctx } - + [] member this.TryGetRecentCheckResults(workflow: Async, fileId: string, expected) = async { @@ -1372,15 +1374,15 @@ type ProjectWorkflowBuilder let! snapshot = FSharpProjectSnapshot.FromOptions(options, getFileSnapshot ctx.Project) let r = checker.TryGetRecentCheckResultsForFile(fileName, snapshot) expected r - + match r with | Some(parseFileResults, checkFileResults) -> - let signature = getSignature(parseFileResults, FSharpCheckFileAnswer.Succeeded(checkFileResults)) + let signature = getSignature(parseFileResults, FSharpCheckFileAnswer.Succeeded(checkFileResults)) match ctx.Signatures.TryFind(fileId) with | Some priorSignature -> Assert.Equal(priorSignature, signature) | None -> () | None -> () - + return ctx } @@ -1423,7 +1425,7 @@ type SyntheticProject with projectDir ++ node.Attributes["Include"].InnerText ] |> List.partition (fun path -> path.EndsWith ".fsi") let signatureFiles = set signatureFiles - + let parseReferences refType = [ for node in fsproj.DocumentElement.SelectNodes($"//{refType}") do { Name = node.Attributes["Include"].InnerText @@ -1449,3 +1451,44 @@ type SyntheticProject with OtherOptions = [ for w in nowarns do $"--nowarn:{w}" ] } + + +module WorkspaceHelpers = + + type ProjectConfig with + + /// Creates an empty project configuration with optional parameters for name, output path, and references on disk. + static member Empty(?name, ?outputPath, ?referencesOnDisk) = + let name = defaultArg name "test" + let projectFileName = $"{name}.fsproj" + let outputPath = defaultArg outputPath $"{name}.dll" + let referencesOnDisk = defaultArg referencesOnDisk [] + ProjectConfig(projectFileName, Some outputPath, referencesOnDisk, []) + + static member Create(?name) = + let name = defaultArg name "test" + + let snapshot, _ = + CompilerAssertHelpers.checker.GetProjectSnapshotFromScript(name, SourceTextNew.ofString "", assumeDotNetFramework = false) + |> Async.RunSynchronously + snapshot.ProjectConfig + + /// Retrieves the referenced project snapshot from the given project snapshot based on the project identifier. + let getReferencedSnapshot (projectIdentifier: FSharpProjectIdentifier) (projectSnapshot: FSharpProjectSnapshot) = + projectSnapshot.ReferencedProjects + |> Seq.pick (function + | FSharpReference(x, snapshot) when x = projectIdentifier.OutputFileName -> Some snapshot + | _ -> None) + + /// Creates a temporary source file on disk with the given content and returns its URI. + let sourceFileOnDisk (content: string) = + let path = getTemporaryFileName () + ".fs" + FileSystem.OpenFileForWriteShim(path).Write(content) + Uri(path) + + /// Asserts that the file at the given path within the project snapshot has the expected content. + let assertFileHasContent filePath expectedContent (projectSnapshot: FSharpProjectSnapshot) = + let fileSnapshot = + projectSnapshot.SourceFiles |> Seq.find (_.FileName >> (=) filePath) + + Assert.Equal(expectedContent, fileSnapshot.GetSource().Result.ToString()) diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl index d59c7d2adda..331b8bb361a 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl @@ -21,7 +21,7 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x00000082][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3510-791::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001E5][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3510-792::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001E5][found Char] Unexpected type on the stack. [IL]: Error [UnmanagedPointer]: : FSharp.Compiler.Interactive.Shell+Utilities+pointerToNativeInt@110::Invoke(object)][offset 0x00000007] Unmanaged pointers are not a verifiable type. [IL]: Error [StackUnexpected]: : .$FSharpCheckerResults+dataTipOfReferences@2205::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000084][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-504::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000032][found Char] Unexpected type on the stack. diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl index be76953ef7d..16f3dd27fb0 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl @@ -28,7 +28,7 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+FsiStdinSyphon::GetLine(string, int32)][offset 0x00000039][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3510-791::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001E5][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3510-792::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001E5][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+FsiInteractionProcessor::CompletionsForPartialLID([FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompilerState, string)][offset 0x0000001B][found Char] Unexpected type on the stack. [IL]: Error [UnmanagedPointer]: : FSharp.Compiler.Interactive.Shell+Utilities+pointerToNativeInt@110::Invoke(object)][offset 0x00000007] Unmanaged pointers are not a verifiable type. [IL]: Error [StackUnexpected]: : .$FSharpCheckerResults+dataTipOfReferences@2205::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000084][found Char] Unexpected type on the stack. diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl index 1c6248ec60a..82567e7b827 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl @@ -21,7 +21,7 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x00000082][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3510-831::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001C7][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3510-832::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001C7][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$FSharpCheckerResults+GetReferenceResolutionStructuredToolTipText@2205::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000076][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-525::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000032][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-525::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x0000003B][found Char] Unexpected type on the stack. diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl index fc795ecde1b..266e340248d 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl @@ -28,7 +28,7 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+FsiStdinSyphon::GetLine(string, int32)][offset 0x00000032][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3510-831::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001C7][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3510-832::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001C7][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+FsiInteractionProcessor::CompletionsForPartialLID([FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompilerState, string)][offset 0x00000024][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$FSharpCheckerResults+GetReferenceResolutionStructuredToolTipText@2205::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000076][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.EditorServices.AssemblyContent+traverseMemberFunctionAndValues@176::Invoke([FSharp.Compiler.Service]FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue)][offset 0x0000002B][found Char] Unexpected type on the stack. diff --git a/vsintegration/src/FSharp.Editor/Common/CancellableTasks.fs b/vsintegration/src/FSharp.Editor/Common/CancellableTasks.fs index 78a28eb0de2..4299936d05a 100644 --- a/vsintegration/src/FSharp.Editor/Common/CancellableTasks.fs +++ b/vsintegration/src/FSharp.Editor/Common/CancellableTasks.fs @@ -336,7 +336,7 @@ module CancellableTasks = else let mutable awaiter = sm.ResumptionDynamicInfo.ResumptionData - :?> ICriticalNotifyCompletion + :?> ICriticalNotifyCompletion | null assert not (isNull awaiter) sm.Data.MethodBuilder.AwaitUnsafeOnCompleted(&awaiter, &sm) @@ -386,7 +386,7 @@ module CancellableTasks = (MoveNextMethodImpl<_>(fun sm -> //-- RESUMABLE CODE START __resumeAt sm.ResumptionPoint - let mutable __stack_exn: Exception = null + let mutable __stack_exn: Exception | null = null try let __stack_code_fin = code.Invoke(&sm)