diff --git a/docs/builder-caches.md b/docs/builder-caches.md new file mode 100644 index 00000000000..90d7e2e471d --- /dev/null +++ b/docs/builder-caches.md @@ -0,0 +1,13 @@ +--- +title: IncrementalBuilder caches +category: Language Service Internals +categoryindex: 300 +index: 1300 +--- +# IncrementalBuilder SyntaxTree cache + +Incremental builder keeps in a cache at most one `ParsedInput` for each file it parses. +This behavior can be toggled with `useSyntaxTreeCache` parameter. + +Memory impact of this feature can be in range of tens of MB for larger solutions. This can be inspected in memory profilng tools by searching for `ParsedInput` instances. +When partial checking is enabled, implementation files backed by signature will not be parsed or cached, as expected. diff --git a/src/Compiler/Facilities/BuildGraph.fs b/src/Compiler/Facilities/BuildGraph.fs index b8ee50564c1..5f9f80b7f14 100644 --- a/src/Compiler/Facilities/BuildGraph.fs +++ b/src/Compiler/Facilities/BuildGraph.fs @@ -228,14 +228,14 @@ module GraphNode = | None -> () [] -type GraphNode<'T>(retryCompute: bool, computation: NodeCode<'T>) = +type GraphNode<'T> private (retryCompute: bool, computation: NodeCode<'T>, cachedResult: Task<'T>, cachedResultNode: NodeCode<'T>) = let gate = obj () let mutable computation = computation let mutable requestCount = 0 - let mutable cachedResult: Task<'T> = Unchecked.defaultof<_> - let mutable cachedResultNode: NodeCode<'T> = Unchecked.defaultof<_> + let mutable cachedResult: Task<'T> = cachedResult + let mutable cachedResultNode: NodeCode<'T> = cachedResultNode let isCachedResultNodeNotNull () = not (obj.ReferenceEquals(cachedResultNode, null)) @@ -429,4 +429,9 @@ type GraphNode<'T>(retryCompute: bool, computation: NodeCode<'T>) = member _.IsComputing = requestCount > 0 + static member FromResult(result: 'T) = + let nodeResult = node.Return result + GraphNode(true, nodeResult, Task.FromResult(result), nodeResult) + + new(retryCompute: bool, computation) = GraphNode(retryCompute, computation, Unchecked.defaultof<_>, Unchecked.defaultof<_>) new(computation) = GraphNode(retryCompute = true, computation = computation) diff --git a/src/Compiler/Facilities/BuildGraph.fsi b/src/Compiler/Facilities/BuildGraph.fsi index b94c6e30b26..5afb43e5f08 100644 --- a/src/Compiler/Facilities/BuildGraph.fsi +++ b/src/Compiler/Facilities/BuildGraph.fsi @@ -102,6 +102,9 @@ type internal GraphNode<'T> = /// By default, 'retryCompute' is 'true'. new: computation: NodeCode<'T> -> GraphNode<'T> + /// Creates a GraphNode with given result already cached. + static member FromResult: 'T -> GraphNode<'T> + /// Return NodeCode which, when executed, will get the value of the computation if already computed, or /// await an existing in-progress computation for the node if one exists, or else will synchronously /// start the computation on the current thread. diff --git a/src/Compiler/Service/IncrementalBuild.fs b/src/Compiler/Service/IncrementalBuild.fs index 57562813eb9..7977b2d9701 100644 --- a/src/Compiler/Service/IncrementalBuild.fs +++ b/src/Compiler/Service/IncrementalBuild.fs @@ -7,7 +7,6 @@ open System.Collections.Generic open System.Collections.Immutable open System.Diagnostics open System.IO -open System.IO.Compression open System.Threading open Internal.Utilities.Library open Internal.Utilities.Collections @@ -18,7 +17,6 @@ open FSharp.Compiler.CheckBasics open FSharp.Compiler.CheckDeclarations open FSharp.Compiler.CompilerConfig open FSharp.Compiler.CompilerDiagnostics -open FSharp.Compiler.CompilerGlobalState open FSharp.Compiler.CompilerImports open FSharp.Compiler.CompilerOptions open FSharp.Compiler.CreateILModule @@ -30,7 +28,6 @@ open FSharp.Compiler.IO open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.NameResolution open FSharp.Compiler.ParseAndCheckInputs -open FSharp.Compiler.Syntax.PrettyNaming open FSharp.Compiler.ScriptClosure open FSharp.Compiler.Syntax open FSharp.Compiler.TcGlobals @@ -41,14 +38,13 @@ open FSharp.Compiler.TypedTree open FSharp.Compiler.TypedTreeOps open FSharp.Compiler.BuildGraph - [] module internal IncrementalBuild = let mutable injectCancellationFault = false let LocallyInjectCancellationFault() = injectCancellationFault <- true - { new IDisposable with member _.Dispose() = injectCancellationFault <- false } + { new IDisposable with member _.Dispose() = injectCancellationFault <- false } // Record the most recent IncrementalBuilder events, so we can more easily unit test/debug the // 'incremental' behavior of the product. @@ -97,9 +93,16 @@ module IncrementalBuilderEventTesting = module Tc = CheckExpressions +type internal FSharpFile = { + Range: range + Source: FSharpSource + Flags: bool * bool + } + // This module is only here to contain the SyntaxTree type as to avoid ambiguity with the module FSharp.Compiler.Syntax. [] module IncrementalBuildSyntaxTree = + open System.Runtime.CompilerServices /// Information needed to lazily parse a file to get a ParsedInput. Internally uses a weak cache. [] @@ -107,78 +110,82 @@ module IncrementalBuildSyntaxTree = tcConfig: TcConfig, fileParsed: Event, lexResourceManager, - sourceRange: range, - source: FSharpSource, - isLastCompiland + file: FSharpFile, + useCache ) = - let fileName = source.FilePath - let mutable weakCache: WeakReference<_> option = None - - let parse(sigNameOpt: QualifiedNameOfFile option) = + static let cache = ConditionalWeakTable() + + let fileName = file.Source.FilePath + let sourceRange = file.Range + let source = file.Source + let isLastCompiland = file.Flags + + let isImplFile = FSharpImplFileSuffixes |> List.exists (FileSystemUtils.checkSuffix fileName) + + let parsedImplFileStub sigName = + ParsedInput.ImplFile( + ParsedImplFileInput( + fileName, + false, + sigName, + [], + [], + [], + isLastCompiland, + { ConditionalDirectives = []; CodeComments = [] }, + Set.empty + ) + ), sourceRange, fileName, [||] + let parse _ = let diagnosticsLogger = CompilationDiagnosticLogger("Parse", tcConfig.diagnosticsOptions) // Return the disposable object that cleans up use _holder = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parse) - - try - IncrementalBuilderEventTesting.MRU.Add(IncrementalBuilderEventTesting.IBEParsed fileName) - let canSkip = sigNameOpt.IsSome && FSharpImplFileSuffixes |> List.exists (FileSystemUtils.checkSuffix fileName) - use act = - Activity.start "IncrementalBuildSyntaxTree.parse" - [| - Activity.Tags.fileName, source.FilePath - "buildPhase", BuildPhase.Parse.ToString() - "canSkip", canSkip.ToString() - |] - let input = - if canSkip then - ParsedInput.ImplFile( - ParsedImplFileInput( - fileName, - false, - sigNameOpt.Value, - [], - [], - [], - isLastCompiland, - { ConditionalDirectives = []; CodeComments = [] }, - Set.empty - ) - ) - else - use text = source.GetTextContainer() - match text with - | TextContainer.Stream(stream) -> - ParseOneInputStream(tcConfig, lexResourceManager, fileName, isLastCompiland, diagnosticsLogger, false, stream) - | TextContainer.SourceText(sourceText) -> - ParseOneInputSourceText(tcConfig, lexResourceManager, fileName, isLastCompiland, diagnosticsLogger, sourceText) - | TextContainer.OnDisk -> - ParseOneInputFile(tcConfig, lexResourceManager, fileName, isLastCompiland, diagnosticsLogger, true) + try + use text = source.GetTextContainer() + let input = + match text with + | TextContainer.Stream(stream) -> + ParseOneInputStream(tcConfig, lexResourceManager, fileName, isLastCompiland, diagnosticsLogger, false, stream) + | TextContainer.SourceText(sourceText) -> + ParseOneInputSourceText(tcConfig, lexResourceManager, fileName, isLastCompiland, diagnosticsLogger, sourceText) + | TextContainer.OnDisk -> + ParseOneInputFile(tcConfig, lexResourceManager, fileName, isLastCompiland, diagnosticsLogger, true) fileParsed.Trigger fileName - let res = input, sourceRange, fileName, diagnosticsLogger.GetDiagnostics() - // If we do not skip parsing the file, then we can cache the real result. - if not canSkip then - weakCache <- Some(WeakReference<_>(res)) - res + input, sourceRange, fileName, diagnosticsLogger.GetDiagnostics() + with exn -> let msg = sprintf "unexpected failure in SyntaxTree.parse\nerror = %s" (exn.ToString()) System.Diagnostics.Debug.Assert(false, msg) failwith msg - /// Parse the given file and return the given input. - member _.Parse sigNameOpt = - match weakCache with - | Some weakCache -> - match weakCache.TryGetTarget() with - | true, res -> res - | _ -> parse sigNameOpt - | _ -> parse sigNameOpt + let parseOrSkip sigNameOpt = + IncrementalBuilderEventTesting.MRU.Add(IncrementalBuilderEventTesting.IBEParsed fileName) + use _ = + Activity.start "IncrementalBuildSyntaxTree.parseOrSkip" + [| + Activity.Tags.fileName, fileName + "buildPhase", BuildPhase.Parse.ToString() + "canSkip", (isImplFile && sigNameOpt |> Option.isSome).ToString() + |] + + match sigNameOpt with + | Some sigName when isImplFile -> parsedImplFileStub sigName + | _ when useCache -> + match cache.TryGetValue file with + | true, result -> + Activity.addEvent Activity.Events.cacheHit + result + | _ -> cache.GetValue(file, parse) + | _ -> parse file - member _.Invalidate() = - SyntaxTree(tcConfig, fileParsed, lexResourceManager, sourceRange, source, isLastCompiland) + /// Parse the given file and return the given input. + member _.Parse(sigNameOpt) = parseOrSkip sigNameOpt + + static member Invalidate(source) = cache.Remove(source) |> ignore member _.FileName = fileName @@ -268,7 +275,7 @@ type TcInfoNode = static member FromState(state: TcInfoState) = let tcInfo = state.TcInfo let tcInfoExtras = state.TcInfoExtras - TcInfoNode(GraphNode(node.Return tcInfo), GraphNode(node.Return (tcInfo, defaultArg tcInfoExtras emptyTcInfoExtras))) + TcInfoNode(GraphNode.FromResult tcInfo, GraphNode.FromResult (tcInfo, defaultArg tcInfoExtras emptyTcInfoExtras)) /// Bound model of an underlying syntax and typed tree. [] @@ -352,11 +359,6 @@ type BoundModel private (tcConfig: TcConfig, // If partial checking is enabled and we have a backing sig file, then use the partial state. The partial state contains the sig state. if tcInfoNode.HasFull && enablePartialTypeChecking && hasSig then - // Always invalidate the syntax tree cache. - let newSyntaxTreeOpt = - syntaxTreeOpt - |> Option.map (fun x -> x.Invalidate()) - let newTcInfoStateOpt = match tcInfoNode with | TcInfoNode(_, fullGraphNode) -> @@ -374,7 +376,7 @@ type BoundModel private (tcConfig: TcConfig, beforeFileChecked, fileChecked, prevTcInfo, - newSyntaxTreeOpt, + syntaxTreeOpt, newTcInfoStateOpt) else this @@ -736,11 +738,6 @@ type RawFSharpAssemblyDataBackedByLanguageService (tcConfig, tcGlobals, generate [] module IncrementalBuilderHelpers = - /// Get the timestamp of the given file name. - let StampFileNameTask (cache: TimeStampCache) (_m: range, source: FSharpSource, _isLastCompiland) notifiedTime = - notifiedTime - |> Option.defaultWith (fun () -> cache.GetFileTimeStamp source.FilePath) - /// Timestamps of referenced assemblies are taken from the file's timestamp. let StampReferencedAssemblyTask (cache: TimeStampCache) (_ref, timeStamper) = timeStamper cache @@ -949,8 +946,7 @@ module IncrementalBuilderHelpers = return ilAssemRef, tcAssemblyDataOpt, tcAssemblyExprOpt, finalBoundModelWithErrors } - let GetSyntaxTree tcConfig fileParsed lexResourceManager (sourceRange: range, source, isLastCompiland) = - SyntaxTree(tcConfig, fileParsed, lexResourceManager, sourceRange, source, isLastCompiland) + let GetSyntaxTree tcConfig fileParsed lexResourceManager file useCache = SyntaxTree(tcConfig, fileParsed, lexResourceManager, file, useCache) [] type IncrementalBuilderInitialState = @@ -962,7 +958,7 @@ type IncrementalBuilderInitialState = outfile: string assemblyName: string lexResourceManager: Lexhelp.LexResourceManager - fileNames: ImmutableArray + fileNames: ImmutableArray enablePartialTypeChecking: bool beforeFileChecked: Event fileChecked: Event @@ -975,26 +971,30 @@ type IncrementalBuilderInitialState = defaultTimeStamp: DateTime mutable isImportsInvalidated: bool useChangeNotifications: bool + useSyntaxTreeCache: bool } - static member Create( - initialBoundModel: BoundModel, - tcGlobals, - nonFrameworkAssemblyInputs, - tcConfig: TcConfig, - outfile, - assemblyName, - lexResourceManager, - sourceFiles, - enablePartialTypeChecking, - beforeFileChecked: Event, - fileChecked: Event, + static member Create + ( + initialBoundModel: BoundModel, + tcGlobals, + nonFrameworkAssemblyInputs, + tcConfig: TcConfig, + outfile, + assemblyName, + lexResourceManager, + sourceFiles, + enablePartialTypeChecking, + beforeFileChecked: Event, + fileChecked: Event, #if !NO_TYPEPROVIDERS - importsInvalidatedByTypeProvider: Event, + importsInvalidatedByTypeProvider: Event, #endif - allDependencies, - defaultTimeStamp: DateTime, - useChangeNotifications: bool) = + allDependencies, + defaultTimeStamp: DateTime, + useChangeNotifications: bool, + useSyntaxTreeCache + ) = let initialState = { @@ -1018,6 +1018,7 @@ type IncrementalBuilderInitialState = defaultTimeStamp = defaultTimeStamp isImportsInvalidated = false useChangeNotifications = useChangeNotifications + useSyntaxTreeCache = useSyntaxTreeCache } #if !NO_TYPEPROVIDERS importsInvalidatedByTypeProvider.Publish.Add(fun () -> initialState.isImportsInvalidated <- true) @@ -1043,12 +1044,12 @@ type IncrementalBuilderState = module IncrementalBuilderStateHelpers = let createBoundModelGraphNode (initialState: IncrementalBuilderInitialState) initialBoundModel (boundModels: ImmutableArray>.Builder) i = - let fileInfo = initialState.fileNames[i] + let file = initialState.fileNames[i] let prevBoundModelGraphNode = match i with | 0 (* first file *) -> initialBoundModel | _ -> boundModels[i - 1] - let syntaxTree = GetSyntaxTree initialState.tcConfig initialState.fileParsed initialState.lexResourceManager fileInfo + let syntaxTree = GetSyntaxTree initialState.tcConfig initialState.fileParsed initialState.lexResourceManager file initialState.useSyntaxTreeCache GraphNode(node { let! prevBoundModel = prevBoundModelGraphNode.GetOrComputeValue() return! TypeCheckTask initialState.enablePartialTypeChecking prevBoundModel syntaxTree @@ -1057,11 +1058,17 @@ module IncrementalBuilderStateHelpers = let rec createFinalizeBoundModelGraphNode (initialState: IncrementalBuilderInitialState) (boundModels: ImmutableArray>.Builder) = GraphNode(node { use _ = Activity.start "GetCheckResultsAndImplementationsForProject" [|Activity.Tags.project, initialState.outfile|] - // Compute last bound model then get all the evaluated models. + + // Compute last bound model then get all the evaluated models*. let! _ = boundModels[boundModels.Count - 1].GetOrComputeValue() - let boundModels = - boundModels.ToImmutable() - |> ImmutableArray.map (fun x -> x.TryPeekValue().Value) + let! boundModels = + boundModels + |> Seq.map (fun x -> + match x.TryPeekValue() with + | ValueSome v -> node.Return v + // *Evaluating the last bound model doesn't always guarantee that all the other bound models are evaluated. + | _ -> node.ReturnFrom(x.GetOrComputeValue())) + |> NodeCode.Sequential let! result = FinalizeTypeCheckTask @@ -1070,24 +1077,35 @@ module IncrementalBuilderStateHelpers = initialState.enablePartialTypeChecking initialState.assemblyName initialState.outfile - boundModels + (boundModels.ToImmutableArray()) let result = (result, DateTime.UtcNow) return result }) - and computeStampedFileName (initialState: IncrementalBuilderInitialState) (state: IncrementalBuilderState) (cache: TimeStampCache) slot fileInfo = - let currentStamp = state.stampedFileNames[slot] - let notifiedStamp = if initialState.useChangeNotifications then Some state.notifiedStampedFileNames[slot] else None - let stamp = StampFileNameTask cache fileInfo notifiedStamp + and computeStampedFileNames (initialState: IncrementalBuilderInitialState) (state: IncrementalBuilderState) (cache: TimeStampCache) = + + let getStamp slot = + if initialState.useChangeNotifications then + state.notifiedStampedFileNames[slot] + else + cache.GetFileTimeStamp initialState.fileNames[slot].Source.FilePath + + let modified = + [ for i, file in initialState.fileNames |> Seq.indexed do + let stamp = getStamp i + if state.stampedFileNames[i] <> stamp then + i, stamp, file ] + + for _, _, f in modified do SyntaxTree.Invalidate f - if currentStamp <> stamp then + let computeStampedFileName state (slot, stamp, _) = match state.boundModels[slot].TryPeekValue() with // This prevents an implementation file that has a backing signature file from invalidating the rest of the build. | ValueSome(boundModel) when initialState.enablePartialTypeChecking && boundModel.BackingSignature.IsSome -> let newBoundModel = boundModel.ClearTcInfoExtras() { state with - boundModels = state.boundModels.RemoveAt(slot).Insert(slot, GraphNode(node.Return newBoundModel)) - stampedFileNames = state.stampedFileNames.SetItem(slot, StampFileNameTask cache fileInfo notifiedStamp) + boundModels = state.boundModels.SetItem(slot, GraphNode.FromResult newBoundModel) + stampedFileNames = state.stampedFileNames.SetItem(slot, stamp) } | _ -> @@ -1096,12 +1114,11 @@ module IncrementalBuilderStateHelpers = let boundModels = state.boundModels.ToBuilder() // Invalidate the file and all files below it. - for j = 0 to stampedFileNames.Count - slot - 1 do - let notifiedStamp = if initialState.useChangeNotifications then Some state.notifiedStampedFileNames.[slot + j] else None - let stamp = StampFileNameTask cache initialState.fileNames[slot + j] notifiedStamp - stampedFileNames[slot + j] <- stamp - logicalStampedFileNames[slot + j] <- stamp - boundModels[slot + j] <- createBoundModelGraphNode initialState state.initialBoundModel boundModels (slot + j) + for j = slot to stampedFileNames.Count - 1 do + let stamp = getStamp j + stampedFileNames[j] <- stamp + logicalStampedFileNames[j] <- stamp + boundModels[j] <- createBoundModelGraphNode initialState state.initialBoundModel boundModels j { state with // Something changed, the finalized view of the project must be invalidated. @@ -1111,17 +1128,9 @@ module IncrementalBuilderStateHelpers = logicalStampedFileNames = logicalStampedFileNames.ToImmutable() boundModels = boundModels.ToImmutable() } - else - state - and computeStampedFileNames (initialState: IncrementalBuilderInitialState) state (cache: TimeStampCache) = - let mutable i = 0 - (state, initialState.fileNames) - ||> ImmutableArray.fold (fun state fileInfo -> - let newState = computeStampedFileName initialState state cache i fileInfo - i <- i + 1 - newState - ) + (state, modified) + ||> List.fold computeStampedFileName and computeStampedReferencedAssemblies (initialState: IncrementalBuilderInitialState) state canTriggerInvalidation (cache: TimeStampCache) = let stampedReferencedAssemblies = state.stampedReferencedAssemblies.ToBuilder() @@ -1162,7 +1171,7 @@ type IncrementalBuilderState with let referencedAssemblies = initialState.referencedAssemblies let cache = TimeStampCache(defaultTimeStamp) - let initialBoundModel = GraphNode(node.Return initialBoundModel) + let initialBoundModel = GraphNode.FromResult initialBoundModel let boundModels = ImmutableArrayBuilder.create fileNames.Length for slot = 0 to fileNames.Length - 1 do @@ -1406,10 +1415,10 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc member _.TryGetSlotOfFileName(fileName: string) = // Get the slot of the given file and force it to build. - let CompareFileNames (_, f2: FSharpSource, _) = + let CompareFileNames f = let result = - String.Compare(fileName, f2.FilePath, StringComparison.CurrentCultureIgnoreCase)=0 - || String.Compare(FileSystem.GetFullPathShim fileName, FileSystem.GetFullPathShim f2.FilePath, StringComparison.CurrentCultureIgnoreCase)=0 + String.Compare(fileName, f.Source.FilePath, StringComparison.CurrentCultureIgnoreCase)=0 + || String.Compare(FileSystem.GetFullPathShim fileName, FileSystem.GetFullPathShim f.Source.FilePath, StringComparison.CurrentCultureIgnoreCase)=0 result match fileNames |> ImmutableArray.tryFindIndex CompareFileNames with | Some slot -> Some slot @@ -1427,9 +1436,8 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc member builder.GetParseResultsForFile fileName = let slotOfFile = builder.GetSlotOfFileName fileName - let fileInfo = fileNames[slotOfFile] - // re-parse on demand instead of retaining - let syntaxTree = GetSyntaxTree initialState.tcConfig initialState.fileParsed initialState.lexResourceManager fileInfo + let file = initialState.fileNames[slotOfFile] + let syntaxTree = GetSyntaxTree initialState.tcConfig initialState.fileParsed initialState.lexResourceManager file initialState.useSyntaxTreeCache syntaxTree.Parse None member builder.NotifyFileChanged(fileName, timeStamp) = @@ -1441,7 +1449,7 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc setCurrentState newState cache ct } - member _.SourceFiles = fileNames |> Seq.map (fun (_, f, _) -> f.FilePath) |> List.ofSeq + member _.SourceFiles = fileNames |> Seq.map (fun f -> f.Source.FilePath) |> List.ofSeq /// CreateIncrementalBuilder (for background type checking). Note that fsc.fs also /// creates an incremental builder used by the command line compiler. @@ -1467,7 +1475,8 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc parallelReferenceResolution, captureIdentifiersWhenParsing, getSource, - useChangeNotifications + useChangeNotifications, + useSyntaxTreeCache ) = let useSimpleResolutionSwitch = "--simpleresolution" @@ -1678,16 +1687,16 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc let getFSharpSource fileName = getSource |> Option.map(fun getSource -> - let getTimeStamp() = DateTime.UtcNow + let timeStamp = DateTime.UtcNow + let getTimeStamp = fun () -> timeStamp let getSourceText() = getSource fileName FSharpSource.Create(fileName, getTimeStamp, getSourceText)) |> Option.defaultWith(fun () -> FSharpSource.CreateFromFile(fileName)) let sourceFiles = sourceFiles - |> List.map (fun (m, fileName, isLastCompiland) -> - (m, getFSharpSource(fileName), isLastCompiland) - ) + |> List.map (fun (m, fileName, isLastCompiland) -> + { Range = m; Source = getFSharpSource fileName; Flags = isLastCompiland } ) let initialState = IncrementalBuilderInitialState.Create( @@ -1707,7 +1716,9 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc #endif allDependencies, defaultTimeStamp, - useChangeNotifications) + useChangeNotifications, + useSyntaxTreeCache + ) let builder = IncrementalBuilder(initialState, IncrementalBuilderState.Create(initialState)) return Some builder diff --git a/src/Compiler/Service/IncrementalBuild.fsi b/src/Compiler/Service/IncrementalBuild.fsi index ee9b06380eb..a1c5fa70624 100644 --- a/src/Compiler/Service/IncrementalBuild.fsi +++ b/src/Compiler/Service/IncrementalBuild.fsi @@ -269,7 +269,8 @@ type internal IncrementalBuilder = parallelReferenceResolution: ParallelReferenceResolution * captureIdentifiersWhenParsing: bool * getSource: (string -> ISourceText option) option * - useChangeNotifications: bool -> + useChangeNotifications: bool * + useSyntaxTreeCache: bool -> NodeCode /// Generalized Incremental Builder. This is exposed only for unit testing purposes. diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs index 65537dd67b8..cf5487e25df 100644 --- a/src/Compiler/Service/service.fs +++ b/src/Compiler/Service/service.fs @@ -195,7 +195,8 @@ type BackgroundCompiler parallelReferenceResolution, captureIdentifiersWhenParsing, getSource: (string -> ISourceText option) option, - useChangeNotifications + useChangeNotifications, + useSyntaxTreeCache ) as self = let beforeFileChecked = Event() @@ -329,7 +330,8 @@ type BackgroundCompiler parallelReferenceResolution, captureIdentifiersWhenParsing, getSource, - useChangeNotifications + useChangeNotifications, + useSyntaxTreeCache ) match builderOpt with @@ -408,7 +410,7 @@ type BackgroundCompiler let createBuilderNode (options, userOpName, ct: CancellationToken) = lock gate (fun () -> if ct.IsCancellationRequested then - GraphNode(node.Return(None, [||])) + GraphNode.FromResult(None, [||]) else let getBuilderNode = GraphNode(CreateOneIncrementalBuilder(options, userOpName)) incrementalBuildersCache.Set(AnyCallerThread, options, getBuilderNode) @@ -636,9 +638,6 @@ type BackgroundCompiler ) = node { - if useChangeNotifications then - do! builder.NotifyFileChanged(fileName, DateTime.UtcNow) - match! bc.GetCachedCheckFileResult(builder, fileName, sourceText, options) with | Some (_, results) -> return FSharpCheckFileAnswer.Succeeded results | _ -> @@ -1263,7 +1262,8 @@ type FSharpChecker parallelReferenceResolution, captureIdentifiersWhenParsing, getSource, - useChangeNotifications + useChangeNotifications, + useSyntaxTreeCache ) = let backgroundCompiler = @@ -1280,7 +1280,8 @@ type FSharpChecker parallelReferenceResolution, captureIdentifiersWhenParsing, getSource, - useChangeNotifications + useChangeNotifications, + useSyntaxTreeCache ) static let globalInstance = lazy FSharpChecker.Create() @@ -1324,7 +1325,8 @@ type FSharpChecker ?enablePartialTypeChecking, ?parallelReferenceResolution: bool, ?captureIdentifiersWhenParsing: bool, - ?documentSource: DocumentSource + ?documentSource: DocumentSource, + ?useSyntaxTreeCache: bool ) = use _ = Activity.startNoTags "FSharpChecker.Create" @@ -1352,6 +1354,8 @@ type FSharpChecker | Some (DocumentSource.Custom _) -> true | _ -> false + let useSyntaxTreeCache = defaultArg useSyntaxTreeCache true + if keepAssemblyContents && enablePartialTypeChecking then invalidArg "enablePartialTypeChecking" "'keepAssemblyContents' and 'enablePartialTypeChecking' cannot be both enabled." @@ -1372,7 +1376,8 @@ type FSharpChecker (match documentSource with | Some (DocumentSource.Custom f) -> Some f | _ -> None), - useChangeNotifications + useChangeNotifications, + useSyntaxTreeCache ) member _.ReferenceResolver = legacyReferenceResolver diff --git a/src/Compiler/Service/service.fsi b/src/Compiler/Service/service.fsi index 52a355c9162..5d482b3cbed 100644 --- a/src/Compiler/Service/service.fsi +++ b/src/Compiler/Service/service.fsi @@ -41,6 +41,7 @@ type public FSharpChecker = /// Indicates whether to resolve references in parallel. /// When set to true we create a set of all identifiers for each parsed file which can be used to speed up finding references. /// Default: FileSystem. You can use Custom source to provide a function that will return the source for a given file path instead of reading it from the file system. Note that with this option the FSharpChecker will also not monitor the file system for file changes. It will expect to be notified of changes via the NotifyFileChanged method. + /// Default: true. Indicates whether to keep parsing results in a cache. static member Create: ?projectCacheSize: int * ?keepAssemblyContents: bool * @@ -53,7 +54,8 @@ type public FSharpChecker = ?enablePartialTypeChecking: bool * ?parallelReferenceResolution: bool * ?captureIdentifiersWhenParsing: bool * - [] ?documentSource: DocumentSource -> + [] ?documentSource: DocumentSource * + [] ?useSyntaxTreeCache: bool -> FSharpChecker /// @@ -383,7 +385,6 @@ type public FSharpChecker = member ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients: unit -> unit /// Notify the checker that given file has changed. This needs to be used when checker is created with documentSource = Custom. - /// Although it is not mandatory when the changed file is the next thing requested to be checked. [] member NotifyFileChanged: fileName: string * options: FSharpProjectOptions * ?userOpName: string -> Async diff --git a/src/Compiler/Utilities/Activity.fs b/src/Compiler/Utilities/Activity.fs index a5f8000cfa0..6305ce77e08 100644 --- a/src/Compiler/Utilities/Activity.fs +++ b/src/Compiler/Utilities/Activity.fs @@ -10,6 +10,8 @@ open System.Text [] module internal Activity = + let FscSourceName = "fsc" + module Tags = let fileName = "fileName" let project = "project" @@ -40,7 +42,10 @@ module internal Activity = outputDllFile |] - let private activitySourceName = "fsc" + module Events = + let cacheHit = "cacheHit" + + let private activitySourceName = FscSourceName let private profiledSourceName = "fsc_with_env_stats" type System.Diagnostics.Activity with @@ -75,6 +80,10 @@ module internal Activity = let startNoTags (name: string) : IDisposable = activitySource.StartActivity(name) + let addEvent name = + if Activity.Current <> null && Activity.Current.Source = activitySource then + Activity.Current.AddEvent(ActivityEvent(name)) |> ignore + module Profiling = module Tags = diff --git a/src/Compiler/Utilities/Activity.fsi b/src/Compiler/Utilities/Activity.fsi index 0f9647a4ecc..96d3844ea4f 100644 --- a/src/Compiler/Utilities/Activity.fsi +++ b/src/Compiler/Utilities/Activity.fsi @@ -9,6 +9,8 @@ open System [] module internal Activity = + val FscSourceName: string + module Tags = val fileName: string val qualifiedNameOfFile: string @@ -17,10 +19,15 @@ module internal Activity = val length: string val cache: string + module Events = + val cacheHit: string + val startNoTags: name: string -> IDisposable val start: name: string -> tags: (string * string) seq -> IDisposable + val addEvent: name: string -> unit + module Profiling = val startAndMeasureEnvironmentStats: name: string -> IDisposable val addConsoleListener: unit -> IDisposable diff --git a/src/FSharp.Core/array.fs b/src/FSharp.Core/array.fs index 8c2fa8470fa..2e8926ec6c6 100644 --- a/src/FSharp.Core/array.fs +++ b/src/FSharp.Core/array.fs @@ -1934,6 +1934,46 @@ module Array = module Parallel = open System.Threading.Tasks + [] + let tryFindIndex predicate (array: _[]) = + checkNonNull "array" array + + let pResult = + Parallel.For( + 0, + array.Length, + (fun i pState -> + if predicate array[i] then + pState.Break()) + ) + + pResult.LowestBreakIteration |> Option.ofNullable |> Option.map int + + [] + let tryFind predicate (array: _[]) = + array |> tryFindIndex predicate |> Option.map (fun i -> array[i]) + + [] + let tryPick chooser (array: _[]) = + checkNonNull "array" array + let allChosen = new System.Collections.Concurrent.ConcurrentDictionary<_, _>() + + let pResult = + Parallel.For( + 0, + array.Length, + (fun i pState -> + match chooser array[i] with + | None -> () + | chosenElement -> + allChosen[i] <- chosenElement + pState.Break()) + ) + + pResult.LowestBreakIteration + |> Option.ofNullable + |> Option.bind (fun i -> allChosen[int i]) + [] let choose chooser (array: 'T[]) = checkNonNull "array" array diff --git a/src/FSharp.Core/array.fsi b/src/FSharp.Core/array.fsi index 2d08d1116e1..d05ecacc0b3 100644 --- a/src/FSharp.Core/array.fsi +++ b/src/FSharp.Core/array.fsi @@ -3094,6 +3094,102 @@ module Array = /// Provides parallel operations on arrays module Parallel = + /// Returns the first element for which the given function returns True. + /// Returns None if no such element exists. + /// + /// The function to test the input elements. + /// The input array. + /// + /// The first element that satisfies the predicate, or None. + /// + /// Thrown when the input array is null. + /// + /// Try to find the first even number: + /// + /// let inputs = [| 1; 2; 3 |] + /// + /// inputs |> Array.Parallel.tryFind (fun elm -> elm % 2 = 0) + /// + /// Evaluates to Some 2. + /// + /// + /// Try to find the first even number: + /// + /// let inputs = [| 1; 5; 3 |] + /// + /// inputs |> Array.Parallel.tryFind (fun elm -> elm % 2 = 0) + /// + /// Evaluates to None + /// + [] + [] + val tryFind: predicate:('T -> bool) -> array:'T[] -> 'T option + + + /// Returns the index of the first element in the array + /// that satisfies the given predicate. + /// Returns None if no such element exists. + /// The function to test the input elements. + /// The input array. + /// + /// Thrown when the input array is null. + /// + /// The index of the first element that satisfies the predicate, or None. + /// + /// Try to find the index of the first even number: + /// + /// let inputs = [| 1; 2; 3; 4; 5 |] + /// + /// inputs |> Array.Parallel.tryFindIndex (fun elm -> elm % 2 = 0) + /// + /// Evaluates to Some 1 + /// + /// + /// Try to find the index of the first even number: + /// + /// let inputs = [| 1; 3; 5; 7 |] + /// + /// inputs |> Array.Parallel.tryFindIndex (fun elm -> elm % 2 = 0) + /// + /// Evaluates to None + /// + [] + [] + val tryFindIndex : predicate:('T -> bool) -> array:'T[] -> int option + + /// Applies the given function to successive elements, returning the first + /// result where the function returns Some(x) for some x. If the function + /// never returns Some(x) then None is returned. + /// + /// The function to transform the array elements into options. + /// The input array. + /// + /// The first transformed element that is Some(x). + /// + /// Thrown when the input array is null. + /// + /// + /// + /// let input = [| 1; 2; 3 |] + /// + /// input |> Array.Parallel.tryPick (fun n -> if n % 2 = 0 then Some (string n) else None) + /// + /// Evaluates to Some 2. + /// + /// + /// + /// + /// let input = [| 1; 2; 3 |] + /// + /// input |> Array.Parallel.tryPick (fun n -> if n > 3 = 0 then Some (string n) else None) + /// + /// Evaluates to None. + /// + /// + [] + [] + val tryPick: chooser:('T -> 'U option) -> array:'T[] -> 'U option + /// Apply the given function to each element of the array. Return /// the array comprised of the results x for each element where /// the function returns Some(x). diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/CommonWorkflows.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/CommonWorkflows.fs index 6b5775f23e7..ce7820ddf4e 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/CommonWorkflows.fs +++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/CommonWorkflows.fs @@ -2,6 +2,7 @@ open System open System.IO +open System.Diagnostics open Xunit @@ -10,6 +11,22 @@ open FSharp.Test.ProjectGeneration.Internal open FSharp.Compiler.Text open FSharp.Compiler.CodeAnalysis +module FcsDiagnostics = FSharp.Compiler.Diagnostics.Activity + +let expectCacheHits n = + let events = ResizeArray() + let listener = + new ActivityListener( + ShouldListenTo = (fun s -> s.Name = FcsDiagnostics.FscSourceName), + Sample = (fun _ -> ActivitySamplingResult.AllData), + ActivityStopped = (fun a -> events.AddRange a.Events) + ) + ActivitySource.AddActivityListener listener + { new IDisposable with + member this.Dispose() = + listener.Dispose() + Assert.Equal(n, events |> Seq.filter (fun e -> e.Name = FcsDiagnostics.Events.cacheHit) |> Seq.length) } + let makeTestProject () = SyntheticProject.Create( sourceFile "First" [], @@ -132,3 +149,62 @@ let ``Using getSource and notifications instead of filesystem`` () = checkFile middle expectSignatureChanged checkFile last expectSignatureChanged } + +[] +let ``Using getSource and notifications instead of filesystem with parse caching`` () = + + let size = 20 + + let project = + { SyntheticProject.Create() with + SourceFiles = [ + sourceFile $"File%03d{0}" [] + for i in 1..size do + sourceFile $"File%03d{i}" [$"File%03d{i-1}"] + ] + } + + let first = "File001" + let middle = $"File%03d{size / 2}" + let last = $"File%03d{size}" + + use _ = expectCacheHits 28 + ProjectWorkflowBuilder(project, useGetSource = true, useChangeNotifications = true, useSyntaxTreeCache = true) { + updateFile first updatePublicSurface + checkFile first expectSignatureChanged + checkFile last expectSignatureChanged + updateFile middle updatePublicSurface + checkFile last expectSignatureChanged + addFileAbove middle (sourceFile "addedFile" [first]) + updateFile middle (addDependency "addedFile") + checkFile middle expectSignatureChanged + checkFile last expectSignatureChanged + } + +[] +let ``Edit file, check it, then check dependent file with parse caching`` () = + use _ = expectCacheHits 1 + ProjectWorkflowBuilder(makeTestProject(), useSyntaxTreeCache = true) { + updateFile "First" breakDependentFiles + checkFile "First" expectSignatureChanged + saveFile "First" + checkFile "Second" expectErrors + } + +[] +let ``Edit file, don't check it, check dependent file with parse caching `` () = + use _ = expectCacheHits 1 + ProjectWorkflowBuilder(makeTestProject(), useSyntaxTreeCache = true) { + updateFile "First" breakDependentFiles + saveFile "First" + checkFile "Second" expectErrors + } + +[] +let ``Parse cache not used when not enabled`` () = + use _ = expectCacheHits 0 + ProjectWorkflowBuilder(makeTestProject(), useSyntaxTreeCache = false) { + updateFile "First" breakDependentFiles + saveFile "First" + checkFile "Second" expectErrors + } \ No newline at end of file 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 615dddacdf9..98973518922 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 @@ -2031,7 +2031,7 @@ FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: FSharp.Compiler.Symbols. FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String ToString() FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String[] DependencyFiles FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String[] get_DependencyFiles() -FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Create(Microsoft.FSharp.Core.FSharpOption`1[System.Int32], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[System.String,System.DateTime],Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[System.Object,System.IntPtr,System.Int32]]]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.DocumentSource]) +FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Create(Microsoft.FSharp.Core.FSharpOption`1[System.Int32], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[System.String,System.DateTime],Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[System.Object,System.IntPtr,System.Int32]]]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.DocumentSource], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean]) FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Instance FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker get_Instance() FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions GetProjectOptionsFromCommandLineArgs(System.String, System.String[], Microsoft.FSharp.Core.FSharpOption`1[System.DateTime], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean]) 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 615dddacdf9..98973518922 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 @@ -2031,7 +2031,7 @@ FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: FSharp.Compiler.Symbols. FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String ToString() FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String[] DependencyFiles FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String[] get_DependencyFiles() -FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Create(Microsoft.FSharp.Core.FSharpOption`1[System.Int32], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[System.String,System.DateTime],Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[System.Object,System.IntPtr,System.Int32]]]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.DocumentSource]) +FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Create(Microsoft.FSharp.Core.FSharpOption`1[System.Int32], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[System.String,System.DateTime],Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[System.Object,System.IntPtr,System.Int32]]]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.DocumentSource], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean]) FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Instance FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker get_Instance() FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions GetProjectOptionsFromCommandLineArgs(System.String, System.String[], Microsoft.FSharp.Core.FSharpOption`1[System.DateTime], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean]) diff --git a/tests/FSharp.Compiler.UnitTests/BuildGraphTests.fs b/tests/FSharp.Compiler.UnitTests/BuildGraphTests.fs index ae2aeff2071..a33f9020897 100644 --- a/tests/FSharp.Compiler.UnitTests/BuildGraphTests.fs +++ b/tests/FSharp.Compiler.UnitTests/BuildGraphTests.fs @@ -272,3 +272,10 @@ module BuildGraphTests = tasks |> Seq.iter (fun x -> try x.Wait(1000) |> ignore with | :? TimeoutException -> reraise() | _ -> ()) + + [] + let ``GraphNode created from an already computed result will return it in tryPeekValue`` () = + let graphNode = GraphNode.FromResult 1 + + Assert.shouldBeTrue graphNode.HasValue + Assert.shouldBe (ValueSome 1) (graphNode.TryPeekValue()) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl index 348c413de1b..783f3bc30aa 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl @@ -40,6 +40,9 @@ Microsoft.FSharp.Collections.Array4DModule: T[,,,] Create[T](Int32, Int32, Int32 Microsoft.FSharp.Collections.Array4DModule: T[,,,] Initialize[T](Int32, Int32, Int32, Int32, Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,T]]]]) Microsoft.FSharp.Collections.Array4DModule: T[,,,] ZeroCreate[T](Int32, Int32, Int32, Int32) Microsoft.FSharp.Collections.Array4DModule: Void Set[T](T[,,,], Int32, Int32, Int32, Int32, T) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[System.Int32] TryFindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[TResult] TryPick[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[T] TryFind[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[T[],T[]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Choose[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Collect[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult[]], T[]) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl index 2d5ddb40c7a..bca7a6bb25a 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl @@ -40,6 +40,9 @@ Microsoft.FSharp.Collections.Array4DModule: T[,,,] Create[T](Int32, Int32, Int32 Microsoft.FSharp.Collections.Array4DModule: T[,,,] Initialize[T](Int32, Int32, Int32, Int32, Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,T]]]]) Microsoft.FSharp.Collections.Array4DModule: T[,,,] ZeroCreate[T](Int32, Int32, Int32, Int32) Microsoft.FSharp.Collections.Array4DModule: Void Set[T](T[,,,], Int32, Int32, Int32, Int32, T) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[System.Int32] TryFindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[TResult] TryPick[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[T] TryFind[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[T[],T[]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Choose[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Collect[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult[]], T[]) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl index 45805d53ae0..614ec47f2d7 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl @@ -40,6 +40,9 @@ Microsoft.FSharp.Collections.Array4DModule: T[,,,] Create[T](Int32, Int32, Int32 Microsoft.FSharp.Collections.Array4DModule: T[,,,] Initialize[T](Int32, Int32, Int32, Int32, Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,T]]]]) Microsoft.FSharp.Collections.Array4DModule: T[,,,] ZeroCreate[T](Int32, Int32, Int32, Int32) Microsoft.FSharp.Collections.Array4DModule: Void Set[T](T[,,,], Int32, Int32, Int32, Int32, T) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[System.Int32] TryFindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[TResult] TryPick[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[T] TryFind[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[T[],T[]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Choose[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Collect[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult[]], T[]) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl index 275087e02e0..702f3302cee 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl @@ -40,6 +40,9 @@ Microsoft.FSharp.Collections.Array4DModule: T[,,,] Create[T](Int32, Int32, Int32 Microsoft.FSharp.Collections.Array4DModule: T[,,,] Initialize[T](Int32, Int32, Int32, Int32, Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,T]]]]) Microsoft.FSharp.Collections.Array4DModule: T[,,,] ZeroCreate[T](Int32, Int32, Int32, Int32) Microsoft.FSharp.Collections.Array4DModule: Void Set[T](T[,,,], Int32, Int32, Int32, Int32, T) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[System.Int32] TryFindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[TResult] TryPick[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[T] TryFind[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[T[],T[]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Choose[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Collect[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult[]], T[]) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule.fs index 3d9185468d9..2c68635b3b9 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule.fs @@ -955,17 +955,16 @@ type ArrayModule() = let intArr = [| 1..10 |] let seq = Array.toSeq intArr let sum = Seq.sum seq - Assert.AreEqual(55, sum) - - [] - member this.TryPick() = + Assert.AreEqual(55, sum) + + member private _.TryPickTester tryPickInt tryPickString = // integer array let intArr = [| 1..10 |] let funcInt x = match x with | _ when x % 3 = 0 -> Some (x.ToString()) | _ -> None - let resultInt = Array.tryPick funcInt intArr + let resultInt = tryPickInt funcInt intArr if resultInt <> Some "3" then Assert.Fail() // string array @@ -974,20 +973,26 @@ type ArrayModule() = match x with | "good" -> Some (x.ToString()) | _ -> None - let resultStr = Array.tryPick funcStr strArr + let resultStr = tryPickString funcStr strArr if resultStr <> None then Assert.Fail() // empty array let emptyArr:int[] = [| |] - let resultEpt = Array.tryPick funcInt emptyArr + let resultEpt = tryPickInt funcInt emptyArr if resultEpt <> None then Assert.Fail() // null array let nullArr = null:string[] - CheckThrowsArgumentNullException (fun () -> Array.tryPick funcStr nullArr |> ignore) + CheckThrowsArgumentNullException (fun () -> tryPickString funcStr nullArr |> ignore) () + [] + member this.TryPick() = this.TryPickTester Array.tryPick Array.tryPick + + [] + member this.ParallelTryPick() = this.TryPickTester Array.Parallel.tryPick Array.Parallel.tryPick + [] member this.Fold() = // integer array diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs index 23510ddb781..b10ce17fb2e 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs @@ -972,25 +972,31 @@ type ArrayModule2() = () - [] - member this.TryFind() = + member private _.TryFindTester tryFindInts tryFindStrings = // integer array - let resultInt = [|1..10|] |> Array.tryFind (fun x -> x%7 = 0) + let resultInt = [|1..10|] |> tryFindInts (fun x -> x%7 = 0) if resultInt <> Some 7 then Assert.Fail() // string array - let resultStr = [|"Lists"; "are"; "commonly" ; "list" |] |> Array.tryFind (fun (x:string) -> x.Length > 4) + let resultStr = [|"Lists"; "are"; "commonly" ; "list" |] |> tryFindStrings (fun (x:string) -> x.Length > 4) if resultStr <> Some "Lists" then Assert.Fail() // empty array - let resultEpt =[||] |> Array.tryFind (fun x -> x%7 = 0) + let resultEpt =[||] |> tryFindInts (fun x -> x%7 = 0) if resultEpt <> None then Assert.Fail() // null array let nullArr = null:string[] - CheckThrowsArgumentNullException (fun () -> Array.tryFind (fun (x:string) -> x.Length > 4) nullArr |> ignore) + CheckThrowsArgumentNullException (fun () -> tryFindStrings (fun (x:string) -> x.Length > 4) nullArr |> ignore) () + + [] + member this.TryFind() = this.TryFindTester Array.tryFind Array.tryFind + + [] + member this.ParallelTryFind() = this.TryFindTester Array.Parallel.tryFind Array.Parallel.tryFind + [] member this.TryFindBack() = @@ -1016,26 +1022,30 @@ type ArrayModule2() = () - [] - member this.TryFindIndex() = + member private _.TryFindIndexTester tryFindIdxInt tryFindIdxString = // integer array - let resultInt = [|1..10|] |> Array.tryFindIndex (fun x -> x%7 = 0) + let resultInt = [|1..10|] |> tryFindIdxInt (fun x -> x%7 = 0) if resultInt <> Some 6 then Assert.Fail() // string array - let resultStr = [|"Lists"; "are"; "commonly" ; "list" |] |> Array.tryFindIndex (fun (x:string) -> x.Length > 4) + let resultStr = [|"Lists"; "are"; "commonly" ; "list" |] |> tryFindIdxString (fun (x:string) -> x.Length > 4) if resultStr <> Some 0 then Assert.Fail() // empty array - let resultEpt =[||] |> Array.tryFindIndex (fun x -> x % 7 = 0) + let resultEpt =[||] |> tryFindIdxInt (fun x -> x % 7 = 0) if resultEpt <> None then Assert.Fail() // null array let nullArr = null:string[] - CheckThrowsArgumentNullException (fun () -> Array.tryFindIndex (fun (x:string) -> x.Length > 4) nullArr |> ignore) + CheckThrowsArgumentNullException (fun () -> tryFindIdxString (fun (x:string) -> x.Length > 4) nullArr |> ignore) () + [] + member this.TryFindIndex() = this.TryFindIndexTester Array.tryFindIndex Array.tryFindIndex + + [] + member this.ParallelTryFindIndex() = this.TryFindIndexTester Array.Parallel.tryFindIndex Array.Parallel.tryFindIndex [] member this.TryFindIndexBack() = // integer array diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/CollectionModulesConsistency.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/CollectionModulesConsistency.fs index 1560c16b564..0494f9682d4 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/CollectionModulesConsistency.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/CollectionModulesConsistency.fs @@ -14,6 +14,9 @@ let consistency name sqs ls arr = (sqs = arr) |@ (sprintf "Seq.%s = '%A', Array.%s = '%A'" name sqs name arr) .&. (ls = arr) |@ (sprintf "List.%s = '%A', Array.%s = '%A'" name ls name arr) +let consistencyIncludingParallel name sqs ls arr paraArr = + consistency name sqs ls arr .&. + (paraArr = arr) |@ (sprintf "Parallel.%s = '%A', Array.%s = '%A'" name paraArr name arr) let allPairs<'a when 'a : equality> (xs : list<'a>) (xs2 : list<'a>) = let s = xs |> Seq.allPairs xs2 |> Seq.toArray @@ -1104,7 +1107,8 @@ let tryFind<'a when 'a : equality> (xs : 'a []) predicate = let s = xs |> Seq.tryFind predicate let l = xs |> List.ofArray |> List.tryFind predicate let a = xs |> Array.tryFind predicate - consistency "tryFind" s l a + let pa = xs |> Array.Parallel.tryFind predicate + consistencyIncludingParallel "tryFind" s l a pa [] let ``tryFind is consistent`` () = @@ -1128,7 +1132,8 @@ let tryFindIndex<'a when 'a : equality> (xs : 'a []) predicate = let s = xs |> Seq.tryFindIndex predicate let l = xs |> List.ofArray |> List.tryFindIndex predicate let a = xs |> Array.tryFindIndex predicate - consistency "tryFindIndex" s l a + let pa = xs |> Array.Parallel.tryFindIndex predicate + consistencyIncludingParallel "tryFindIndex" s l a pa [] let ``tryFindIndex is consistent`` () = @@ -1188,7 +1193,8 @@ let tryPick<'a when 'a : comparison> (xs : 'a []) f = let s = xs |> Seq.tryPick f let l = xs |> List.ofArray |> List.tryPick f let a = xs |> Array.tryPick f - consistency "tryPick" s l a + let pa = xs |> Array.Parallel.tryPick f + consistencyIncludingParallel "tryPick" s l a pa [] let ``tryPick is consistent`` () = diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs index cf5fae95066..7d789d00f4a 100644 --- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs +++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs @@ -502,7 +502,8 @@ type ProjectWorkflowBuilder ?initialContext, ?checker: FSharpChecker, ?useGetSource, - ?useChangeNotifications + ?useChangeNotifications, + ?useSyntaxTreeCache ) = let useGetSource = defaultArg useGetSource false @@ -533,7 +534,8 @@ type ProjectWorkflowBuilder enableBackgroundItemKeyStoreAndSemanticClassification = true, enablePartialTypeChecking = true, captureIdentifiersWhenParsing = true, - documentSource = (if useGetSource then DocumentSource.Custom getSource else DocumentSource.FileSystem) + documentSource = (if useGetSource then DocumentSource.Custom getSource else DocumentSource.FileSystem), + useSyntaxTreeCache = defaultArg useSyntaxTreeCache false )) let mapProjectAsync f workflow = diff --git a/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs b/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs index f2cb16164a9..2df8f930b9e 100644 --- a/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs +++ b/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs @@ -139,7 +139,7 @@ module internal RoslynHelpers = | :? OperationCanceledException -> tcs.TrySetCanceled(cancellationToken) |> ignore | exn -> - System.Diagnostics.Trace.WriteLine("Visual F# Tools: exception swallowed and not passed to Roslyn: {0}", exn.Message) + System.Diagnostics.Trace.TraceError("Visual F# Tools: exception swallowed and not passed to Roslyn: {0}", exn) let res = Unchecked.defaultof<_> tcs.TrySetResult(res) |> ignore ), diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 4e83825b9b8..70a2a009e54 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -28,6 +28,7 @@ + diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx index af946778b69..da310df50bf 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx @@ -207,7 +207,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) Advanced diff --git a/vsintegration/src/FSharp.Editor/Hints/Hints.fs b/vsintegration/src/FSharp.Editor/Hints/Hints.fs index 9e6bab5c297..99bc26409e2 100644 --- a/vsintegration/src/FSharp.Editor/Hints/Hints.fs +++ b/vsintegration/src/FSharp.Editor/Hints/Hints.fs @@ -15,4 +15,9 @@ module Hints = Kind: HintKind Range: range Parts: TaggedText list - } \ No newline at end of file + } + + let serialize kind = + match kind with + | TypeHint -> "type" + | ParameterNameHint -> "parameterName" \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/Hints/RoslynAdapter.fs b/vsintegration/src/FSharp.Editor/Hints/RoslynAdapter.fs index f79e1dba1fa..668cd3cb2fd 100644 --- a/vsintegration/src/FSharp.Editor/Hints/RoslynAdapter.fs +++ b/vsintegration/src/FSharp.Editor/Hints/RoslynAdapter.fs @@ -6,6 +6,7 @@ open System.Collections.Immutable open System.ComponentModel.Composition open Microsoft.CodeAnalysis.ExternalAccess.FSharp.InlineHints open Microsoft.VisualStudio.FSharp.Editor +open Microsoft.VisualStudio.FSharp.Editor.Telemetry // So the Roslyn interface is called IFSharpInlineHintsService // but our implementation is called just HintsService. @@ -27,6 +28,9 @@ type internal RoslynAdapter if hintKinds.IsEmpty then return ImmutableArray.Empty else + let hintKindsSerialized = hintKinds |> Set.map Hints.serialize |> String.concat "," + TelemetryReporter.reportEvent "hints" [("hints.kinds", hintKindsSerialized)] + let! sourceText = document.GetTextAsync cancellationToken |> Async.AwaitTask let! nativeHints = HintService.getHintsForDocument diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index 821a0ab8aad..74809b4acf4 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -27,6 +27,7 @@ open Microsoft.CodeAnalysis.ExternalAccess.FSharp open Microsoft.CodeAnalysis.Host open Microsoft.CodeAnalysis.Host.Mef open Microsoft.VisualStudio.FSharp.Editor.WorkspaceExtensions +open Microsoft.VisualStudio.FSharp.Editor.Telemetry open System.Threading.Tasks #nowarn "9" // NativePtr.toNativeInt @@ -104,6 +105,8 @@ type internal FSharpWorkspaceServiceFactory | _ -> let checker = lazy + TelemetryReporter.reportEvent "languageservicestarted" [] + let editorOptions = let editorOptions = workspace.Services.GetService() @@ -122,6 +125,9 @@ type internal FSharpWorkspaceServiceFactory let enableLiveBuffers = getOption (fun options -> options.Advanced.IsLiveBuffersEnabled) false + let useSyntaxTreeCache = + getOption (fun options -> options.LanguageServicePerformance.UseSyntaxTreeCache) LanguageServicePerformanceOptions.Default.UseSyntaxTreeCache + let checker = FSharpChecker.Create( projectCacheSize = 5000, // We do not care how big the cache is. VS will actually tell FCS to clear caches, so this is fine. @@ -133,7 +139,8 @@ type internal FSharpWorkspaceServiceFactory enablePartialTypeChecking = true, parallelReferenceResolution = enableParallelReferenceResolution, captureIdentifiersWhenParsing = true, - documentSource = (if enableLiveBuffers then DocumentSource.Custom getSource else DocumentSource.FileSystem)) + documentSource = (if enableLiveBuffers then DocumentSource.Custom getSource else DocumentSource.FileSystem), + useSyntaxTreeCache = useSyntaxTreeCache) if enableLiveBuffers then workspace.WorkspaceChanged.Add(fun args -> diff --git a/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs b/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs index 78f751999eb..6edfcc6cc1d 100644 --- a/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs +++ b/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs @@ -64,13 +64,15 @@ type LanguageServicePerformanceOptions = AllowStaleCompletionResults: bool TimeUntilStaleCompletion: int EnableParallelReferenceResolution: bool - EnableFastFindReferences: bool } + EnableFastFindReferences: bool + UseSyntaxTreeCache: bool } static member Default = { EnableInMemoryCrossProjectReferences = true AllowStaleCompletionResults = true TimeUntilStaleCompletion = 2000 // In ms, so this is 2 seconds EnableParallelReferenceResolution = false - EnableFastFindReferences = FSharpExperimentalFeaturesEnabledAutomatically } + EnableFastFindReferences = FSharpExperimentalFeaturesEnabledAutomatically + UseSyntaxTreeCache = FSharpExperimentalFeaturesEnabledAutomatically } [] type AdvancedOptions = diff --git a/vsintegration/src/FSharp.Editor/Telemetry/TelemetryReporter.fs b/vsintegration/src/FSharp.Editor/Telemetry/TelemetryReporter.fs new file mode 100644 index 00000000000..f4f91d7f7d0 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/Telemetry/TelemetryReporter.fs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace Microsoft.VisualStudio.FSharp.Editor.Telemetry + +open Microsoft.VisualStudio.Telemetry + +module TelemetryReporter = + + let eventPrefix = "dotnet/fsharp/" + let propPrefix = "dotnet.fsharp." + + let getFullEventName name = eventPrefix + name + let getFullPropName name = propPrefix + name + + let createEvent name (props: (string * obj) list) = + let event = TelemetryEvent (getFullEventName name) + + props + |> List.map (fun (k, v) -> getFullPropName k, v) + |> List.iter event.Properties.Add + + event + + let reportEvent name props = + let session = TelemetryService.DefaultSession + let event = createEvent name props + session.PostEvent event + diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf index 70ff3891f24..8fd5631ac14 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf @@ -159,16 +159,16 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) - Možnosti výkonu projektu F# a ukládání do mezipaměti; -Povolit odkazy mezi projekty v paměti; -Možnosti výkonu IntelliSense; -Povolit zastaralá data pro funkce IntelliSense; -Doba, než se použijí zastaralé výsledky (v milisekundách); -Paralelizace (vyžaduje restartování); -Povolit paralelní kontrolu typů pomocí souborů podpisu; -Povolit paralelní referenční rozlišení; -Povolit odkazy rychlého hledání a přejmenování (experimentální) +Enable fast find references & rename (experimental);Cache parsing results (experimental) + F# Project and Caching Performance Options; +Enable in-memory cross project references; +IntelliSense Performance Options; +Enable stale data for IntelliSense features; +Time until stale results are used (in milliseconds); +Parallelization (requires restart); +Enable parallel type checking with signature files; +Enable parallel reference resolution; +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf index 03a32dee7a7..10b3ee85df3 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf @@ -159,16 +159,16 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) - F#-Projekt- und Cacheleistungsoptionen; -Projektübergreifende Verweise im Arbeitsspeicher aktivieren; -IntelliSense-Leistungsoptionen; -Veraltete Daten für IntelliSense-Features aktivieren; -Zeit bis zur Verwendung veralteter Ergebnisse (in Millisekunden); -Parallelisierung (Neustart erforderlich); -Parallele Typüberprüfung mit Signaturdateien aktivieren; -Parallele Verweisauflösung aktivieren; -Schnellsuche und Umbenennen von Verweisen aktivieren (experimentell) +Enable fast find references & rename (experimental);Cache parsing results (experimental) + F# Project and Caching Performance Options; +Enable in-memory cross project references; +IntelliSense Performance Options; +Enable stale data for IntelliSense features; +Time until stale results are used (in milliseconds); +Parallelization (requires restart); +Enable parallel type checking with signature files; +Enable parallel reference resolution; +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf index 87c8686c488..bb9f6b04089 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf @@ -159,16 +159,16 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) - Opciones de rendimiento de almacenamiento en caché y proyecto de F#; -Habilitar referencias entre proyectos en memoria; -Opciones de rendimiento de IntelliSense; -Habilitar datos obsoletos para características de IntelliSense; -Tiempo hasta que se usan resultados obsoletos (en milisegundos); -Paralelización (requiere reiniciar); -Habilitar la comprobación de tipos paralelos con archivos de firma; -Habilitar resolución de referencias paralelas; -Habilitar referencias de búsqueda rápida y cambio de nombre (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) + F# Project and Caching Performance Options; +Enable in-memory cross project references; +IntelliSense Performance Options; +Enable stale data for IntelliSense features; +Time until stale results are used (in milliseconds); +Parallelization (requires restart); +Enable parallel type checking with signature files; +Enable parallel reference resolution; +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf index 947bd5c0247..8ba85c388ee 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf @@ -159,16 +159,16 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) - Options de performances du projet F# et de la mise en cache ; -Activer les références entre projets en mémoire ; -Options de performances IntelliSense ; -Activer les données périmées pour les fonctionnalités IntelliSense ; -Durée d’utilisation des résultats périmés (en millisecondes) ; -Parallélisation (redémarrage nécessaire); -Activer la vérification de type parallèle avec les fichiers de signature ; -Activer la résolution de référence parallèle ; -Activer les références de recherche rapide et renommer (expérimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) + F# Project and Caching Performance Options; +Enable in-memory cross project references; +IntelliSense Performance Options; +Enable stale data for IntelliSense features; +Time until stale results are used (in milliseconds); +Parallelization (requires restart); +Enable parallel type checking with signature files; +Enable parallel reference resolution; +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf index a4eb0425b53..b12f55aa89b 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf @@ -159,16 +159,16 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) - Opzioni prestazioni progetto F# e memorizzazione nella cache; -Abilita riferimenti tra progetti in memoria; -Opzioni prestazioni IntelliSense; -Abilita dati non aggiornati per le funzionalità di IntelliSense; -Tempo prima dell'utilizzo dei risultati non aggiornati (in millisecondi); -Parallelizzazione (richiede il riavvio); -Abilita il controllo dei tipi paralleli con i file di firma; -Abilita risoluzione riferimenti paralleli; -Abilita la ricerca rapida dei riferimenti e la ridenominazione (sperimentale) +Enable fast find references & rename (experimental);Cache parsing results (experimental) + F# Project and Caching Performance Options; +Enable in-memory cross project references; +IntelliSense Performance Options; +Enable stale data for IntelliSense features; +Time until stale results are used (in milliseconds); +Parallelization (requires restart); +Enable parallel type checking with signature files; +Enable parallel reference resolution; +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf index 0153598d37a..9dc9cf0d675 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf @@ -159,16 +159,16 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) - F# プロジェクトとキャッシュのパフォーマンス オプション; -メモリ内のプロジェクト間参照を有効にする。 -IntelliSense パフォーマンス オプション; -IntelliSense 機能の古いデータを有効にする。 -古い結果が使用されるまでの時間 (ミリ秒); -並列化 (再起動が必要); -署名ファイルを使用して並列型チェックを有効にする。 -並列参照解決を有効にする; -高速検索参照の有効化と名前の変更 (試験段階) +Enable fast find references & rename (experimental);Cache parsing results (experimental) + F# Project and Caching Performance Options; +Enable in-memory cross project references; +IntelliSense Performance Options; +Enable stale data for IntelliSense features; +Time until stale results are used (in milliseconds); +Parallelization (requires restart); +Enable parallel type checking with signature files; +Enable parallel reference resolution; +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf index b55f057c183..f85c697ca78 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf @@ -159,16 +159,16 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) - F# 프로젝트 및 캐싱 성능 옵션, -메모리 내 프로젝트 간 참조 사용, -IntelliSense 성능 옵션; -IntelliSense 기능에 부실 데이터 사용 -부실 결과가 사용될 때까지의 시간(밀리초) -병렬 처리(다시 시작해야 함) -서명 파일을 사용한 병렬 형식 검사 사용 -병렬 참조 확인 사용 -빠른 찾기 참조 및 이름 바꾸기 사용(실험적) +Enable fast find references & rename (experimental);Cache parsing results (experimental) + F# Project and Caching Performance Options; +Enable in-memory cross project references; +IntelliSense Performance Options; +Enable stale data for IntelliSense features; +Time until stale results are used (in milliseconds); +Parallelization (requires restart); +Enable parallel type checking with signature files; +Enable parallel reference resolution; +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf index fbfceff5310..36c84a6e350 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf @@ -159,16 +159,16 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) - Opcje wydajności projektów i buforowania języka F#; -Włącz odwołania między projektami w pamięci; -Opcje wydajności funkcji IntelliSense; -Włącz nieaktualne dane dla funkcji IntelliSense; -Czas do użycia nieodświeżonych wyników (w milisekundach); -Równoległość (wymaga ponownego uruchomienia); -Włącz równoległe sprawdzanie typów za pomocą plików podpisu; -Włącz równoległe rozpoznawanie odwołań; -Włącz szybkie znajdowanie odwołań i zmianę nazwy (eksperymentalne) +Enable fast find references & rename (experimental);Cache parsing results (experimental) + F# Project and Caching Performance Options; +Enable in-memory cross project references; +IntelliSense Performance Options; +Enable stale data for IntelliSense features; +Time until stale results are used (in milliseconds); +Parallelization (requires restart); +Enable parallel type checking with signature files; +Enable parallel reference resolution; +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf index eac4d64abef..d9ca4243be4 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf @@ -159,16 +159,16 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) - Opções de Desempenho de Projeto e Cache do F#; -Habilitar referências entre projetos na memória; -Opções de Desempenho do IntelliSense; -Habilitar dados obsoletos para recursos do IntelliSense; -Tempo até que os resultados obsoletos sejam usados (em milissegundos); -Paralelização (requer reinicialização); -Habilitar a verificação de tipo paralelo com arquivos de assinatura; -Habilitar a resolução de referência paralela; -Habilitar localizar referências rapidamente e renomear (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) + F# Project and Caching Performance Options; +Enable in-memory cross project references; +IntelliSense Performance Options; +Enable stale data for IntelliSense features; +Time until stale results are used (in milliseconds); +Parallelization (requires restart); +Enable parallel type checking with signature files; +Enable parallel reference resolution; +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf index 96500e113a7..d4e1670c5cf 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf @@ -159,16 +159,16 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) - Проект F# и параметры производительности кэширования; -Включить перекрестные ссылки между проектами в памяти; -Параметры производительности IntelliSense; -Включение устаревших данных для функций IntelliSense; -Время использования устаревших результатов (в миллисекундах); -Параллелизация (требуется перезапуск); -Включить параллельную проверку типа с файлами подписей; -Включить параллельное разрешение ссылок; -Включить быстрый поиск ссылок и переименование (экспериментальная версия) +Enable fast find references & rename (experimental);Cache parsing results (experimental) + F# Project and Caching Performance Options; +Enable in-memory cross project references; +IntelliSense Performance Options; +Enable stale data for IntelliSense features; +Time until stale results are used (in milliseconds); +Parallelization (requires restart); +Enable parallel type checking with signature files; +Enable parallel reference resolution; +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf index f41e35d5dd3..6b178783235 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf @@ -159,16 +159,16 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) - F# Proje ve Önbelleğe Alma Performans Seçenekleri; -Bellek içi çapraz proje başvurularını etkinleştir; -IntelliSense Performans Seçenekleri; -IntelliSense özellikleri için durum verilerini etkinleştir; -Eski sonuçlar kullanılana kadar geçen süre (milisaniye olarak); -Paralelleştirme (yeniden başlatma gerektirir); -İmza dosyalarıyla paralel tür denetlemeyi etkinleştir; -Paralel başvuru çözümlemeyi etkinleştir; -Başvuruları hızlı bulma ve yeniden adlandırmayı etkinleştir (deneysel) +Enable fast find references & rename (experimental);Cache parsing results (experimental) + F# Project and Caching Performance Options; +Enable in-memory cross project references; +IntelliSense Performance Options; +Enable stale data for IntelliSense features; +Time until stale results are used (in milliseconds); +Parallelization (requires restart); +Enable parallel type checking with signature files; +Enable parallel reference resolution; +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf index 1c54f18d6c7..58dcfed93b4 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf @@ -159,16 +159,16 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) - F# 项目和缓存性能选项; -启用内存中跨项目引用; -IntelliSense 性能选项; -为 IntelliSense 功能启用过时数据; -使用过时结果之前的时间(以毫秒为单位); -并行化(需要重启); -使用签名文件启用并行类型检查; -启用并行引用解析; -启用快速查找引用和重命名(实验性) +Enable fast find references & rename (experimental);Cache parsing results (experimental) + F# Project and Caching Performance Options; +Enable in-memory cross project references; +IntelliSense Performance Options; +Enable stale data for IntelliSense features; +Time until stale results are used (in milliseconds); +Parallelization (requires restart); +Enable parallel type checking with signature files; +Enable parallel reference resolution; +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf index fdf9d4eccc1..48a26b02975 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf @@ -159,16 +159,16 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) - F# 專案和快取效能選項; -啟用記憶體內部跨專案參考; -IntelliSense 效能選項; -啟用 IntelliSense 功能的過時資料; -使用過時結果之前的時間 (毫秒); -平行化 (需要重新開機); -啟用簽章檔案的平行類型檢查; -啟用平行參考解析; -啟用快速尋找參考和重新命名 (實驗性) +Enable fast find references & rename (experimental);Cache parsing results (experimental) + F# Project and Caching Performance Options; +Enable in-memory cross project references; +IntelliSense Performance Options; +Enable stale data for IntelliSense features; +Time until stale results are used (in milliseconds); +Parallelization (requires restart); +Enable parallel type checking with signature files; +Enable parallel reference resolution; +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.UIResources/LanguageServicePerformanceOptionControl.xaml b/vsintegration/src/FSharp.UIResources/LanguageServicePerformanceOptionControl.xaml index b61f20c47f2..0a14570aaaf 100644 --- a/vsintegration/src/FSharp.UIResources/LanguageServicePerformanceOptionControl.xaml +++ b/vsintegration/src/FSharp.UIResources/LanguageServicePerformanceOptionControl.xaml @@ -23,6 +23,9 @@ IsChecked="{Binding EnableInMemoryCrossProjectReferences}" Content="{x:Static local:Strings.Enable_in_memory_cross_project_references}" ToolTip="{x:Static local:Strings.Tooltip_in_memory_cross_project_references}"/> + diff --git a/vsintegration/src/FSharp.UIResources/Strings.Designer.cs b/vsintegration/src/FSharp.UIResources/Strings.Designer.cs index 8e3e92323e1..f983f08de3b 100644 --- a/vsintegration/src/FSharp.UIResources/Strings.Designer.cs +++ b/vsintegration/src/FSharp.UIResources/Strings.Designer.cs @@ -446,5 +446,14 @@ public static string Unused_opens_code_fix { return ResourceManager.GetString("Unused_opens_code_fix", resourceCulture); } } + + /// + /// Looks up a localized string similar to Cache parsing results (experimental). + /// + public static string Use_syntax_tree_cache { + get { + return ResourceManager.GetString("Use_syntax_tree_cache", resourceCulture); + } + } } } diff --git a/vsintegration/src/FSharp.UIResources/Strings.resx b/vsintegration/src/FSharp.UIResources/Strings.resx index e97f18d0ecc..06637b5c147 100644 --- a/vsintegration/src/FSharp.UIResources/Strings.resx +++ b/vsintegration/src/FSharp.UIResources/Strings.resx @@ -246,4 +246,7 @@ Live Buffers (experimental) + + Cache parsing results (experimental) + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf index fc4e33ea0ba..ecc69bdb7bf 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf @@ -217,6 +217,11 @@ Navrhovat názvy pro nerozpoznané identifikátory + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf index 5a6b51190cf..985a768fafa 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf @@ -217,6 +217,11 @@ Namen für nicht aufgelöste Bezeichner vorschlagen + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf index 2d6d8a5f9f7..23d97525d5c 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf @@ -217,6 +217,11 @@ Sugerir nombres para los identificadores no resueltos + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf index 532a06cabfe..78506af53e0 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf @@ -217,6 +217,11 @@ Suggérer des noms pour les identificateurs non résolus + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf index ae11082955f..f7fe9890e34 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf @@ -217,6 +217,11 @@ Suggerisci nomi per gli identificatori non risolti + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf index d78f5c41b30..fb10b926922 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf @@ -217,6 +217,11 @@ 未解決の識別子の名前を提案します + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf index 4fb3c03af6a..6c72922fc6e 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf @@ -217,6 +217,11 @@ 확인되지 않은 식별자의 이름 제안 + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf index 9a68f70402b..363ea00d6f1 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf @@ -217,6 +217,11 @@ Sugeruj nazwy w przypadku nierozpoznanych identyfikatorów + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf index 25edf6f7928..77341c45040 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf @@ -217,6 +217,11 @@ Sugerir nomes para identificadores não resolvidos + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf index ddb8daca5ef..890d7590393 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf @@ -217,6 +217,11 @@ Предлагать имена для неразрешенных идентификаторов + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf index f82d4483139..8aaacb976c9 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf @@ -217,6 +217,11 @@ Çözümlenmemiş tanımlayıcılar için ad öner + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf index 4256946d180..626ecc0c9ba 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf @@ -217,6 +217,11 @@ 为未解析标识符建议名称 + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf index e1069a83cce..68d7d958056 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf @@ -217,6 +217,11 @@ 為未解析的識別碼建議名稱 + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file