From c069beb4c1be114b9ba866b9dd578f136f27f72f Mon Sep 17 00:00:00 2001 From: Don Syme Date: Sat, 19 Sep 2020 16:59:50 +0100 Subject: [PATCH 01/12] fix script editing perf --- .../DependencyProvider.fs | 43 +++++++++++-------- .../Classification/ClassificationService.fs | 2 +- .../CodeFix/AddOpenCodeFixProvider.fs | 2 +- .../ImplementInterfaceCodeFixProvider.fs | 2 +- .../CodeFix/RemoveUnusedOpens.fs | 3 +- .../CodeFix/RenameUnusedValue.fs | 2 +- .../CodeFix/ReplaceWithSuggestion.fs | 2 +- .../CodeLens/FSharpCodeLensService.fs | 3 +- .../Commands/HelpContextService.fs | 2 +- .../Commands/XmlDocCommandService.fs | 2 +- .../Completion/CompletionProvider.fs | 4 +- .../FSharp.Editor/Completion/SignatureHelp.fs | 2 +- .../Debugging/BreakpointResolutionService.fs | 2 +- .../Diagnostics/DocumentDiagnosticAnalyzer.fs | 4 +- .../SimplifyNameDiagnosticAnalyzer.fs | 2 +- .../Diagnostics/UnusedDeclarationsAnalyzer.fs | 2 +- .../UnusedOpensDiagnosticAnalyzer.fs | 2 +- .../DocumentHighlightsService.fs | 2 +- .../Formatting/BraceMatchingService.fs | 6 +-- .../Formatting/EditorFormattingService.fs | 17 +++----- .../Formatting/IndentationService.fs | 8 ++-- .../InlineRename/InlineRenameService.fs | 2 +- .../FSharpProjectOptionsManager.fs | 34 +++++++++------ .../LanguageService/SymbolHelpers.fs | 4 +- .../Navigation/FindUsagesService.fs | 2 +- .../Navigation/GoToDefinition.fs | 8 ++-- .../Navigation/NavigateToSearchService.fs | 3 +- .../Navigation/NavigationBarItemService.fs | 2 +- .../QuickInfo/QuickInfoProvider.fs | 2 +- .../Structure/BlockStructureService.fs | 2 +- 30 files changed, 91 insertions(+), 82 deletions(-) diff --git a/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs b/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs index 2146c10b750..c3c7046ef29 100644 --- a/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs +++ b/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs @@ -8,6 +8,7 @@ open System.Reflection open System.Runtime.InteropServices open Internal.Utilities.FSharpEnvironment open Microsoft.FSharp.Reflection +open System.Collections.Concurrent [] module ReflectionHelper = @@ -88,19 +89,19 @@ type IResolveDependenciesResult = abstract Success: bool /// The resolution output log - abstract StdOut: string array + abstract StdOut: string[] /// The resolution error log (* process stderror *) - abstract StdError: string array + abstract StdError: string[] /// The resolution paths - abstract Resolutions: string seq + abstract Resolutions: seq /// The source code file paths - abstract SourceFiles: string seq + abstract SourceFiles: seq /// The roots to package directories - abstract Roots: string seq + abstract Roots: seq [] @@ -326,6 +327,8 @@ type DependencyProvider (assemblyProbingPaths: AssemblyResolutionProbe, nativePr None managers + let cache = ConcurrentDictionary<_,IResolveDependenciesResult>(HashIdentity.Structural) + /// Returns a formatted error message for the host to presentconstruct with just nativeProbing handler new (nativeProbingRoots: NativeResolutionProbe) = new DependencyProvider(Unchecked.defaultof, nativeProbingRoots) @@ -390,20 +393,24 @@ type DependencyProvider (assemblyProbingPaths: AssemblyResolutionProbe, nativePr []implicitIncludeDir: string, []mainScriptName: string, []fileName: string): IResolveDependenciesResult = + + let key = (packageManager.Key, scriptExt, Seq.toArray packageManagerTextLines, executionTfm, executionRid, implicitIncludeDir, mainScriptName, fileName) - try - let executionRid = - if isNull executionRid then - RidHelpers.platformRid - else - executionRid - packageManager.ResolveDependencies(implicitIncludeDir, mainScriptName, fileName, scriptExt, packageManagerTextLines, executionTfm, executionRid) - - with e -> - let e = stripTieWrapper e - let err, msg = (DependencyManager.SR.packageManagerError(e.Message)) - reportError.Invoke(ErrorReportType.Error, err, msg) - ReflectionDependencyManagerProvider.MakeResultFromFields(false, arrEmpty, arrEmpty, seqEmpty, seqEmpty, seqEmpty) + cache.GetOrAdd(key, System.Func<_,_>(fun _ -> + try + let executionRid = + if isNull executionRid then + RidHelpers.platformRid + else + executionRid + packageManager.ResolveDependencies(implicitIncludeDir, mainScriptName, fileName, scriptExt, packageManagerTextLines, executionTfm, executionRid) + + with e -> + let e = stripTieWrapper e + let err, msg = (DependencyManager.SR.packageManagerError(e.Message)) + reportError.Invoke(ErrorReportType.Error, err, msg) + ReflectionDependencyManagerProvider.MakeResultFromFields(false, arrEmpty, arrEmpty, seqEmpty, seqEmpty, seqEmpty) + )) interface IDisposable with diff --git a/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs b/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs index 77d349e091e..916ad1e2f29 100644 --- a/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs +++ b/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs @@ -158,7 +158,7 @@ type internal FSharpClassificationService asyncMaybe { use _logBlock = Logger.LogBlock(LogEditorFunctionId.Classification_Semantic) - let! _, _, projectOptions = projectInfoManager.TryGetOptionsForDocumentOrProject(document, cancellationToken) + let! _, _, projectOptions = projectInfoManager.TryGetOptionsForDocumentOrProject(document, cancellationToken, userOpName) let! sourceText = document.GetTextAsync(cancellationToken) // If we are trying to get semantic classification for a document that is not open, get the results from the background and cache it. diff --git a/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs b/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs index 902d32357f0..5810202d7af 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs @@ -96,7 +96,7 @@ type internal FSharpAddOpenCodeFixProvider override __.RegisterCodeFixesAsync context : Task = asyncMaybe { let document = context.Document - let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken) + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken, userOpName) let! sourceText = context.Document.GetTextAsync(context.CancellationToken) let! _, parsedInput, checkResults = checker.ParseAndCheckDocument(document, projectOptions, sourceText = sourceText, userOpName = userOpName) let line = sourceText.Lines.GetLineFromPosition(context.Span.End) diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs b/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs index d50fce766fa..4f995284b90 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs @@ -138,7 +138,7 @@ type internal FSharpImplementInterfaceCodeFixProvider override __.RegisterCodeFixesAsync context : Task = asyncMaybe { - let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(context.Document, context.CancellationToken) + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(context.Document, context.CancellationToken, userOpName) let cancellationToken = context.CancellationToken let! sourceText = context.Document.GetTextAsync(cancellationToken) let! _, parsedInput, checkFileResults = checker.ParseAndCheckDocument(context.Document, projectOptions, sourceText = sourceText, userOpName = userOpName) diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs b/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs index 8b659aafb32..9f9d81cb9b9 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs @@ -22,6 +22,7 @@ type internal FSharpRemoveUnusedOpensCodeFixProvider projectInfoManager: FSharpProjectOptionsManager ) = inherit CodeFixProvider() + let userOpName = "FSharpRemoveUnusedOpensCodeFixProvider" let fixableDiagnosticIds = [FSharpIDEDiagnosticIds.RemoveUnnecessaryImportsDiagnosticId] let createCodeFix (title: string, context: CodeFixContext) = @@ -32,7 +33,7 @@ type internal FSharpRemoveUnusedOpensCodeFixProvider let document = context.Document let! sourceText = document.GetTextAsync() let checker = checkerProvider.Checker - let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken) + let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken, userOpName) let! unusedOpens = UnusedOpensDiagnosticAnalyzer.GetUnusedOpenRanges(document, projectOptions, checker) let changes = unusedOpens diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs b/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs index 67379326323..d4f564f75f3 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs @@ -57,7 +57,7 @@ type internal FSharpRenameUnusedValueCodeFixProvider // We have to use the additional check for backtickes because `IsOperatorOrBacktickedName` operates on display names // where backtickes are replaced with parens. if not (PrettyNaming.IsOperatorOrBacktickedName ident) && not (ident.StartsWith "``") then - let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken) + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken, userOpName) let! _, _, checkResults = checker.ParseAndCheckDocument(document, projectOptions, sourceText = sourceText, userOpName=userOpName) let m = RoslynHelpers.TextSpanToFSharpRange(document.FilePath, context.Span, sourceText) let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ReplaceWithSuggestion.fs b/vsintegration/src/FSharp.Editor/CodeFix/ReplaceWithSuggestion.fs index 969cfb55a16..628508e76b6 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/ReplaceWithSuggestion.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/ReplaceWithSuggestion.fs @@ -33,7 +33,7 @@ type internal FSharpReplaceWithSuggestionCodeFixProvider do! Option.guard settings.CodeFixes.SuggestNamesForErrors let document = context.Document - let! _, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken) + let! _, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken, userOpName) let! parseFileResults, _, checkFileResults = checker.ParseAndCheckDocument(document, projectOptions, userOpName=userOpName) // This is all needed to get a declaration list diff --git a/vsintegration/src/FSharp.Editor/CodeLens/FSharpCodeLensService.fs b/vsintegration/src/FSharp.Editor/CodeLens/FSharpCodeLensService.fs index 668606afa20..dd2b8271dc8 100644 --- a/vsintegration/src/FSharp.Editor/CodeLens/FSharpCodeLensService.fs +++ b/vsintegration/src/FSharp.Editor/CodeLens/FSharpCodeLensService.fs @@ -52,6 +52,7 @@ type internal FSharpCodeLensService ) as self = let lineLens = codeLens + let userOpName = "FSharpCodeLensService" let visit pos parseTree = AstTraversal.Traverse(pos, parseTree, { new AstTraversal.AstVisitorBase<_>() with @@ -154,7 +155,7 @@ type internal FSharpCodeLensService logInfof "Rechecking code due to buffer edit!" #endif let! document = workspace.CurrentSolution.GetDocument(documentId.Value) |> Option.ofObj - let! _, options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, bufferChangedCts.Token) + let! _, options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, bufferChangedCts.Token, userOpName) let! _, parsedInput, checkFileResults = checker.ParseAndCheckDocument(document, options, "LineLens", allowStaleResults=true) #if DEBUG logInfof "Getting uses of all symbols!" diff --git a/vsintegration/src/FSharp.Editor/Commands/HelpContextService.fs b/vsintegration/src/FSharp.Editor/Commands/HelpContextService.fs index 1683cb6a4a7..ffdb586ff57 100644 --- a/vsintegration/src/FSharp.Editor/Commands/HelpContextService.fs +++ b/vsintegration/src/FSharp.Editor/Commands/HelpContextService.fs @@ -98,7 +98,7 @@ type internal FSharpHelpContextService member this.GetHelpTermAsync(document, textSpan, cancellationToken) = asyncMaybe { - let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) + let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let! sourceText = document.GetTextAsync(cancellationToken) let! textVersion = document.GetTextVersionAsync(cancellationToken) let defines = projectInfoManager.GetCompilationDefinesForEditingDocument(document) diff --git a/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs b/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs index 11922d0d0d0..107cde020bf 100644 --- a/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs +++ b/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs @@ -67,7 +67,7 @@ type internal XmlDocCommandFilter // XmlDocable line #1 are 1-based, editor is 0-based let curLineNum = wpfTextView.Caret.Position.BufferPosition.GetContainingLine().LineNumber + 1 let! document = document.Value - let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, CancellationToken.None) + let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, CancellationToken.None, userOpName) let! sourceText = document.GetTextAsync(CancellationToken.None) let! parsedInput = checker.ParseDocument(document, parsingOptions, sourceText, userOpName) let xmlDocables = XmlDocParser.getXmlDocables (sourceText.ToFSharpSourceText(), Some parsedInput) diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs index 11c5f3f0c57..acca943c970 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs @@ -228,7 +228,7 @@ type internal FSharpCompletionProvider let! sourceText = context.Document.GetTextAsync(context.CancellationToken) let defines = projectInfoManager.GetCompilationDefinesForEditingDocument(document) do! Option.guard (CompletionUtils.shouldProvideCompletion(document.Id, document.FilePath, defines, sourceText, context.Position)) - let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken) + let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken, userOpName) let! textVersion = context.Document.GetTextVersionAsync(context.CancellationToken) let getAllSymbols(fileCheckResults: FSharpCheckFileResults) = if settings.IntelliSense.IncludeSymbolsFromUnopenedNamespacesOrModules @@ -298,7 +298,7 @@ type internal FSharpCompletionProvider let! sourceText = document.GetTextAsync(cancellationToken) let textWithItemCommitted = sourceText.WithChanges(TextChange(item.Span, nameInCode)) let line = sourceText.Lines.GetLineFromPosition(item.Span.Start) - let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) + let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let! parsedInput = checker.ParseDocument(document, parsingOptions, sourceText, userOpName) let fullNameIdents = fullName |> Option.map (fun x -> x.Split '.') |> Option.defaultValue [||] diff --git a/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs b/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs index 02f4e938925..de4d3c597d0 100644 --- a/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs +++ b/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs @@ -197,7 +197,7 @@ type internal FSharpSignatureHelpProvider member this.GetItemsAsync(document, position, triggerInfo, cancellationToken) = asyncMaybe { try - let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) + let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let! sourceText = document.GetTextAsync(cancellationToken) let! textVersion = document.GetTextVersionAsync(cancellationToken) diff --git a/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs b/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs index 42bd5f9282d..17e2724d6ee 100644 --- a/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs +++ b/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs @@ -44,7 +44,7 @@ type internal FSharpBreakpointResolutionService interface IFSharpBreakpointResolutionService with member this.ResolveBreakpointAsync(document: Document, textSpan: TextSpan, cancellationToken: CancellationToken): Task = asyncMaybe { - let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) + let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let! sourceText = document.GetTextAsync(cancellationToken) let! range = FSharpBreakpointResolutionService.GetBreakpointLocation(checkerProvider.Checker, sourceText, document.Name, textSpan, parsingOptions) let! span = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, range) diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs index 2e7a44e2511..a8534353c65 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs @@ -112,7 +112,7 @@ type internal FSharpDocumentDiagnosticAnalyzer [] () = member this.AnalyzeSyntaxAsync(document: Document, cancellationToken: CancellationToken): Task> = let projectInfoManager = getProjectInfoManager document asyncMaybe { - let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let! sourceText = document.GetTextAsync(cancellationToken) let! textVersion = document.GetTextVersionAsync(cancellationToken) return! @@ -125,7 +125,7 @@ type internal FSharpDocumentDiagnosticAnalyzer [] () = member this.AnalyzeSemanticsAsync(document: Document, cancellationToken: CancellationToken): Task> = let projectInfoManager = getProjectInfoManager document asyncMaybe { - let! parsingOptions, _, projectOptions = projectInfoManager.TryGetOptionsForDocumentOrProject(document, cancellationToken) + let! parsingOptions, _, projectOptions = projectInfoManager.TryGetOptionsForDocumentOrProject(document, cancellationToken, userOpName) let! sourceText = document.GetTextAsync(cancellationToken) let! textVersion = document.GetTextVersionAsync(cancellationToken) if document.Project.Name <> FSharpConstants.FSharpMiscellaneousFilesName || isScriptFile document.FilePath then diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs index 09ee9cc2390..e888ccdc7ce 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs @@ -41,7 +41,7 @@ type internal SimplifyNameDiagnosticAnalyzer [] () = do! Option.guard document.FSharpOptions.CodeFixes.SimplifyName do Trace.TraceInformation("{0:n3} (start) SimplifyName", DateTime.Now.TimeOfDay.TotalSeconds) do! Async.Sleep DefaultTuning.SimplifyNameInitialDelay |> liftAsync - let! _parsingOptions, projectOptions = getProjectInfoManager(document).TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) + let! _parsingOptions, projectOptions = getProjectInfoManager(document).TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let! textVersion = document.GetTextVersionAsync(cancellationToken) let textVersionHash = textVersion.GetHashCode() let! _ = guard.WaitAsync(cancellationToken) |> Async.AwaitTask |> liftAsync diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs index 28f1b1f9c4f..66c0a60e452 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs @@ -31,7 +31,7 @@ type internal UnusedDeclarationsAnalyzer [] () = do Trace.TraceInformation("{0:n3} (start) UnusedDeclarationsAnalyzer", DateTime.Now.TimeOfDay.TotalSeconds) do! Async.Sleep DefaultTuning.UnusedDeclarationsAnalyzerInitialDelay |> liftAsync // be less intrusive, give other work priority most of the time - match! getProjectInfoManager(document).TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) with + match! getProjectInfoManager(document).TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) with | (_parsingOptions, projectOptions) -> let! sourceText = document.GetTextAsync() let checker = getChecker document diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs index 629989ca454..f9e4d917c2d 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs @@ -51,7 +51,7 @@ type internal UnusedOpensDiagnosticAnalyzer [] () = asyncMaybe { do Trace.TraceInformation("{0:n3} (start) UnusedOpensAnalyzer", DateTime.Now.TimeOfDay.TotalSeconds) do! Async.Sleep DefaultTuning.UnusedOpensAnalyzerInitialDelay |> liftAsync // be less intrusive, give other work priority most of the time - let! _parsingOptions, projectOptions = getProjectInfoManager(document).TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) + let! _parsingOptions, projectOptions = getProjectInfoManager(document).TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let! sourceText = document.GetTextAsync() let checker = getChecker document let! unusedOpens = UnusedOpensDiagnosticAnalyzer.GetUnusedOpenRanges(document, projectOptions, checker) diff --git a/vsintegration/src/FSharp.Editor/DocumentHighlights/DocumentHighlightsService.fs b/vsintegration/src/FSharp.Editor/DocumentHighlights/DocumentHighlightsService.fs index 10ee6533790..6ceb996cf1e 100644 --- a/vsintegration/src/FSharp.Editor/DocumentHighlights/DocumentHighlightsService.fs +++ b/vsintegration/src/FSharp.Editor/DocumentHighlights/DocumentHighlightsService.fs @@ -75,7 +75,7 @@ type internal FSharpDocumentHighlightsService [] (checkerP interface IFSharpDocumentHighlightsService with member __.GetDocumentHighlightsAsync(document, position, _documentsToSearch, cancellationToken) : Task> = asyncMaybe { - let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let! sourceText = document.GetTextAsync(cancellationToken) let! textVersion = document.GetTextVersionAsync(cancellationToken) let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions diff --git a/vsintegration/src/FSharp.Editor/Formatting/BraceMatchingService.fs b/vsintegration/src/FSharp.Editor/Formatting/BraceMatchingService.fs index 794fd5de362..8b6cacb5436 100644 --- a/vsintegration/src/FSharp.Editor/Formatting/BraceMatchingService.fs +++ b/vsintegration/src/FSharp.Editor/Formatting/BraceMatchingService.fs @@ -17,7 +17,7 @@ type internal FSharpBraceMatchingService projectInfoManager: FSharpProjectOptionsManager ) = - static let defaultUserOpName = "BraceMatching" + static let userOpName = "BraceMatching" static member GetBraceMatchingResult(checker: FSharpChecker, sourceText: SourceText, fileName, parsingOptions: FSharpParsingOptions, position: int, userOpName: string, [] forFormatting: bool) = async { @@ -37,9 +37,9 @@ type internal FSharpBraceMatchingService interface IFSharpBraceMatcher with member this.FindBracesAsync(document, position, cancellationToken) = asyncMaybe { - let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) + let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let! sourceText = document.GetTextAsync(cancellationToken) - let! (left, right) = FSharpBraceMatchingService.GetBraceMatchingResult(checkerProvider.Checker, sourceText, document.Name, parsingOptions, position, defaultUserOpName) + let! (left, right) = FSharpBraceMatchingService.GetBraceMatchingResult(checkerProvider.Checker, sourceText, document.Name, parsingOptions, position, userOpName) let! leftSpan = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, left) let! rightSpan = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, right) return FSharpBraceMatchingResult(leftSpan, rightSpan) diff --git a/vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs b/vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs index 4cc4b10c5a2..01f3938758c 100644 --- a/vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs +++ b/vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs @@ -29,7 +29,7 @@ type internal FSharpEditorFormattingService static let getIndentation (line : string) = line |> Seq.takeWhile ((=) ' ') |> Seq.length - static member GetFormattingChanges(documentId: DocumentId, sourceText: SourceText, filePath: string, checker: FSharpChecker, indentStyle: FormattingOptions.IndentStyle, options: (FSharpParsingOptions * FSharpProjectOptions) option, position: int) = + static member GetFormattingChanges(documentId: DocumentId, sourceText: SourceText, filePath: string, checker: FSharpChecker, indentStyle: FormattingOptions.IndentStyle, parsingOptions: FSharpParsingOptions, position: int) = // Logic for determining formatting changes: // If first token on the current line is a closing brace, // match the indent with the indent on the line that opened it @@ -40,8 +40,6 @@ type internal FSharpEditorFormattingService // (this is what C# does) do! Option.guard (indentStyle = FormattingOptions.IndentStyle.Smart) - let! parsingOptions, _projectOptions = options - let line = sourceText.Lines.[sourceText.Lines.IndexOf position] let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions @@ -151,8 +149,8 @@ type internal FSharpEditorFormattingService let! sourceText = document.GetTextAsync(cancellationToken) |> Async.AwaitTask let! options = document.GetOptionsAsync(cancellationToken) |> Async.AwaitTask let indentStyle = options.GetOption(FormattingOptions.SmartIndent, FSharpConstants.FSharpLanguageName) - let! projectOptionsOpt = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) - let! textChange = FSharpEditorFormattingService.GetFormattingChanges(document.Id, sourceText, document.FilePath, checkerProvider.Checker, indentStyle, projectOptionsOpt, position) + let parsingOptions = projectInfoManager.TryGetQuickParsingOptionsForEditingDocumentOrProject(document) + let! textChange = FSharpEditorFormattingService.GetFormattingChanges(document.Id, sourceText, document.FilePath, checkerProvider.Checker, indentStyle, parsingOptions, position) return textChange |> Option.toList |> toIList } @@ -162,12 +160,9 @@ type internal FSharpEditorFormattingService let! options = document.GetOptionsAsync(cancellationToken) |> Async.AwaitTask let tabSize = options.GetOption(FormattingOptions.TabSize, FSharpConstants.FSharpLanguageName) - match! projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) with - | Some (parsingOptions, _) -> - let! textChanges = FSharpEditorFormattingService.GetPasteChanges(document.Id, sourceText, document.FilePath, settings.Formatting, tabSize, parsingOptions, currentClipboard, span) - return textChanges |> Option.defaultValue Seq.empty |> toIList - | None -> - return toIList Seq.empty + let parsingOptions = projectInfoManager.TryGetQuickParsingOptionsForEditingDocumentOrProject(document) + let! textChanges = FSharpEditorFormattingService.GetPasteChanges(document.Id, sourceText, document.FilePath, settings.Formatting, tabSize, parsingOptions, currentClipboard, span) + return textChanges |> Option.defaultValue Seq.empty |> toIList } interface IFSharpEditorFormattingService with diff --git a/vsintegration/src/FSharp.Editor/Formatting/IndentationService.fs b/vsintegration/src/FSharp.Editor/Formatting/IndentationService.fs index a888518523d..32b06175449 100644 --- a/vsintegration/src/FSharp.Editor/Formatting/IndentationService.fs +++ b/vsintegration/src/FSharp.Editor/Formatting/IndentationService.fs @@ -61,7 +61,7 @@ type internal FSharpIndentationService true | _ -> false - static member GetDesiredIndentation(documentId: DocumentId, sourceText: SourceText, filePath: string, lineNumber: int, tabSize: int, indentStyle: FormattingOptions.IndentStyle, options: (FSharpParsingOptions * FSharpProjectOptions) option): Option = + static member GetDesiredIndentation(documentId: DocumentId, sourceText: SourceText, filePath: string, lineNumber: int, tabSize: int, indentStyle: FormattingOptions.IndentStyle, parsingOptions: FSharpParsingOptions): Option = // Match indentation with previous line let rec tryFindPreviousNonEmptyLine l = @@ -81,8 +81,6 @@ type internal FSharpIndentationService |> Seq.takeWhile ((=) ' ') |> Seq.length - let! parsingOptions, _ = options - // Only use smart indentation after tokens that need indentation // if the option is enabled return @@ -100,8 +98,8 @@ type internal FSharpIndentationService let! options = document.GetOptionsAsync(cancellationToken) |> Async.AwaitTask let tabSize = options.GetOption(FormattingOptions.TabSize, FSharpConstants.FSharpLanguageName) let indentStyle = options.GetOption(FormattingOptions.SmartIndent, FSharpConstants.FSharpLanguageName) - let! projectOptionsOpt = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) - let indent = FSharpIndentationService.GetDesiredIndentation(document.Id, sourceText, document.FilePath, lineNumber, tabSize, indentStyle, projectOptionsOpt) + let parsingOptions = projectInfoManager.TryGetQuickParsingOptionsForEditingDocumentOrProject(document) + let indent = FSharpIndentationService.GetDesiredIndentation(document.Id, sourceText, document.FilePath, lineNumber, tabSize, indentStyle, parsingOptions) return match indent with | None -> Nullable() diff --git a/vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs b/vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs index 92778109d04..9d05c920b8e 100644 --- a/vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs +++ b/vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs @@ -169,7 +169,7 @@ type internal InlineRenameService interface IFSharpEditorInlineRenameService with member __.GetRenameInfoAsync(document: Document, position: int, cancellationToken: CancellationToken) : Task = asyncMaybe { - let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let! sourceText = document.GetTextAsync(cancellationToken) let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions return! InlineRenameService.GetInlineRenameInfo(checkerProvider.Checker, projectInfoManager, document, sourceText, position, defines, projectOptions) diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs index 96921834f38..d42c4478ed2 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs @@ -75,7 +75,7 @@ module private FSharpProjectOptionsHelpers = [] type private FSharpProjectOptionsMessage = - | TryGetOptionsByDocument of Document * AsyncReplyChannel<(FSharpParsingOptions * FSharpProjectOptions) option> * CancellationToken + | TryGetOptionsByDocument of Document * AsyncReplyChannel<(FSharpParsingOptions * FSharpProjectOptions) option> * CancellationToken * userOpName: string | TryGetOptionsByProject of Project * AsyncReplyChannel<(FSharpParsingOptions * FSharpProjectOptions) option> * CancellationToken | ClearOptions of ProjectId | ClearSingleFileOptionsCache of DocumentId @@ -92,13 +92,13 @@ type private FSharpProjectOptionsReactor (workspace: Workspace, settings: Editor let cache = ConcurrentDictionary() let singleFileCache = ConcurrentDictionary() - let rec tryComputeOptionsByFile (document: Document) (ct: CancellationToken) = + let rec tryComputeOptionsByFile (document: Document) (ct: CancellationToken) userOpName = async { let! fileStamp = document.GetTextVersionAsync(ct) |> Async.AwaitTask match singleFileCache.TryGetValue(document.Id) with | false, _ -> let! sourceText = document.GetTextAsync(ct) |> Async.AwaitTask - let! scriptProjectOptions, _ = checkerProvider.Checker.GetProjectOptionsFromScript(document.FilePath, sourceText.ToFSharpSourceText(), SessionsProperties.fsiPreview) + let! scriptProjectOptions, _ = checkerProvider.Checker.GetProjectOptionsFromScript(document.FilePath, sourceText.ToFSharpSourceText(), SessionsProperties.fsiPreview, userOpName=userOpName) let projectOptions = if isScriptFile document.FilePath then scriptProjectOptions @@ -129,7 +129,7 @@ type private FSharpProjectOptionsReactor (workspace: Workspace, settings: Editor | true, (fileStamp2, parsingOptions, projectOptions) -> if fileStamp <> fileStamp2 then singleFileCache.TryRemove(document.Id) |> ignore - return! tryComputeOptionsByFile document ct + return! tryComputeOptionsByFile document ct userOpName else return Some(parsingOptions, projectOptions) } @@ -244,7 +244,7 @@ type private FSharpProjectOptionsReactor (workspace: Workspace, settings: Editor async { while true do match! agent.Receive() with - | FSharpProjectOptionsMessage.TryGetOptionsByDocument(document, reply, ct) -> + | FSharpProjectOptionsMessage.TryGetOptionsByDocument(document, reply, ct, userOpName) -> if ct.IsCancellationRequested then reply.Reply None else @@ -253,7 +253,7 @@ type private FSharpProjectOptionsReactor (workspace: Workspace, settings: Editor if document.Project.Solution.Workspace.Kind = WorkspaceKind.MiscellaneousFiles then reply.Reply None elif document.Project.Name = FSharpConstants.FSharpMiscellaneousFilesName then - let! options = tryComputeOptionsByFile document ct + let! options = tryComputeOptionsByFile document ct userOpName reply.Reply options else // We only care about the latest project in the workspace's solution. @@ -300,8 +300,8 @@ type private FSharpProjectOptionsReactor (workspace: Workspace, settings: Editor member __.TryGetOptionsByProjectAsync(project, ct) = agent.PostAndAsyncReply(fun reply -> FSharpProjectOptionsMessage.TryGetOptionsByProject(project, reply, ct)) - member __.TryGetOptionsByDocumentAsync(document, ct) = - agent.PostAndAsyncReply(fun reply -> FSharpProjectOptionsMessage.TryGetOptionsByDocument(document, reply, ct)) + member __.TryGetOptionsByDocumentAsync(document, ct, userOpName) = + agent.PostAndAsyncReply(fun reply -> FSharpProjectOptionsMessage.TryGetOptionsByDocument(document, reply, ct, userOpName)) member __.ClearOptionsByProjectId(projectId) = agent.Post(FSharpProjectOptionsMessage.ClearOptions(projectId)) @@ -379,23 +379,29 @@ type internal FSharpProjectOptionsManager reactor.TryGetOptionsByProjectAsync(project) /// Get the exact options for a document or project - member this.TryGetOptionsForDocumentOrProject(document: Document, cancellationToken) = + member this.TryGetOptionsForDocumentOrProject(document: Document, cancellationToken, userOpName) = async { - match! reactor.TryGetOptionsByDocumentAsync(document, cancellationToken) with + match! reactor.TryGetOptionsByDocumentAsync(document, cancellationToken, userOpName) with | Some(parsingOptions, projectOptions) -> return Some(parsingOptions, None, projectOptions) | _ -> return None } - /// Get the options for a document or project relevant for syntax processing. - /// Quicker then TryGetOptionsForDocumentOrProject as it doesn't need to recompute the exact project options for a script. - member this.TryGetOptionsForEditingDocumentOrProject(document:Document, cancellationToken) = + /// Get the exact options for a document or project relevant for syntax processing. + member this.TryGetOptionsForEditingDocumentOrProject(document:Document, cancellationToken, userOpName) = async { - let! result = this.TryGetOptionsForDocumentOrProject(document, cancellationToken) + let! result = this.TryGetOptionsForDocumentOrProject(document, cancellationToken, userOpName) return result |> Option.map(fun (parsingOptions, _, projectOptions) -> parsingOptions, projectOptions) } + /// Get the options for a document or project relevant for syntax processing. + /// Quicker it doesn't need to recompute the exact project options for a script. + member this.TryGetQuickParsingOptionsForEditingDocumentOrProject(document:Document) = + match reactor.TryGetCachedOptionsByProjectId(document.Project.Id) with + | Some (_, parsingOptions, _) -> parsingOptions + | _ -> { FSharpParsingOptions.Default with IsInteractive = FSharpFileUtilities.isScriptFile document.Name } + [] /// This handles commandline change notifications from the Dotnet Project-system /// Prior to VS 15.7 path contained path to project file, post 15.7 contains target binpath diff --git a/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs b/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs index 3dbe12fc40d..22100b4f158 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs @@ -25,7 +25,7 @@ module internal SymbolHelpers = let textLine = sourceText.Lines.GetLineFromPosition(position) let textLinePos = sourceText.Lines.GetLinePosition(position) let fcsTextLineNumber = Line.fromZ textLinePos.Line - let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions let! symbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, false) let settings = document.FSharpOptions @@ -118,7 +118,7 @@ module internal SymbolHelpers = let! sourceText = document.GetTextAsync(cancellationToken) let originalText = sourceText.ToString(symbolSpan) do! Option.guard (originalText.Length > 0) - let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions let! symbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, symbolSpan.Start, document.FilePath, defines, SymbolLookupKind.Greedy, false) let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, projectOptions, userOpName = userOpName) diff --git a/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs b/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs index ff841e4b5fc..f742a679474 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs @@ -51,7 +51,7 @@ type internal FSharpFindUsagesService asyncMaybe { let! sourceText = document.GetTextAsync(context.CancellationToken) |> Async.AwaitTask |> liftAsync let checker = checkerProvider.Checker - let! parsingOptions, _, projectOptions = projectInfoManager.TryGetOptionsForDocumentOrProject(document, context.CancellationToken) + let! parsingOptions, _, projectOptions = projectInfoManager.TryGetOptionsForDocumentOrProject(document, context.CancellationToken, userOpName) let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, projectOptions, sourceText = sourceText, userOpName = userOpName) let textLine = sourceText.Lines.GetLineFromPosition(position).ToString() let lineNumber = sourceText.Lines.GetLinePosition(position).Line + 1 diff --git a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs index a607442e462..4c3c00e6943 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs @@ -168,7 +168,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP /// Helper function that is used to determine the navigation strategy to apply, can be tuned towards signatures or implementation files. member private __.FindSymbolHelper (originDocument: Document, originRange: range, sourceText: SourceText, preferSignature: bool) = asyncMaybe { - let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(originDocument, CancellationToken.None) + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(originDocument, CancellationToken.None, userOpName) let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions let! originTextSpan = RoslynHelpers.TryFSharpRangeToTextSpan (sourceText, originRange) let position = originTextSpan.Start @@ -190,7 +190,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP if not (File.Exists fsfilePath) then return! None else let! implDoc = originDocument.Project.Solution.TryGetDocumentFromPath fsfilePath let! implSourceText = implDoc.GetTextAsync () - let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(implDoc, CancellationToken.None) + let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(implDoc, CancellationToken.None, userOpName) let! _, _, checkFileResults = checker.ParseAndCheckDocument (implDoc, projectOptions, sourceText=implSourceText, userOpName=userOpName) let! symbolUses = checkFileResults.GetUsesOfSymbolInFile symbol |> liftAsync let! implSymbol = symbolUses |> Array.tryHead @@ -220,7 +220,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP member private this.FindDefinitionAtPosition(originDocument: Document, position: int) = asyncMaybe { - let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(originDocument, CancellationToken.None) + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(originDocument, CancellationToken.None, userOpName) let! sourceText = originDocument.GetTextAsync () |> liftTaskAsync let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions let textLine = sourceText.Lines.GetLineFromPosition position @@ -307,7 +307,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP let! implDocument = originDocument.Project.Solution.TryGetDocumentFromPath implFilePath let! implVersion = implDocument.GetTextVersionAsync () |> liftTaskAsync let! implSourceText = implDocument.GetTextAsync () |> liftTaskAsync - let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(implDocument, CancellationToken.None) + let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(implDocument, CancellationToken.None, userOpName) let! targetRange = this.FindSymbolDeclarationInFile(targetSymbolUse, implFilePath, implSourceText, projectOptions, implVersion.GetHashCode()) diff --git a/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs b/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs index 428ca48ef62..3fb063047ec 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs @@ -172,6 +172,7 @@ type internal FSharpNavigateToSearchService projectInfoManager: FSharpProjectOptionsManager ) = + let userOpName = "FSharpNavigateToSearchService" let kindsProvided = ImmutableHashSet.Create(FSharpNavigateToItemKind.Module, FSharpNavigateToItemKind.Class, FSharpNavigateToItemKind.Field, FSharpNavigateToItemKind.Property, FSharpNavigateToItemKind.Method, FSharpNavigateToItemKind.Enum, FSharpNavigateToItemKind.EnumItem) :> IImmutableSet // Save the backing navigation data in a memory cache held in a sliding window @@ -261,7 +262,7 @@ type internal FSharpNavigateToSearchService member __.SearchDocumentAsync(document, searchPattern, kinds, cancellationToken) : Task> = asyncMaybe { - let! parsingOptions, _, _ = projectInfoManager.TryGetOptionsForDocumentOrProject(document, cancellationToken) + let! parsingOptions, _, _ = projectInfoManager.TryGetOptionsForDocumentOrProject(document, cancellationToken, userOpName) let! items = getCachedIndexedNavigableItems(document, parsingOptions, kinds) |> liftAsync return items.Find(searchPattern) } diff --git a/vsintegration/src/FSharp.Editor/Navigation/NavigationBarItemService.fs b/vsintegration/src/FSharp.Editor/Navigation/NavigationBarItemService.fs index d8edebd3ac1..13350004ab1 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/NavigationBarItemService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/NavigationBarItemService.fs @@ -32,7 +32,7 @@ type internal FSharpNavigationBarItemService interface IFSharpNavigationBarItemService with member __.GetItemsAsync(document, cancellationToken) : Task> = asyncMaybe { - let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) + let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let! sourceText = document.GetTextAsync(cancellationToken) let! parsedInput = checkerProvider.Checker.ParseDocument(document, parsingOptions, sourceText=sourceText, userOpName=userOpName) let navItems = FSharpNavigation.getNavigation parsedInput diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs index a6ea0c90332..cd5d0fc143e 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs @@ -92,7 +92,7 @@ module internal FSharpQuickInfo = asyncMaybe { let! sourceText = document.GetTextAsync cancellationToken - let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions let! lexerSymbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, true) let idRange = lexerSymbol.Ident.idRange diff --git a/vsintegration/src/FSharp.Editor/Structure/BlockStructureService.fs b/vsintegration/src/FSharp.Editor/Structure/BlockStructureService.fs index 9123aea5f1e..13c74ef0f53 100644 --- a/vsintegration/src/FSharp.Editor/Structure/BlockStructureService.fs +++ b/vsintegration/src/FSharp.Editor/Structure/BlockStructureService.fs @@ -152,7 +152,7 @@ type internal FSharpBlockStructureService [] (checkerProvi member __.GetBlockStructureAsync(document, cancellationToken) : Task = asyncMaybe { - let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken) + let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let! sourceText = document.GetTextAsync(cancellationToken) let! parsedInput = checkerProvider.Checker.ParseDocument(document, parsingOptions, sourceText, userOpName) return createBlockSpans document.FSharpOptions.Advanced.IsBlockStructureEnabled sourceText parsedInput |> Seq.toImmutableArray From df2ca3b385e9497d8ad4196e13aefb3b887319cf Mon Sep 17 00:00:00 2001 From: Don Syme Date: Sat, 19 Sep 2020 18:59:39 +0100 Subject: [PATCH 02/12] fix script editing perf --- vsintegration/tests/UnitTests/EditorFormattingServiceTests.fs | 2 +- vsintegration/tests/UnitTests/IndentationServiceTests.fs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vsintegration/tests/UnitTests/EditorFormattingServiceTests.fs b/vsintegration/tests/UnitTests/EditorFormattingServiceTests.fs index fbcfc1125af..3a5b70f2051 100644 --- a/vsintegration/tests/UnitTests/EditorFormattingServiceTests.fs +++ b/vsintegration/tests/UnitTests/EditorFormattingServiceTests.fs @@ -78,7 +78,7 @@ marker4""" let lineNumber = sourceText.Lines |> Seq.findIndex (fun line -> line.Span.Contains position) let parsingOptions, _ = checker.GetParsingOptionsFromProjectOptions projectOptions - let changesOpt = FSharpEditorFormattingService.GetFormattingChanges(documentId, sourceText, filePath, checker, indentStyle, Some (parsingOptions, projectOptions), position) |> Async.RunSynchronously + let changesOpt = FSharpEditorFormattingService.GetFormattingChanges(documentId, sourceText, filePath, checker, indentStyle, parsingOptions, position) |> Async.RunSynchronously match changesOpt with | None -> Assert.Fail("Expected a text change, but got None") | Some changes -> diff --git a/vsintegration/tests/UnitTests/IndentationServiceTests.fs b/vsintegration/tests/UnitTests/IndentationServiceTests.fs index d16c48ddab2..a1a8cb0943f 100644 --- a/vsintegration/tests/UnitTests/IndentationServiceTests.fs +++ b/vsintegration/tests/UnitTests/IndentationServiceTests.fs @@ -176,7 +176,7 @@ while true do let sourceText = SourceText.From(template) let parsingOptions, _ = checker.GetParsingOptionsFromProjectOptions projectOptions - let actualIndentation = FSharpIndentationService.GetDesiredIndentation(documentId, sourceText, filePath, lineNumber, tabSize, indentStyle, Some (parsingOptions, projectOptions)) + let actualIndentation = FSharpIndentationService.GetDesiredIndentation(documentId, sourceText, filePath, lineNumber, tabSize, indentStyle, parsingOptions) match expectedIndentation with | None -> Assert.IsTrue(actualIndentation.IsNone, "No indentation was expected at line {0}", lineNumber) | Some indentation -> Assert.AreEqual(expectedIndentation.Value, actualIndentation.Value, "Indentation on line {0} doesn't match", lineNumber) @@ -189,7 +189,7 @@ while true do let sourceText = SourceText.From(template) let parsingOptions, _ = checker.GetParsingOptionsFromProjectOptions projectOptions - let actualIndentation = FSharpIndentationService.GetDesiredIndentation(documentId, sourceText, filePath, lineNumber, tabSize, indentStyle, Some (parsingOptions, projectOptions)) + let actualIndentation = FSharpIndentationService.GetDesiredIndentation(documentId, sourceText, filePath, lineNumber, tabSize, indentStyle, parsingOptions) match expectedIndentation with | None -> Assert.IsTrue(actualIndentation.IsNone, "No indentation was expected at line {0}", lineNumber) | Some indentation -> Assert.AreEqual(expectedIndentation.Value, actualIndentation.Value, "Indentation on line {0} doesn't match", lineNumber) From 928cf6d153fec089c935a7fecd9ad94f930deb2b Mon Sep 17 00:00:00 2001 From: Don Syme Date: Sat, 19 Sep 2020 23:59:37 +0100 Subject: [PATCH 03/12] one DependencyProvider per project --- src/fsharp/CompileOps.fs | 205 ++++++++++-------- src/fsharp/CompileOps.fsi | 93 ++++++-- .../DependencyProvider.fs | 21 +- .../DependencyProvider.fsi | 12 +- .../NativeDllResolveHandler.fs | 5 +- .../NativeDllResolveHandler.fsi | 2 +- src/fsharp/fsc.fs | 19 +- src/fsharp/fsi/fsi.fs | 54 ++++- src/fsharp/service/FSharpCheckerResults.fs | 10 +- src/fsharp/service/IncrementalBuild.fs | 48 ++-- src/fsharp/service/IncrementalBuild.fsi | 28 ++- src/fsharp/service/service.fs | 20 +- 12 files changed, 346 insertions(+), 171 deletions(-) diff --git a/src/fsharp/CompileOps.fs b/src/fsharp/CompileOps.fs index 63dba3fed83..cdf760b3f23 100644 --- a/src/fsharp/CompileOps.fs +++ b/src/fsharp/CompileOps.fs @@ -2308,8 +2308,6 @@ type TcConfigBuilder = mutable pathMap: PathMap mutable langVersion: LanguageVersion - - mutable dependencyProvider: DependencyProvider } static member Initial = @@ -2449,7 +2447,6 @@ type TcConfigBuilder = noConditionalErasure = false pathMap = PathMap.empty langVersion = LanguageVersion("default") - dependencyProvider = Unchecked.defaultof } // Directories to start probing in @@ -2459,13 +2456,17 @@ type TcConfigBuilder = // 2. compilerToolPath directories // 3. reference dll's // 4. The implicit include directory - member private tcConfigB.nativeProbingRoots () = + // + // NOTE: it is important this is a delayed IEnumerable sequence. It is recomputed + // each time a resolution happens and additional paths may be added as a result. + member tcConfigB.GetNativeProbingRoots () = seq { yield! tcConfigB.includes yield! tcConfigB.compilerToolPaths yield! (tcConfigB.referencedDLLs |> Seq.map(fun ref -> Path.GetDirectoryName(ref.Text))) yield tcConfigB.implicitIncludeDir - } |> Seq.distinct + } + |> Seq.distinct static member CreateNew(legacyReferenceResolver, defaultFSharpBinariesDir, reduceMemoryUsage, implicitIncludeDir, isInteractive, isInvalidationSupported, defaultCopyFSharpCore, tryGetMetadataSnapshot) = @@ -2487,7 +2488,6 @@ type TcConfigBuilder = tryGetMetadataSnapshot = tryGetMetadataSnapshot useFsiAuxLib = isInteractive } - tcConfigBuilder.dependencyProvider <- new DependencyProvider(NativeResolutionProbe(tcConfigBuilder.nativeProbingRoots)) tcConfigBuilder member tcConfigB.ResolveSourceFile(m, nm, pathLoadedFrom) = @@ -2599,6 +2599,32 @@ type TcConfigBuilder = member tcConfigB.AddDependencyManagerText (packageManager: IDependencyManagerProvider, lt, m, path: string) = tcConfigB.packageManagerLines <- PackageManagerLine.AddLineWithKey packageManager.Key lt path m tcConfigB.packageManagerLines + member tcConfigB.AddReferenceDirective (dependencyProvider: DependencyProvider, m, path: string, directive) = + let output = tcConfigB.outputDir |> Option.defaultValue "" + + let reportError = + ResolvingErrorReport (fun errorType err msg -> + let error = err, msg + match errorType with + | ErrorReportType.Warning -> warning(Error(error, m)) + | ErrorReportType.Error -> errorR(Error(error, m))) + + let dm = dependencyProvider.TryFindDependencyManagerInPath(tcConfigB.compilerToolPaths, output , reportError, path) + + match dm with + | _, dependencyManager when not(isNull dependencyManager) -> + if tcConfigB.langVersion.SupportsFeature(LanguageFeature.PackageManagement) then + tcConfigB.AddDependencyManagerText (dependencyManager, directive, m, path) + else + errorR(Error(FSComp.SR.packageManagementRequiresVFive(), m)) + + | _, _ when directive = Directive.Include -> + errorR(Error(FSComp.SR.poundiNotSupportedByRegisteredDependencyManagers(), m)) + + // #r "Assembly" + | path, _ -> + tcConfigB.AddReferencedAssemblyByPath (m, path) + member tcConfigB.RemoveReferencedAssemblyByPath (m, path) = tcConfigB.referencedDLLs <- tcConfigB.referencedDLLs |> List.filter (fun ar -> not (Range.equals ar.Range m) || ar.Text <> path) @@ -2920,8 +2946,6 @@ type TcConfig private (data: TcConfigBuilder, validate: bool) = member x.legacyReferenceResolver = data.legacyReferenceResolver - member x.dependencyProvider = data.dependencyProvider - member tcConfig.CloneOfOriginalBuilder = { data with conditionalCompilationDefines=data.conditionalCompilationDefines } @@ -3290,6 +3314,8 @@ type TcConfig private (data: TcConfigBuilder, validate: bool) = member tcConfig.CoreLibraryDllReference() = fslibReference + member tcConfig.GetNativeProbingRoots() = data.GetNativeProbingRoots() + let ReportWarning options err = warningOn err (options.WarnLevel) (options.WarnOn) && not (List.contains (GetDiagnosticNumber err) (options.WarnOff)) @@ -3999,7 +4025,9 @@ and TcImportsWeakHack (tcImports: WeakReference) = /// Represents a table of imported assemblies with their resolutions. /// Is a disposable object, but it is recommended not to explicitly call Dispose unless you absolutely know nothing will be using its contents after the disposal. /// Otherwise, simply allow the GC to collect this and it will properly call Dispose from the finalizer. -and [] TcImports(tcConfigP: TcConfigProvider, initialResolutions: TcAssemblyResolutions, importsBase: TcImports option, ilGlobalsOpt, compilationThread: ICompilationThread) as this = +and [] TcImports(tcConfigP: TcConfigProvider, initialResolutions: TcAssemblyResolutions, importsBase: TcImports option, + ilGlobalsOpt, compilationThread: ICompilationThread, + dependencyProviderOpt: DependencyProvider option) as this = let mutable resolutions = initialResolutions let mutable importsBase: TcImports option = importsBase @@ -4330,6 +4358,14 @@ and [] TcImports(tcConfigP: TcConfigProvider, initialResolutions: TcAsse | ILScopeRef.Assembly a -> a.Name = nm | _ -> false) + member tcImports.DependencyProvider = + CheckDisposed() + match dependencyProviderOpt with + | None -> + Debug.Assert(false, "this should never be called on FrameworkTcImports") + new DependencyProvider(null, null) + | Some dependencyProvider -> dependencyProvider + member tcImports.GetImportMap() = CheckDisposed() let loaderInterface = @@ -4893,7 +4929,7 @@ and [] TcImports(tcConfigP: TcConfigProvider, initialResolutions: TcAsse let tcResolutions = TcAssemblyResolutions.BuildFromPriorResolutions(ctok, tcConfig, frameworkDLLs, []) let tcAltResolutions = TcAssemblyResolutions.BuildFromPriorResolutions(ctok, tcConfig, nonFrameworkDLLs, []) - let frameworkTcImports = new TcImports(tcConfigP, tcResolutions, None, None, tcConfig.compilationThread) + let frameworkTcImports = new TcImports(tcConfigP, tcResolutions, None, None, tcConfig.compilationThread, None) // Fetch the primaryAssembly from the referenced assemblies otherwise let primaryAssemblyReference = @@ -5019,24 +5055,27 @@ and [] TcImports(tcConfigP: TcConfigProvider, initialResolutions: TcAsse |> List.map (function UnresolvedAssemblyReference(file, originalReferences) -> file, originalReferences) |> List.iter reportAssemblyNotResolved - static member BuildNonFrameworkTcImports (ctok, tcConfigP: TcConfigProvider, tcGlobals: TcGlobals, baseTcImports, nonFrameworkReferences, knownUnresolved) = + static member BuildNonFrameworkTcImports + (ctok, tcConfigP: TcConfigProvider, tcGlobals: TcGlobals, baseTcImports, + nonFrameworkReferences, knownUnresolved, dependencyProvider) = + cancellable { let tcConfig = tcConfigP.Get ctok let tcResolutions = TcAssemblyResolutions.BuildFromPriorResolutions(ctok, tcConfig, nonFrameworkReferences, knownUnresolved) let references = tcResolutions.GetAssemblyResolutions() - let tcImports = new TcImports(tcConfigP, tcResolutions, Some baseTcImports, Some tcGlobals.ilg, tcConfig.compilationThread) + let tcImports = new TcImports(tcConfigP, tcResolutions, Some baseTcImports, Some tcGlobals.ilg, tcConfig.compilationThread, Some dependencyProvider) let! _assemblies = tcImports.RegisterAndImportReferencedAssemblies(ctok, references) tcImports.ReportUnresolvedAssemblyReferences knownUnresolved return tcImports } - static member BuildTcImports(ctok, tcConfigP: TcConfigProvider) = + static member BuildTcImports(ctok, tcConfigP: TcConfigProvider, dependencyProvider) = cancellable { let tcConfig = tcConfigP.Get ctok //let foundationalTcImports, tcGlobals = TcImports.BuildFoundationalTcImports tcConfigP let frameworkDLLs, nonFrameworkReferences, knownUnresolved = TcAssemblyResolutions.SplitNonFoundationalResolutions(ctok, tcConfig) let! tcGlobals, frameworkTcImports = TcImports.BuildFrameworkTcImports (ctok, tcConfigP, frameworkDLLs, nonFrameworkReferences) - let! tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, nonFrameworkReferences, knownUnresolved) + let! tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, nonFrameworkReferences, knownUnresolved, dependencyProvider) return tcGlobals, tcImports } @@ -5066,10 +5105,12 @@ let RequireDLL (ctok, tcImports: TcImports, tcEnv, thisAssemblyName, m, file) = let ProcessMetaCommandsFromInput (nowarnF: 'state -> range * string -> 'state, - dllRequireF: 'state -> range * string -> 'state, - packageRequireF: 'state -> IDependencyManagerProvider * Directive * range * string -> 'state, + hashReferenceF: 'state -> range * string * Directive -> 'state, loadSourceF: 'state -> range * string -> unit) - (tcConfig:TcConfigBuilder, inp, pathOfMetaCommandSource, state0) = + (tcConfig:TcConfigBuilder, + inp: ParsedInput, + pathOfMetaCommandSource, + state0) = use unwindBuildPhase = PushThreadBuildPhaseUntilUnwind BuildPhase.Parse @@ -5078,50 +5119,25 @@ let ProcessMetaCommandsFromInput | ParsedInput.SigFile (_) -> false | ParsedInput.ImplFile (ParsedImplFileInput (isScript = isScript)) -> isScript - let ProcessMetaCommand state hash = - let mutable matchedm = range0 - try - let processDependencyManagerDirectives directive args m = - if not canHaveScriptMetaCommands then - errorR(HashReferenceNotAllowedInNonScript m) - - let reportError = - let report errorType err msg = - let error = err, msg - match errorType with - | ErrorReportType.Warning -> warning(Error(error, m)) - | ErrorReportType.Error -> errorR(Error(error, m)) - ResolvingErrorReport (report) - - match args with - | [path] -> - matchedm <- m - let output = tcConfig.outputDir |> Option.defaultValue "" - let dm = tcConfig.dependencyProvider.TryFindDependencyManagerInPath(tcConfig.compilerToolPaths, output , reportError, path) - match dm with - | _, dependencyManager when not(isNull dependencyManager) -> - if tcConfig.langVersion.SupportsFeature(LanguageFeature.PackageManagement) then - packageRequireF state (dependencyManager, directive, m, path) - else - errorR(Error(FSComp.SR.packageManagementRequiresVFive(), m)) - state - - | _, _ when directive = Directive.Include -> - errorR(Error(FSComp.SR.poundiNotSupportedByRegisteredDependencyManagers(), m)) - state + let ProcessDependencyManagerDirective directive args m state = + if not canHaveScriptMetaCommands then + errorR(HashReferenceNotAllowedInNonScript m) - // #r "Assembly" - | path, _ -> - let p = - if String.IsNullOrWhiteSpace(path) then "" - else path + match args with + | [path] -> + let p = + if String.IsNullOrWhiteSpace(path) then "" + else path - dllRequireF state (m, p) + hashReferenceF state (m, p, directive) - | _ -> - errorR(Error(FSComp.SR.buildInvalidHashrDirective(), m)) - state + | _ -> + errorR(Error(FSComp.SR.buildInvalidHashrDirective(), m)) + state + let ProcessMetaCommand state hash = + let mutable matchedm = range0 + try match hash with | ParsedHashDirective("I", args, m) -> if not canHaveScriptMetaCommands then @@ -5138,10 +5154,12 @@ let ProcessMetaCommandsFromInput List.fold (fun state d -> nowarnF state (m,d)) state numbers | ParsedHashDirective(("reference" | "r"), args, m) -> - processDependencyManagerDirectives Directive.Resolution args m + matchedm<-m + ProcessDependencyManagerDirective Directive.Resolution args m state | ParsedHashDirective(("i"), args, m) -> - processDependencyManagerDirectives Directive.Include args m + matchedm<-m + ProcessDependencyManagerDirective Directive.Include args m state | ParsedHashDirective("load", args, m) -> if not canHaveScriptMetaCommands then @@ -5217,20 +5235,22 @@ let ApplyNoWarnsToTcConfig (tcConfig: TcConfig, inp: ParsedInput, pathOfMetaComm // Clone let tcConfigB = tcConfig.CloneOfOriginalBuilder let addNoWarn = fun () (m,s) -> tcConfigB.TurnWarningOff(m, s) - let addReferencedAssemblyByPath = fun () (_m,_s) -> () - let addDependencyManagerText = fun () (_prefix, _lt, _m, _s) -> () - let addLoadedSource = fun () (_m,_s) -> () - ProcessMetaCommandsFromInput (addNoWarn, addReferencedAssemblyByPath, addDependencyManagerText, addLoadedSource) (tcConfigB, inp, pathOfMetaCommandSource, ()) + let addReference = fun () (_m, _s, _) -> () + let addLoadedSource = fun () (_m, _s) -> () + ProcessMetaCommandsFromInput + (addNoWarn, addReference, addLoadedSource) + (tcConfigB, inp, pathOfMetaCommandSource, ()) TcConfig.Create(tcConfigB, validate=false) -let ApplyMetaCommandsFromInputToTcConfig (tcConfig: TcConfig, inp: ParsedInput, pathOfMetaCommandSource) = +let ApplyMetaCommandsFromInputToTcConfig (tcConfig: TcConfig, inp: ParsedInput, pathOfMetaCommandSource, dependencyProvider) = // Clone let tcConfigB = tcConfig.CloneOfOriginalBuilder let getWarningNumber = fun () _ -> () - let addReferencedAssemblyByPath = fun () (m,s) -> tcConfigB.AddReferencedAssemblyByPath(m,s) - let addDependencyManagerText = fun () (packageManager, lt, m,s) -> tcConfigB.AddDependencyManagerText(packageManager, lt, m, s) + let addReferenceDirective = fun () (m, path, directive) -> tcConfigB.AddReferenceDirective(dependencyProvider, m, path, directive) let addLoadedSource = fun () (m,s) -> tcConfigB.AddLoadedSource(m,s,pathOfMetaCommandSource) - ProcessMetaCommandsFromInput (getWarningNumber, addReferencedAssemblyByPath, addDependencyManagerText, addLoadedSource) (tcConfigB, inp, pathOfMetaCommandSource, ()) + ProcessMetaCommandsFromInput + (getWarningNumber, addReferenceDirective, addLoadedSource) + (tcConfigB, inp, pathOfMetaCommandSource, ()) TcConfig.Create(tcConfigB, validate=false) //---------------------------------------------------------------------------- @@ -5334,8 +5354,8 @@ module ScriptPreprocessClosure = let tcConfigB = TcConfigBuilder.CreateNew (legacyReferenceResolver, defaultFSharpBinariesDir, reduceMemoryUsage, projectDir, - isInteractive, isInvalidationSupported, defaultCopyFSharpCore=CopyFSharpCoreFlag.No, - tryGetMetadataSnapshot=tryGetMetadataSnapshot) + isInteractive, isInvalidationSupported, CopyFSharpCoreFlag.No, + tryGetMetadataSnapshot) applyCommandLineArgs tcConfigB @@ -5372,16 +5392,16 @@ module ScriptPreprocessClosure = [] let ApplyMetaCommandsFromInputToTcConfigAndGatherNoWarn - (tcConfig: TcConfig, inp: ParsedInput, pathOfMetaCommandSource) = + (tcConfig: TcConfig, inp: ParsedInput, + pathOfMetaCommandSource, dependencyProvider) = let tcConfigB = tcConfig.CloneOfOriginalBuilder let mutable nowarns = [] let getWarningNumber = fun () (m, s) -> nowarns <- (s, m) :: nowarns - let addReferencedAssemblyByPath = fun () (m, s) -> tcConfigB.AddReferencedAssemblyByPath(m, s) - let addDependencyManagerText = fun () (packageManagerPrefix, lt, m, s) -> tcConfigB.AddDependencyManagerText(packageManagerPrefix, lt, m, s) + let addReferenceDirective = fun () (m, s, directive) -> tcConfigB.AddReferenceDirective(dependencyProvider, m, s, directive) let addLoadedSource = fun () (m, s) -> tcConfigB.AddLoadedSource(m, s, pathOfMetaCommandSource) try - ProcessMetaCommandsFromInput (getWarningNumber, addReferencedAssemblyByPath, addDependencyManagerText, addLoadedSource) (tcConfigB, inp, pathOfMetaCommandSource, ()) + ProcessMetaCommandsFromInput (getWarningNumber, addReferenceDirective, addLoadedSource) (tcConfigB, inp, pathOfMetaCommandSource, ()) with ReportedError _ -> // Recover by using whatever did end up in the tcConfig () @@ -5393,7 +5413,10 @@ module ScriptPreprocessClosure = let tcConfigB = tcConfig.CloneOfOriginalBuilder TcConfig.Create(tcConfigB, validate=false), nowarns - let FindClosureFiles(mainFile, _m, closureSources, origTcConfig:TcConfig, codeContext, lexResourceManager: Lexhelp.LexResourceManager) = + let FindClosureFiles + (mainFile, _m, closureSources, origTcConfig:TcConfig, + codeContext, lexResourceManager: Lexhelp.LexResourceManager, dependencyProvider: DependencyProvider) = + let mutable tcConfig = origTcConfig let observedSources = Observed() @@ -5408,20 +5431,19 @@ module ScriptPreprocessClosure = | [] -> () | { Directive=_; LineStatus=_; Line=_; Range=m } :: _ -> let reportError = - let report errorType err msg = + ResolvingErrorReport (fun errorType err msg -> let error = err, msg match errorType with | ErrorReportType.Warning -> warning(Error(error, m)) - | ErrorReportType.Error -> errorR(Error(error, m)) - ResolvingErrorReport (report) + | ErrorReportType.Error -> errorR(Error(error, m))) match origTcConfig.packageManagerLines |> Map.tryFind packageManagerKey with | Some oldDependencyManagerLines when oldDependencyManagerLines = packageManagerLines -> () | _ -> let outputDir = tcConfig.outputDir |> Option.defaultValue "" - match tcConfig.dependencyProvider.TryFindDependencyManagerByKey(tcConfig.compilerToolPaths, outputDir, reportError, packageManagerKey) with + match dependencyProvider.TryFindDependencyManagerByKey(tcConfig.compilerToolPaths, outputDir, reportError, packageManagerKey) with | null -> - errorR(Error(tcConfig.dependencyProvider.CreatePackageManagerUnknownError(tcConfig.compilerToolPaths, outputDir, packageManagerKey, reportError), m)) + errorR(Error(dependencyProvider.CreatePackageManagerUnknownError(tcConfig.compilerToolPaths, outputDir, packageManagerKey, reportError), m)) | dependencyManager -> let directive d = @@ -5430,7 +5452,7 @@ module ScriptPreprocessClosure = | Directive.Include -> "i" let packageManagerTextLines = packageManagerLines |> List.map(fun l -> directive l.Directive, l.Line) - let result = tcConfig.dependencyProvider.Resolve(dependencyManager, ".fsx", packageManagerTextLines, reportError, executionTfm, executionRid, tcConfig.implicitIncludeDir, mainFile, scriptName) + let result = dependencyProvider.Resolve(dependencyManager, ".fsx", packageManagerTextLines, reportError, executionTfm, executionRid, tcConfig.implicitIncludeDir, mainFile, scriptName) match result.Success with | true -> // Resolution produced no errors @@ -5472,7 +5494,7 @@ module ScriptPreprocessClosure = let pathOfMetaCommandSource = Path.GetDirectoryName filename let preSources = tcConfig.GetAvailableLoadedSources() - let tcConfigResult, noWarns = ApplyMetaCommandsFromInputToTcConfigAndGatherNoWarn (tcConfig, parsedScriptAst, pathOfMetaCommandSource) + let tcConfigResult, noWarns = ApplyMetaCommandsFromInputToTcConfigAndGatherNoWarn (tcConfig, parsedScriptAst, pathOfMetaCommandSource, dependencyProvider) tcConfig <- tcConfigResult // We accumulate the tcConfig in order to collect assembly references yield! resolveDependencyManagerSources filename @@ -5582,7 +5604,7 @@ module ScriptPreprocessClosure = useSimpleResolution, useFsiAuxLib, useSdkRefs, lexResourceManager: Lexhelp.LexResourceManager, applyCommandLineArgs, assumeDotNetFramework, - tryGetMetadataSnapshot, reduceMemoryUsage) = + tryGetMetadataSnapshot, reduceMemoryUsage, dependencyProvider) = // Resolve the basic references such as FSharp.Core.dll first, before processing any #I directives in the script // @@ -5606,15 +5628,18 @@ module ScriptPreprocessClosure = tryGetMetadataSnapshot, reduceMemoryUsage) let closureSources = [ClosureSource(filename, range0, sourceText, true)] - let closureFiles, tcConfig = FindClosureFiles(filename, range0, closureSources, tcConfig, codeContext, lexResourceManager) + let closureFiles, tcConfig = FindClosureFiles(filename, range0, closureSources, tcConfig, codeContext, lexResourceManager, dependencyProvider) GetLoadClosure(ctok, filename, closureFiles, tcConfig, codeContext) /// Given source filename, find the full load closure /// Used from fsi.fs and fsc.fs, for #load and command line - let GetFullClosureOfScriptFiles(ctok, tcConfig:TcConfig, files:(string*range) list,codeContext,lexResourceManager: Lexhelp.LexResourceManager) = + let GetFullClosureOfScriptFiles + (ctok, tcConfig:TcConfig, files:(string*range) list, codeContext, + lexResourceManager: Lexhelp.LexResourceManager, dependencyProvider) = + let mainFile, mainFileRange = List.last files let closureSources = files |> List.collect (fun (filename, m) -> ClosureSourceOfFilename(filename, m,tcConfig.inputCodePage,true)) - let closureFiles,tcConfig = FindClosureFiles(mainFile, mainFileRange, closureSources, tcConfig, codeContext, lexResourceManager) + let closureFiles,tcConfig = FindClosureFiles(mainFile, mainFileRange, closureSources, tcConfig, codeContext, lexResourceManager, dependencyProvider) GetLoadClosure(ctok, mainFile, closureFiles, tcConfig, codeContext) type LoadClosure with @@ -5627,20 +5652,22 @@ type LoadClosure with (ctok, legacyReferenceResolver, defaultFSharpBinariesDir, filename: string, sourceText: ISourceText, codeContext, useSimpleResolution: bool, useFsiAuxLib, useSdkRefs, lexResourceManager: Lexhelp.LexResourceManager, - applyCommandLineArgs, assumeDotNetFramework, tryGetMetadataSnapshot, reduceMemoryUsage) = + applyCommandLineArgs, assumeDotNetFramework, tryGetMetadataSnapshot, + reduceMemoryUsage, dependencyProvider) = use unwindBuildPhase = PushThreadBuildPhaseUntilUnwind BuildPhase.Parse ScriptPreprocessClosure.GetFullClosureOfScriptText (ctok, legacyReferenceResolver, defaultFSharpBinariesDir, filename, sourceText, codeContext, useSimpleResolution, useFsiAuxLib, useSdkRefs, lexResourceManager, - applyCommandLineArgs, assumeDotNetFramework, tryGetMetadataSnapshot, reduceMemoryUsage) + applyCommandLineArgs, assumeDotNetFramework, tryGetMetadataSnapshot, reduceMemoryUsage, dependencyProvider) /// Analyze a set of script files and find the closure of their references. static member ComputeClosureOfScriptFiles (ctok, tcConfig: TcConfig, files:(string*range) list, codeContext, - lexResourceManager: Lexhelp.LexResourceManager) = + lexResourceManager: Lexhelp.LexResourceManager, dependencyProvider) = + use unwindBuildPhase = PushThreadBuildPhaseUntilUnwind BuildPhase.Parse - ScriptPreprocessClosure.GetFullClosureOfScriptFiles (ctok, tcConfig, files, codeContext, lexResourceManager) + ScriptPreprocessClosure.GetFullClosureOfScriptFiles (ctok, tcConfig, files, codeContext, lexResourceManager, dependencyProvider) //---------------------------------------------------------------------------- // Initial type checking environment diff --git a/src/fsharp/CompileOps.fsi b/src/fsharp/CompileOps.fsi index ebedf48153d..9725f135ac6 100644 --- a/src/fsharp/CompileOps.fsi +++ b/src/fsharp/CompileOps.fsi @@ -413,8 +413,6 @@ type TcConfigBuilder = mutable pathMap : PathMap mutable langVersion : LanguageVersion - - mutable dependencyProvider: DependencyProvider } static member Initial: TcConfigBuilder @@ -443,6 +441,9 @@ type TcConfigBuilder = static member SplitCommandLineResourceInfo: string -> string * string * ILResourceAccess + // Directories to start probing in for native DLLs for FSI dynamic loading + member GetNativeProbingRoots: unit -> seq + [] // Immutable TcConfig type TcConfig = @@ -559,8 +560,8 @@ type TcConfig = member isInteractive: bool member isInvalidationSupported: bool - member ComputeLightSyntaxInitialStatus: string -> bool + member GetTargetFrameworkDirectories: unit -> string list /// Get the loaded sources that exist and issue a warning for the ones that don't @@ -575,8 +576,11 @@ type TcConfig = member MakePathAbsolute: string -> string member copyFSharpCore: CopyFSharpCoreFlag + member shadowCopyReferences: bool + member useSdkRefs: bool + member langVersion: LanguageVersion static member Create: TcConfigBuilder * validate: bool -> TcConfig @@ -640,18 +644,28 @@ type TcImports = interface System.IDisposable //new: TcImports option -> TcImports member DllTable: NameMap with get + member GetImportedAssemblies: unit -> ImportedAssembly list + member GetCcusInDeclOrder: unit -> CcuThunk list + /// This excludes any framework imports (which may be shared between multiple builds) member GetCcusExcludingBase: unit -> CcuThunk list + member FindDllInfo: CompilationThreadToken * range * string -> ImportedBinary + member TryFindDllInfo: CompilationThreadToken * range * string * lookupOnly: bool -> option + member FindCcuFromAssemblyRef: CompilationThreadToken * range * ILAssemblyRef -> CcuResolutionResult + #if !NO_EXTENSIONTYPING member ProviderGeneratedTypeRoots: ProviderGeneratedType list #endif + member GetImportMap: unit -> Import.ImportMap + member DependencyProvider: DependencyProvider + /// Try to resolve a referenced assembly based on TcConfig settings. member TryResolveAssemblyReference: CompilationThreadToken * AssemblyReference * ResolveAssemblyReferenceMode -> OperationResult @@ -671,13 +685,33 @@ type TcImports = #endif /// Report unresolved references that also weren't consumed by any type providers. member ReportUnresolvedAssemblyReferences: UnresolvedAssemblyReference list -> unit + member SystemRuntimeContainsType: string -> bool member internal Base: TcImports option - static member BuildFrameworkTcImports : CompilationThreadToken * TcConfigProvider * AssemblyResolution list * AssemblyResolution list -> Cancellable - static member BuildNonFrameworkTcImports : CompilationThreadToken * TcConfigProvider * TcGlobals * TcImports * AssemblyResolution list * UnresolvedAssemblyReference list -> Cancellable - static member BuildTcImports : CompilationThreadToken * TcConfigProvider -> Cancellable + static member BuildFrameworkTcImports: + CompilationThreadToken * + TcConfigProvider * + AssemblyResolution list * + AssemblyResolution list + -> Cancellable + + static member BuildNonFrameworkTcImports: + CompilationThreadToken * + TcConfigProvider * + TcGlobals * + TcImports * + AssemblyResolution list * + UnresolvedAssemblyReference list * + DependencyProvider + -> Cancellable + + static member BuildTcImports: + CompilationThreadToken * + TcConfigProvider * + DependencyProvider + -> Cancellable //---------------------------------------------------------------------------- // Special resources in DLLs @@ -703,24 +737,22 @@ val WriteOptimizationData: TcGlobals * filename: string * inMem: bool * CcuThunk // #r and other directives //-------------------------------------------------------------------------- -//---------------------------------------------------------------------------- -// #r and other directives -//-------------------------------------------------------------------------- - /// Process #r in F# Interactive. /// Adds the reference to the tcImports and add the ccu to the type checking environment. val RequireDLL: CompilationThreadToken * TcImports * TcEnv * thisAssemblyName: string * referenceRange: range * file: string -> TcEnv * (ImportedBinary list * ImportedAssembly list) -/// Processing # commands +/// A general routine to process hash directives val ProcessMetaCommandsFromInput : - (('T -> range * string -> 'T) * ('T -> range * string -> 'T) * ('T -> IDependencyManagerProvider * Directive * range * string -> 'T) * ('T -> range * string -> unit)) - -> TcConfigBuilder * ParsedInput * string * 'T - -> 'T + (('T -> range * string -> 'T) * + ('T -> range * string * Directive -> 'T) * + ('T -> range * string -> unit)) + -> TcConfigBuilder * ParsedInput * string * 'T + -> 'T -/// Process all the #r, #I etc. in an input -val ApplyMetaCommandsFromInputToTcConfig: TcConfig * ParsedInput * string -> TcConfig +/// Process all the #r, #I etc. in an input. For non-scripts report warnings about ignored directives. +val ApplyMetaCommandsFromInputToTcConfig: TcConfig * ParsedInput * string * DependencyProvider -> TcConfig -/// Process the #nowarn in an input +/// Process the #nowarn in an input and integrate them into the TcConfig val ApplyNoWarnsToTcConfig: TcConfig * ParsedInput * string -> TcConfig //---------------------------------------------------------------------------- @@ -853,8 +885,31 @@ type LoadClosure = // /// A temporary TcConfig is created along the way, is why this routine takes so many arguments. We want to be sure to use exactly the /// same arguments as the rest of the application. - static member ComputeClosureOfScriptText: CompilationThreadToken * legacyReferenceResolver: ReferenceResolver.Resolver * defaultFSharpBinariesDir: string * filename: string * sourceText: ISourceText * implicitDefines:CodeContext * useSimpleResolution: bool * useFsiAuxLib: bool * useSdkRefs: bool * lexResourceManager: Lexhelp.LexResourceManager * applyCompilerOptions: (TcConfigBuilder -> unit) * assumeDotNetFramework: bool * tryGetMetadataSnapshot: ILReaderTryGetMetadataSnapshot * reduceMemoryUsage: ReduceMemoryFlag -> LoadClosure + static member ComputeClosureOfScriptText: + CompilationThreadToken * + legacyReferenceResolver: ReferenceResolver.Resolver * + defaultFSharpBinariesDir: string * + filename: string * + sourceText: ISourceText * + implicitDefines:CodeContext * + useSimpleResolution: bool * + useFsiAuxLib: bool * + useSdkRefs: bool * + lexResourceManager: Lexhelp.LexResourceManager * + applyCompilerOptions: (TcConfigBuilder -> unit) * + assumeDotNetFramework: bool * + tryGetMetadataSnapshot: ILReaderTryGetMetadataSnapshot * + reduceMemoryUsage: ReduceMemoryFlag * + dependencyProvider: DependencyProvider + -> LoadClosure /// Analyze a set of script files and find the closure of their references. The resulting references are then added to the given TcConfig. /// Used from fsi.fs and fsc.fs, for #load and command line. - static member ComputeClosureOfScriptFiles: CompilationThreadToken * tcConfig:TcConfig * (string * range) list * implicitDefines:CodeContext * lexResourceManager: Lexhelp.LexResourceManager -> LoadClosure + static member ComputeClosureOfScriptFiles: + CompilationThreadToken * + tcConfig:TcConfig * + (string * range) list * + implicitDefines:CodeContext * + lexResourceManager: Lexhelp.LexResourceManager * + dependencyProvider: DependencyProvider + -> LoadClosure diff --git a/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs b/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs index c3c7046ef29..b89cd09bad7 100644 --- a/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs +++ b/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs @@ -68,19 +68,14 @@ module ReflectionHelper = e.InnerException | _ -> e -open ReflectionHelper -open RidHelpers - /// Indicate the type of error to report [] type ErrorReportType = | Warning | Error - type ResolvingErrorReport = delegate of ErrorReportType * int * string -> unit - (* Shape of Dependency Manager contract, resolved using reflection *) /// The results of ResolveDependencies type IResolveDependenciesResult = @@ -268,9 +263,17 @@ type ReflectionDependencyManagerProvider(theType: Type, /// Class is IDisposable type DependencyProvider (assemblyProbingPaths: AssemblyResolutionProbe, nativeProbingRoots: NativeResolutionProbe) = - let dllResolveHandler = new NativeDllResolveHandler(nativeProbingRoots) :> IDisposable + // Note: creating a NativeDllResolveHandler currently installs process-wide handlers + let dllResolveHandler = + match assemblyProbingPaths with + | null -> { new IDisposable with member _.Dispose() = () } + | _ -> new NativeDllResolveHandler(nativeProbingRoots) :> IDisposable - let assemblyResolveHandler = new AssemblyResolveHandler(assemblyProbingPaths) :> IDisposable + // Note: creating a AssemblyResolveHandler currently installs process-wide handlers + let assemblyResolveHandler = + match assemblyProbingPaths with + | null -> { new IDisposable with member _.Dispose() = () } + | _ -> new AssemblyResolveHandler(assemblyProbingPaths) :> IDisposable // Resolution Path = Location of FSharp.Compiler.Private.dll let assemblySearchPaths = lazy ( @@ -329,10 +332,6 @@ type DependencyProvider (assemblyProbingPaths: AssemblyResolutionProbe, nativePr let cache = ConcurrentDictionary<_,IResolveDependenciesResult>(HashIdentity.Structural) - /// Returns a formatted error message for the host to presentconstruct with just nativeProbing handler - new (nativeProbingRoots: NativeResolutionProbe) = - new DependencyProvider(Unchecked.defaultof, nativeProbingRoots) - /// Returns a formatted help messages for registered dependencymanagers for the host to present member _.GetRegisteredDependencyManagerHelpText (compilerTools, outputDir, errorReport) = [| let managers = RegisteredDependencyManagers compilerTools (Option.ofString outputDir) errorReport diff --git a/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fsi b/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fsi index 2f16b59fd99..a47917c05fb 100644 --- a/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fsi +++ b/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fsi @@ -56,16 +56,18 @@ type ErrorReportType = type ResolvingErrorReport = delegate of ErrorReportType * int * string -> unit /// Provides DependencyManagement functions. -/// Class is IDisposable +/// +/// The class incrementally collects IDependencyManagerProvider, indexed by key, and +/// queries them. These are found and instantiated with respect to the compilerTools and outputDir +/// provided each time the TryFindDependencyManagerByKey and TryFindDependencyManagerInPath are +/// executed, which are assumed to be invariant over the lifetime of the DependencyProvider. type DependencyProvider = interface System.IDisposable - /// Construct a new DependencyProvider + /// Construct a new DependencyProvider. assemblyProbingPaths and nativeProbingRoots may be null + /// to indicate no dynamic resolution handlers should be installed. new: assemblyProbingPaths: AssemblyResolutionProbe * nativeProbingRoots: NativeResolutionProbe -> DependencyProvider - /// Construct a new DependencyProvider - new: nativeProbingRoots: NativeResolutionProbe -> DependencyProvider - /// Returns a formatted help messages for registered dependencymanagers for the host to present member GetRegisteredDependencyManagerHelpText: string seq * string * ResolvingErrorReport -> string[] diff --git a/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fs b/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fs index 60b52982cc5..6a4477631c0 100644 --- a/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fs +++ b/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fs @@ -101,8 +101,9 @@ type NativeDllResolveHandlerCoreClr (_nativeProbingRoots: NativeResolutionProbe) let probe = match _nativeProbingRoots with | null -> None - | _ -> _nativeProbingRoots.Invoke() - |> Seq.tryPick(fun root -> + | _ -> + _nativeProbingRoots.Invoke() + |> Seq.tryPick(fun root -> probingFileNames name |> Seq.tryPick(fun name -> let path = Path.Combine(root, name) if File.Exists(path) then diff --git a/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fsi b/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fsi index c98b5f142e7..d1aa22fe49c 100644 --- a/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fsi +++ b/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fsi @@ -18,7 +18,7 @@ type NativeResolutionProbe = delegate of Unit -> seq // Cut down AssemblyLoadContext, for loading native libraries type NativeDllResolveHandler = - /// Construct a new DependencyProvider + /// Construct a new NativeDllResolveHandler new: nativeProbingRoots: NativeResolutionProbe -> NativeDllResolveHandler interface IDisposable diff --git a/src/fsharp/fsc.fs b/src/fsharp/fsc.fs index 4892c4a07fb..26f375ce05e 100644 --- a/src/fsharp/fsc.fs +++ b/src/fsharp/fsc.fs @@ -50,6 +50,7 @@ open FSharp.Compiler.TypedTreeOps open FSharp.Compiler.TcGlobals open FSharp.Compiler.TypeChecker open FSharp.Compiler.XmlDoc +open Microsoft.DotNet.DependencyManager open FSharp.Compiler.AbstractIL.Internal.StrongNameSign @@ -202,7 +203,7 @@ let TypeCheck (ctok, tcConfig, tcImports, tcGlobals, errorLogger: ErrorLogger, a exiter.Exit 1 /// Check for .fsx and, if present, compute the load closure for of #loaded files. -let AdjustForScriptCompile(ctok, tcConfigB: TcConfigBuilder, commandLineSourceFiles, lexResourceManager) = +let AdjustForScriptCompile(ctok, tcConfigB: TcConfigBuilder, commandLineSourceFiles, lexResourceManager, dependencyProvider) = let combineFilePath file = try @@ -227,7 +228,8 @@ let AdjustForScriptCompile(ctok, tcConfigB: TcConfigBuilder, commandLineSourceFi if IsScript filename then let closure = LoadClosure.ComputeClosureOfScriptFiles - (ctok, tcConfig, [filename, rangeStartup], CodeContext.Compilation, lexResourceManager=lexResourceManager) + (ctok, tcConfig, [filename, rangeStartup], CodeContext.Compilation, + lexResourceManager, dependencyProvider) // Record the references from the analysis of the script. The full resolutions are recorded as the corresponding #I paths used to resolve them // are local to the scripts and not added to the tcConfigB (they are added to localized clones of the tcConfigB). @@ -1763,6 +1765,8 @@ let main0(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, // Share intern'd strings across all lexing/parsing let lexResourceManager = new Lexhelp.LexResourceManager() + let dependencyProvider = new DependencyProvider(null, null) + // process command line, flags and collect filenames let sourceFiles = @@ -1771,7 +1775,7 @@ let main0(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, try let sourceFiles = let files = ProcessCommandLineFlags (tcConfigB, setProcessThreadLocals, lcidFromCodePage, argv) - AdjustForScriptCompile(ctok, tcConfigB, files, lexResourceManager) + AdjustForScriptCompile(ctok, tcConfigB, files, lexResourceManager, dependencyProvider) sourceFiles with e -> @@ -1855,12 +1859,12 @@ let main0(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, if tcConfig.printAst then inputs |> List.iter (fun (input, _filename) -> printf "AST:\n"; printfn "%+A" input; printf "\n") - let tcConfig = (tcConfig, inputs) ||> List.fold (fun z (x, m) -> ApplyMetaCommandsFromInputToTcConfig(z, x, m)) + let tcConfig = (tcConfig, inputs) ||> List.fold (fun z (x, m) -> ApplyMetaCommandsFromInputToTcConfig(z, x, m, dependencyProvider)) let tcConfigP = TcConfigProvider.Constant tcConfig // Import other assemblies ReportTime tcConfig "Import non-system references" - let tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, otherRes, knownUnresolved) |> Cancellable.runWithoutCancellation + let tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, otherRes, knownUnresolved, dependencyProvider) |> Cancellable.runWithoutCancellation // register tcImports to be disposed in future disposables.Register tcImports @@ -1988,6 +1992,7 @@ let main0OfAst (ctok, legacyReferenceResolver, reduceMemoryUsage, assemblyName, delayForFlagsLogger.ForwardDelayedDiagnostics tcConfigB exiter.Exit 1 + let dependencyProvider = new DependencyProvider(null, null) let errorLogger = errorLoggerProvider.CreateErrorLoggerUpToMaxErrors(tcConfigB, exiter) // Install the global error logger and never remove it. This logger does have all command-line flags considered. @@ -2010,12 +2015,12 @@ let main0OfAst (ctok, legacyReferenceResolver, reduceMemoryUsage, assemblyName, use unwindParsePhase = PushThreadBuildPhaseUntilUnwind (BuildPhase.Parse) let meta = Directory.GetCurrentDirectory() - let tcConfig = (tcConfig,inputs) ||> List.fold (fun tcc inp -> ApplyMetaCommandsFromInputToTcConfig (tcc, inp,meta)) + let tcConfig = (tcConfig,inputs) ||> List.fold (fun tcc inp -> ApplyMetaCommandsFromInputToTcConfig (tcc, inp, meta, dependencyProvider)) let tcConfigP = TcConfigProvider.Constant tcConfig // Import other assemblies ReportTime tcConfig "Import non-system references" - let tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, otherRes, knownUnresolved) |> Cancellable.runWithoutCancellation + let tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, otherRes, knownUnresolved, dependencyProvider) |> Cancellable.runWithoutCancellation // register tcImports to be disposed in future disposables.Register tcImports diff --git a/src/fsharp/fsi/fsi.fs b/src/fsharp/fsi/fsi.fs index 8e714f71dd1..f16c1c33b0c 100644 --- a/src/fsharp/fsi/fsi.fs +++ b/src/fsharp/fsi/fsi.fs @@ -601,7 +601,11 @@ let internal directoryName (s:string) = //---------------------------------------------------------------------------- /// Process the command line options -type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, argv: string[], tcConfigB, fsiConsoleOutput: FsiConsoleOutput) = +type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, + argv: string[], + tcConfigB, + fsiConsoleOutput: FsiConsoleOutput) = + let mutable enableConsoleKeyProcessing = // Mono on Win32 doesn't implement correct console processing not (runningOnMono && System.Environment.OSVersion.Platform = System.PlatformID.Win32NT) @@ -757,6 +761,8 @@ type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, argv: s stopProcessingRecovery e range0; failwithf "Error creating evaluation session: %A" e inputFilesAcc + let dependencyProvider = new DependencyProvider(null, NativeResolutionProbe(tcConfigB.GetNativeProbingRoots)) + do if tcConfigB.utf8output then let prev = Console.OutputEncoding @@ -797,7 +803,7 @@ type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, argv: s fsiConsoleOutput.uprintfn """ #help;; // %s""" (FSIstrings.SR.fsiIntroTextHashhelpInfo()) if tcConfigB.langVersion.SupportsFeature(LanguageFeature.PackageManagement) then - for msg in tcConfigB.dependencyProvider.GetRegisteredDependencyManagerHelpText(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m) do + for msg in dependencyProvider.GetRegisteredDependencyManagerHelpText(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m) do fsiConsoleOutput.uprintfn "%s" msg fsiConsoleOutput.uprintfn """ #quit;; // %s""" (FSIstrings.SR.fsiIntroTextHashquitInfo()) (* last thing you want to do, last thing in the list - stands out more *) @@ -824,6 +830,8 @@ type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, argv: s member __.SourceFiles = sourceFiles member __.Gui = gui + member _.DependencyProvider = dependencyProvider + /// Set the current ui culture for the current thread. let internal SetCurrentUICultureForThread (lcid : int option) = let culture = Thread.CurrentThread.CurrentUICulture @@ -1461,9 +1469,9 @@ type internal FsiDynamicCompiler | { Directive=_; LineStatus=_; Line=_; Range=m } :: _ -> let outputDir = tcConfigB.outputDir |> Option.defaultValue "" - match tcConfigB.dependencyProvider.TryFindDependencyManagerByKey(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, packageManagerKey) with + match fsiOptions.DependencyProvider.TryFindDependencyManagerByKey(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, packageManagerKey) with | null -> - errorR(Error(tcConfigB.dependencyProvider.CreatePackageManagerUnknownError(tcConfigB.compilerToolPaths, outputDir, packageManagerKey, reportError m), m)) + errorR(Error(fsiOptions.DependencyProvider.CreatePackageManagerUnknownError(tcConfigB.compilerToolPaths, outputDir, packageManagerKey, reportError m), m)) istate | dependencyManager -> let directive d = @@ -1475,7 +1483,7 @@ type internal FsiDynamicCompiler packageManagerLines |> List.map (fun line -> directive line.Directive, line.Line) try - let result = tcConfigB.dependencyProvider.Resolve(dependencyManager, ".fsx", packageManagerTextLines, reportError m, executionTfm, executionRid, tcConfigB.implicitIncludeDir, "stdin.fsx", "stdin.fsx") + let result = fsiOptions.DependencyProvider.Resolve(dependencyManager, ".fsx", packageManagerTextLines, reportError m, executionTfm, executionRid, tcConfigB.implicitIncludeDir, "stdin.fsx", "stdin.fsx") match result.Success with | false -> tcConfigB.packageManagerLines <- PackageManagerLine.RemoveUnprocessedLines packageManagerKey tcConfigB.packageManagerLines @@ -1502,8 +1510,27 @@ type internal FsiDynamicCompiler (fun () -> ProcessMetaCommandsFromInput ((fun st (m,nm) -> tcConfigB.TurnWarningOff(m,nm); st), - (fun st (m,nm) -> snd (fsiDynamicCompiler.EvalRequireReference (ctok, st, m, nm))), - (fun st (packageManagerPrefix, lt, m, nm) -> fsiDynamicCompiler.EvalDependencyManagerTextFragment (packageManagerPrefix, lt, m, nm); st), + (fun st (m, path, directive) -> + + let dm = tcImports.DependencyProvider.TryFindDependencyManagerInPath(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, path) + + match dm with + | _, dependencyManager when not(isNull dependencyManager) -> + if tcConfigB.langVersion.SupportsFeature(LanguageFeature.PackageManagement) then + fsiDynamicCompiler.EvalDependencyManagerTextFragment (dependencyManager, directive, m, path) + st + else + errorR(Error(FSComp.SR.packageManagementRequiresVFive(), m)) + st + + | _, _ when directive = Directive.Include -> + errorR(Error(FSComp.SR.poundiNotSupportedByRegisteredDependencyManagers(), m)) + st + + // #r "Assembly" + | path, _ -> + snd (fsiDynamicCompiler.EvalRequireReference (ctok, st, m, path)) + ), (fun _ _ -> ())) (tcConfigB, inp, Path.GetDirectoryName sourceFile, istate)) @@ -1517,7 +1544,11 @@ type internal FsiDynamicCompiler // Close the #load graph on each file and gather the inputs from the scripts. let tcConfig = TcConfig.Create(tcConfigB,validate=false) - let closure = LoadClosure.ComputeClosureOfScriptFiles(ctok, tcConfig, sourceFiles, CodeContext.CompilationAndEvaluation, lexResourceManager=lexResourceManager) + + let closure = + LoadClosure.ComputeClosureOfScriptFiles(ctok, tcConfig, + sourceFiles, CodeContext.CompilationAndEvaluation, + lexResourceManager, fsiOptions.DependencyProvider) // Intent "[Loading %s]\n" (String.concat "\n and " sourceFiles) fsiConsoleOutput.uprintf "[%s " (FSIstrings.SR.fsiLoadingFilesPrefixText()) @@ -2106,7 +2137,7 @@ type internal FsiInteractionProcessor /// Execute a single parsed interaction. Called on the GUI/execute/main thread. let ExecInteraction (ctok, tcConfig:TcConfig, istate, action:ParsedFsiInteraction, errorLogger: ErrorLogger) = let packageManagerDirective directive path m = - let dm = tcConfigB.dependencyProvider.TryFindDependencyManagerInPath(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, path) + let dm = fsiOptions.DependencyProvider.TryFindDependencyManagerInPath(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, path) match dm with | null, null -> // error already reported @@ -2749,7 +2780,8 @@ type FsiEvaluationSession (fsi: FsiEvaluationSessionHostConfig, argv:string[], i do updateBannerText() // setting the correct banner so that 'fsi -?' display the right thing - let fsiOptions = FsiCommandLineOptions(fsi, argv, tcConfigB, fsiConsoleOutput) + let fsiOptions = FsiCommandLineOptions(fsi, argv, tcConfigB, fsiConsoleOutput) + let fsiConsolePrompt = FsiConsolePrompt(fsiOptions, fsiConsoleOutput) do @@ -2791,7 +2823,7 @@ type FsiEvaluationSession (fsi: FsiEvaluationSessionHostConfig, argv:string[], i let tcImports = try - TcImports.BuildNonFrameworkTcImports(ctokStartup, tcConfigP, tcGlobals, frameworkTcImports, nonFrameworkResolutions, unresolvedReferences) |> Cancellable.runWithoutCancellation + TcImports.BuildNonFrameworkTcImports(ctokStartup, tcConfigP, tcGlobals, frameworkTcImports, nonFrameworkResolutions, unresolvedReferences, fsiOptions.DependencyProvider) |> Cancellable.runWithoutCancellation with e -> stopProcessingRecovery e range0; failwithf "Error creating evaluation session: %A" e diff --git a/src/fsharp/service/FSharpCheckerResults.fs b/src/fsharp/service/FSharpCheckerResults.fs index f3c78473b27..3fb85438d9d 100644 --- a/src/fsharp/service/FSharpCheckerResults.fs +++ b/src/fsharp/service/FSharpCheckerResults.fs @@ -1621,7 +1621,7 @@ module internal ParseAndCheckFile = | None -> // For non-scripts, check for disallow #r and #load. - ApplyMetaCommandsFromInputToTcConfig (tcConfig, parsedMainInput,Path.GetDirectoryName mainInputFileName) |> ignore + ApplyMetaCommandsFromInputToTcConfig (tcConfig, parsedMainInput, Path.GetDirectoryName mainInputFileName, tcImports.DependencyProvider) |> ignore // Type check a single file against an initial context, gleaning both errors and intellisense information. let CheckOneFile @@ -2161,8 +2161,8 @@ type FSharpCheckProjectResults type FsiInteractiveChecker(legacyReferenceResolver, reactorOps: IReactorOperations, tcConfig: TcConfig, - tcGlobals, - tcImports, + tcGlobals: TcGlobals, + tcImports: TcImports, tcState) = let keepAssemblyContents = false @@ -2192,7 +2192,9 @@ type FsiInteractiveChecker(legacyReferenceResolver, tcConfig.useSimpleResolution, tcConfig.useFsiAuxLib, tcConfig.useSdkRefs, new Lexhelp.LexResourceManager(), applyCompilerOptions, assumeDotNetFramework, - tryGetMetadataSnapshot=(fun _ -> None), reduceMemoryUsage=reduceMemoryUsage) + tryGetMetadataSnapshot=(fun _ -> None), + reduceMemoryUsage=reduceMemoryUsage, + dependencyProvider=tcImports.DependencyProvider) let! tcErrors, tcFileInfo = ParseAndCheckFile.CheckOneFile diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs index f60d85adfc1..85c4e36dcea 100755 --- a/src/fsharp/service/IncrementalBuild.fs +++ b/src/fsharp/service/IncrementalBuild.fs @@ -26,6 +26,8 @@ open FSharp.Compiler.TypeChecker open FSharp.Compiler.TypedTree open FSharp.Compiler.TypedTreeOps +open Microsoft.DotNet.DependencyManager + open Internal.Utilities.Collections [] @@ -1220,9 +1222,12 @@ type RawFSharpAssemblyDataBackedByLanguageService (tcConfig, tcGlobals, tcState: /// Manages an incremental build graph for the build of a single F# project type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInputs, nonFrameworkResolutions, unresolvedReferences, tcConfig: TcConfig, projectDirectory, outfile, - assemblyName, niceNameGen: NiceNameGenerator, lexResourceManager, - sourceFiles, loadClosureOpt: LoadClosure option, - keepAssemblyContents, keepAllBackgroundResolutions, maxTimeShareMilliseconds, keepAllBackgroundSymbolUses, enableBackgroundItemKeyStoreAndSemanticClassification) = + assemblyName, niceNameGen: NiceNameGenerator, lexResourceManager, + sourceFiles, loadClosureOpt: LoadClosure option, + keepAssemblyContents, keepAllBackgroundResolutions, + maxTimeShareMilliseconds, keepAllBackgroundSymbolUses, + enableBackgroundItemKeyStoreAndSemanticClassification, + dependencyProviderOpt: DependencyProvider option) = let tcConfigP = TcConfigProvider.Constant tcConfig let fileParsed = new Event() @@ -1259,6 +1264,13 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput for (_, f, _) in sourceFiles do yield f |] + // For scripts, the dependency provider is already available. + // For projects create a fresh one for the project. + let dependencyProvider = + match dependencyProviderOpt with + | None -> new DependencyProvider(null, null) + | Some dependencyProvider -> dependencyProvider + //---------------------------------------------------- // START OF BUILD TASK FUNCTIONS @@ -1309,7 +1321,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput let! tcImports = cancellable { try - let! tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, nonFrameworkResolutions, unresolvedReferences) + let! tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, nonFrameworkResolutions, unresolvedReferences, dependencyProvider) #if !NO_EXTENSIONTYPING tcImports.GetCcusExcludingBase() |> Seq.iter (fun ccu -> // When a CCU reports an invalidation, merge them together and just report a @@ -1383,7 +1395,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput eventually { beforeFileChecked.Trigger filename - ApplyMetaCommandsFromInputToTcConfig (tcConfig, input, Path.GetDirectoryName filename) |> ignore + ApplyMetaCommandsFromInputToTcConfig (tcConfig, input, Path.GetDirectoryName filename, tcAcc.tcImports.DependencyProvider) |> ignore let sink = TcResultsSinkImpl(tcAcc.tcGlobals) let hadParseErrors = not (Array.isEmpty parseErrors) @@ -1740,7 +1752,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput /// CreateIncrementalBuilder (for background type checking). Note that fsc.fs also /// creates an incremental builder used by the command line compiler. - static member TryCreateBackgroundBuilderForProjectOptions + static member TryCreateIncrementalBuilderForProjectOptions (ctok, legacyReferenceResolver, defaultFSharpBinariesDir, frameworkTcImportsCache: FrameworkImportsCache, loadClosureOpt: LoadClosure option, @@ -1749,7 +1761,11 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput projectReferences, projectDirectory, useScriptResolutionRules, keepAssemblyContents, keepAllBackgroundResolutions, maxTimeShareMilliseconds, - tryGetMetadataSnapshot, suggestNamesForErrors, keepAllBackgroundSymbolUses, enableBackgroundItemKeyStoreAndSemanticClassification) = + tryGetMetadataSnapshot, suggestNamesForErrors, + keepAllBackgroundSymbolUses, + enableBackgroundItemKeyStoreAndSemanticClassification, + dependencyProviderOpt) = + let useSimpleResolutionSwitch = "--simpleresolution" cancellable { @@ -1864,14 +1880,16 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput yield Choice2Of2 pr, (fun (cache: TimeStampCache) ctok -> cache.GetProjectReferenceTimeStamp (pr, ctok)) ] let builder = - new IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInputs, nonFrameworkResolutions, unresolvedReferences, - tcConfig, projectDirectory, outfile, assemblyName, niceNameGen, - resourceManager, sourceFilesNew, loadClosureOpt, - keepAssemblyContents=keepAssemblyContents, - keepAllBackgroundResolutions=keepAllBackgroundResolutions, - maxTimeShareMilliseconds=maxTimeShareMilliseconds, - keepAllBackgroundSymbolUses=keepAllBackgroundSymbolUses, - enableBackgroundItemKeyStoreAndSemanticClassification=enableBackgroundItemKeyStoreAndSemanticClassification) + new IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInputs, + nonFrameworkResolutions, unresolvedReferences, + tcConfig, projectDirectory, outfile, assemblyName, niceNameGen, + resourceManager, sourceFilesNew, loadClosureOpt, + keepAssemblyContents, + keepAllBackgroundResolutions, + maxTimeShareMilliseconds, + keepAllBackgroundSymbolUses, + enableBackgroundItemKeyStoreAndSemanticClassification, + dependencyProviderOpt) return Some builder with e -> errorRecoveryNoRange e diff --git a/src/fsharp/service/IncrementalBuild.fsi b/src/fsharp/service/IncrementalBuild.fsi index e9f945cd970..c6bfe1e1f5a 100755 --- a/src/fsharp/service/IncrementalBuild.fsi +++ b/src/fsharp/service/IncrementalBuild.fsi @@ -16,6 +16,8 @@ open FSharp.Compiler.SyntaxTree open FSharp.Compiler.TcGlobals open FSharp.Compiler.TypedTree +open Microsoft.DotNet.DependencyManager + /// Lookup the global static cache for building the FrameworkTcImports type internal FrameworkImportsCache = new : size: int -> FrameworkImportsCache @@ -178,9 +180,29 @@ type internal IncrementalBuilder = /// Await the untyped parse results for a particular slot in the vector of parse results. /// /// This may be a marginally long-running operation (parses are relatively quick, only one file needs to be parsed) - member GetParseResultsForFile : CompilationThreadToken * filename:string -> Cancellable - - static member TryCreateBackgroundBuilderForProjectOptions : CompilationThreadToken * ReferenceResolver.Resolver * defaultFSharpBinariesDir: string * FrameworkImportsCache * scriptClosureOptions:LoadClosure option * sourceFiles:string list * commandLineArgs:string list * projectReferences: IProjectReference list * projectDirectory:string * useScriptResolutionRules:bool * keepAssemblyContents: bool * keepAllBackgroundResolutions: bool * maxTimeShareMilliseconds: int64 * tryGetMetadataSnapshot: ILBinaryReader.ILReaderTryGetMetadataSnapshot * suggestNamesForErrors: bool * keepAllBackgroundSymbolUses: bool * enableBackgroundItemKeyStoreAndSemanticClassification: bool -> Cancellable + member GetParseResultsForFile: CompilationThreadToken * filename:string -> Cancellable + + /// Create the incremental builder + static member TryCreateIncrementalBuilderForProjectOptions: + CompilationThreadToken * + ReferenceResolver.Resolver * + defaultFSharpBinariesDir: string * + FrameworkImportsCache * + scriptClosureOptions:LoadClosure option * + sourceFiles:string list * + commandLineArgs:string list * + projectReferences: IProjectReference list * + projectDirectory:string * + useScriptResolutionRules:bool * + keepAssemblyContents: bool * + keepAllBackgroundResolutions: bool * + maxTimeShareMilliseconds: int64 * + tryGetMetadataSnapshot: ILBinaryReader.ILReaderTryGetMetadataSnapshot * + suggestNamesForErrors: bool * + keepAllBackgroundSymbolUses: bool * + enableBackgroundItemKeyStoreAndSemanticClassification: bool * + dependencyProvider: DependencyProvider option + -> Cancellable /// Generalized Incremental Builder. This is exposed only for unit testing purposes. module internal IncrementalBuild = diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index 246f6d7440e..99e4cc388c4 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -24,6 +24,8 @@ open FSharp.Compiler.SyntaxTree open FSharp.Compiler.TcGlobals open FSharp.Compiler.Text +open Microsoft.DotNet.DependencyManager + open Internal.Utilities open Internal.Utilities.Collections @@ -274,6 +276,14 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC let scriptClosureCacheLock = Lock() let frameworkTcImportsCache = FrameworkImportsCache(frameworkTcImportsCacheStrongSize) + // We currently share one global dependency provider for all scripts for the FSharpChecker. + // For projects, one is used per project. + // + // Sharing one for all scripts is necessary for good performance from GetProjectOptionsFromScript, + // which requires a dependency provider to process through the project options prior to working out + // if the cached incremental builder can be used for the project. + let dependencyProviderForScripts = new DependencyProvider(null, null) + /// CreateOneIncrementalBuilder (for background type checking). Note that fsc.fs also /// creates an incremental builder used by the command line compiler. let CreateOneIncrementalBuilder (ctok, options:FSharpProjectOptions, userOpName) = @@ -301,12 +311,15 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC member x.FileName = nm } ] let loadClosure = scriptClosureCacheLock.AcquireLock (fun ltok -> scriptClosureCache.TryGet (ltok, options)) + let! builderOpt, diagnostics = - IncrementalBuilder.TryCreateBackgroundBuilderForProjectOptions + IncrementalBuilder.TryCreateIncrementalBuilderForProjectOptions (ctok, legacyReferenceResolver, FSharpCheckerResultsSettings.defaultFSharpBinariesDir, frameworkTcImportsCache, loadClosure, Array.toList options.SourceFiles, Array.toList options.OtherOptions, projectReferences, options.ProjectDirectory, options.UseScriptResolutionRules, keepAssemblyContents, keepAllBackgroundResolutions, FSharpCheckerResultsSettings.maxTimeShareMilliseconds, - tryGetMetadataSnapshot, suggestNamesForErrors, keepAllBackgroundSymbolUses, enableBackgroundItemKeyStoreAndSemanticClassification) + tryGetMetadataSnapshot, suggestNamesForErrors, keepAllBackgroundSymbolUses, + enableBackgroundItemKeyStoreAndSemanticClassification, + (if options.UseScriptResolutionRules then Some dependencyProviderForScripts else None)) match builderOpt with | None -> () @@ -817,8 +830,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC FSharpCheckerResultsSettings.defaultFSharpBinariesDir, filename, sourceText, CodeContext.Editing, useSimpleResolution, useFsiAuxLib, useSdkRefs, new Lexhelp.LexResourceManager(), applyCompilerOptions, assumeDotNetFramework, - tryGetMetadataSnapshot=tryGetMetadataSnapshot, - reduceMemoryUsage=reduceMemoryUsage) + tryGetMetadataSnapshot, reduceMemoryUsage, dependencyProviderForScripts) let otherFlags = [| yield "--noframework"; yield "--warn:3"; From 1edbffb5d6badedc12d37ed777341b11883164fc Mon Sep 17 00:00:00 2001 From: Don Syme Date: Sun, 20 Sep 2020 00:15:18 +0100 Subject: [PATCH 04/12] one DependencyProvider per project --- src/fsharp/CompileOps.fs | 205 ++++++++---------- src/fsharp/CompileOps.fsi | 93 ++------ .../DependencyProvider.fs | 21 +- .../DependencyProvider.fsi | 12 +- .../NativeDllResolveHandler.fs | 5 +- .../NativeDllResolveHandler.fsi | 2 +- src/fsharp/fsc.fs | 19 +- src/fsharp/fsi/fsi.fs | 54 +---- src/fsharp/service/FSharpCheckerResults.fs | 10 +- src/fsharp/service/IncrementalBuild.fs | 48 ++-- src/fsharp/service/IncrementalBuild.fsi | 28 +-- src/fsharp/service/service.fs | 20 +- 12 files changed, 171 insertions(+), 346 deletions(-) diff --git a/src/fsharp/CompileOps.fs b/src/fsharp/CompileOps.fs index cdf760b3f23..63dba3fed83 100644 --- a/src/fsharp/CompileOps.fs +++ b/src/fsharp/CompileOps.fs @@ -2308,6 +2308,8 @@ type TcConfigBuilder = mutable pathMap: PathMap mutable langVersion: LanguageVersion + + mutable dependencyProvider: DependencyProvider } static member Initial = @@ -2447,6 +2449,7 @@ type TcConfigBuilder = noConditionalErasure = false pathMap = PathMap.empty langVersion = LanguageVersion("default") + dependencyProvider = Unchecked.defaultof } // Directories to start probing in @@ -2456,17 +2459,13 @@ type TcConfigBuilder = // 2. compilerToolPath directories // 3. reference dll's // 4. The implicit include directory - // - // NOTE: it is important this is a delayed IEnumerable sequence. It is recomputed - // each time a resolution happens and additional paths may be added as a result. - member tcConfigB.GetNativeProbingRoots () = + member private tcConfigB.nativeProbingRoots () = seq { yield! tcConfigB.includes yield! tcConfigB.compilerToolPaths yield! (tcConfigB.referencedDLLs |> Seq.map(fun ref -> Path.GetDirectoryName(ref.Text))) yield tcConfigB.implicitIncludeDir - } - |> Seq.distinct + } |> Seq.distinct static member CreateNew(legacyReferenceResolver, defaultFSharpBinariesDir, reduceMemoryUsage, implicitIncludeDir, isInteractive, isInvalidationSupported, defaultCopyFSharpCore, tryGetMetadataSnapshot) = @@ -2488,6 +2487,7 @@ type TcConfigBuilder = tryGetMetadataSnapshot = tryGetMetadataSnapshot useFsiAuxLib = isInteractive } + tcConfigBuilder.dependencyProvider <- new DependencyProvider(NativeResolutionProbe(tcConfigBuilder.nativeProbingRoots)) tcConfigBuilder member tcConfigB.ResolveSourceFile(m, nm, pathLoadedFrom) = @@ -2599,32 +2599,6 @@ type TcConfigBuilder = member tcConfigB.AddDependencyManagerText (packageManager: IDependencyManagerProvider, lt, m, path: string) = tcConfigB.packageManagerLines <- PackageManagerLine.AddLineWithKey packageManager.Key lt path m tcConfigB.packageManagerLines - member tcConfigB.AddReferenceDirective (dependencyProvider: DependencyProvider, m, path: string, directive) = - let output = tcConfigB.outputDir |> Option.defaultValue "" - - let reportError = - ResolvingErrorReport (fun errorType err msg -> - let error = err, msg - match errorType with - | ErrorReportType.Warning -> warning(Error(error, m)) - | ErrorReportType.Error -> errorR(Error(error, m))) - - let dm = dependencyProvider.TryFindDependencyManagerInPath(tcConfigB.compilerToolPaths, output , reportError, path) - - match dm with - | _, dependencyManager when not(isNull dependencyManager) -> - if tcConfigB.langVersion.SupportsFeature(LanguageFeature.PackageManagement) then - tcConfigB.AddDependencyManagerText (dependencyManager, directive, m, path) - else - errorR(Error(FSComp.SR.packageManagementRequiresVFive(), m)) - - | _, _ when directive = Directive.Include -> - errorR(Error(FSComp.SR.poundiNotSupportedByRegisteredDependencyManagers(), m)) - - // #r "Assembly" - | path, _ -> - tcConfigB.AddReferencedAssemblyByPath (m, path) - member tcConfigB.RemoveReferencedAssemblyByPath (m, path) = tcConfigB.referencedDLLs <- tcConfigB.referencedDLLs |> List.filter (fun ar -> not (Range.equals ar.Range m) || ar.Text <> path) @@ -2946,6 +2920,8 @@ type TcConfig private (data: TcConfigBuilder, validate: bool) = member x.legacyReferenceResolver = data.legacyReferenceResolver + member x.dependencyProvider = data.dependencyProvider + member tcConfig.CloneOfOriginalBuilder = { data with conditionalCompilationDefines=data.conditionalCompilationDefines } @@ -3314,8 +3290,6 @@ type TcConfig private (data: TcConfigBuilder, validate: bool) = member tcConfig.CoreLibraryDllReference() = fslibReference - member tcConfig.GetNativeProbingRoots() = data.GetNativeProbingRoots() - let ReportWarning options err = warningOn err (options.WarnLevel) (options.WarnOn) && not (List.contains (GetDiagnosticNumber err) (options.WarnOff)) @@ -4025,9 +3999,7 @@ and TcImportsWeakHack (tcImports: WeakReference) = /// Represents a table of imported assemblies with their resolutions. /// Is a disposable object, but it is recommended not to explicitly call Dispose unless you absolutely know nothing will be using its contents after the disposal. /// Otherwise, simply allow the GC to collect this and it will properly call Dispose from the finalizer. -and [] TcImports(tcConfigP: TcConfigProvider, initialResolutions: TcAssemblyResolutions, importsBase: TcImports option, - ilGlobalsOpt, compilationThread: ICompilationThread, - dependencyProviderOpt: DependencyProvider option) as this = +and [] TcImports(tcConfigP: TcConfigProvider, initialResolutions: TcAssemblyResolutions, importsBase: TcImports option, ilGlobalsOpt, compilationThread: ICompilationThread) as this = let mutable resolutions = initialResolutions let mutable importsBase: TcImports option = importsBase @@ -4358,14 +4330,6 @@ and [] TcImports(tcConfigP: TcConfigProvider, initialResolutions: TcAsse | ILScopeRef.Assembly a -> a.Name = nm | _ -> false) - member tcImports.DependencyProvider = - CheckDisposed() - match dependencyProviderOpt with - | None -> - Debug.Assert(false, "this should never be called on FrameworkTcImports") - new DependencyProvider(null, null) - | Some dependencyProvider -> dependencyProvider - member tcImports.GetImportMap() = CheckDisposed() let loaderInterface = @@ -4929,7 +4893,7 @@ and [] TcImports(tcConfigP: TcConfigProvider, initialResolutions: TcAsse let tcResolutions = TcAssemblyResolutions.BuildFromPriorResolutions(ctok, tcConfig, frameworkDLLs, []) let tcAltResolutions = TcAssemblyResolutions.BuildFromPriorResolutions(ctok, tcConfig, nonFrameworkDLLs, []) - let frameworkTcImports = new TcImports(tcConfigP, tcResolutions, None, None, tcConfig.compilationThread, None) + let frameworkTcImports = new TcImports(tcConfigP, tcResolutions, None, None, tcConfig.compilationThread) // Fetch the primaryAssembly from the referenced assemblies otherwise let primaryAssemblyReference = @@ -5055,27 +5019,24 @@ and [] TcImports(tcConfigP: TcConfigProvider, initialResolutions: TcAsse |> List.map (function UnresolvedAssemblyReference(file, originalReferences) -> file, originalReferences) |> List.iter reportAssemblyNotResolved - static member BuildNonFrameworkTcImports - (ctok, tcConfigP: TcConfigProvider, tcGlobals: TcGlobals, baseTcImports, - nonFrameworkReferences, knownUnresolved, dependencyProvider) = - + static member BuildNonFrameworkTcImports (ctok, tcConfigP: TcConfigProvider, tcGlobals: TcGlobals, baseTcImports, nonFrameworkReferences, knownUnresolved) = cancellable { let tcConfig = tcConfigP.Get ctok let tcResolutions = TcAssemblyResolutions.BuildFromPriorResolutions(ctok, tcConfig, nonFrameworkReferences, knownUnresolved) let references = tcResolutions.GetAssemblyResolutions() - let tcImports = new TcImports(tcConfigP, tcResolutions, Some baseTcImports, Some tcGlobals.ilg, tcConfig.compilationThread, Some dependencyProvider) + let tcImports = new TcImports(tcConfigP, tcResolutions, Some baseTcImports, Some tcGlobals.ilg, tcConfig.compilationThread) let! _assemblies = tcImports.RegisterAndImportReferencedAssemblies(ctok, references) tcImports.ReportUnresolvedAssemblyReferences knownUnresolved return tcImports } - static member BuildTcImports(ctok, tcConfigP: TcConfigProvider, dependencyProvider) = + static member BuildTcImports(ctok, tcConfigP: TcConfigProvider) = cancellable { let tcConfig = tcConfigP.Get ctok //let foundationalTcImports, tcGlobals = TcImports.BuildFoundationalTcImports tcConfigP let frameworkDLLs, nonFrameworkReferences, knownUnresolved = TcAssemblyResolutions.SplitNonFoundationalResolutions(ctok, tcConfig) let! tcGlobals, frameworkTcImports = TcImports.BuildFrameworkTcImports (ctok, tcConfigP, frameworkDLLs, nonFrameworkReferences) - let! tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, nonFrameworkReferences, knownUnresolved, dependencyProvider) + let! tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, nonFrameworkReferences, knownUnresolved) return tcGlobals, tcImports } @@ -5105,12 +5066,10 @@ let RequireDLL (ctok, tcImports: TcImports, tcEnv, thisAssemblyName, m, file) = let ProcessMetaCommandsFromInput (nowarnF: 'state -> range * string -> 'state, - hashReferenceF: 'state -> range * string * Directive -> 'state, + dllRequireF: 'state -> range * string -> 'state, + packageRequireF: 'state -> IDependencyManagerProvider * Directive * range * string -> 'state, loadSourceF: 'state -> range * string -> unit) - (tcConfig:TcConfigBuilder, - inp: ParsedInput, - pathOfMetaCommandSource, - state0) = + (tcConfig:TcConfigBuilder, inp, pathOfMetaCommandSource, state0) = use unwindBuildPhase = PushThreadBuildPhaseUntilUnwind BuildPhase.Parse @@ -5119,25 +5078,50 @@ let ProcessMetaCommandsFromInput | ParsedInput.SigFile (_) -> false | ParsedInput.ImplFile (ParsedImplFileInput (isScript = isScript)) -> isScript - let ProcessDependencyManagerDirective directive args m state = - if not canHaveScriptMetaCommands then - errorR(HashReferenceNotAllowedInNonScript m) + let ProcessMetaCommand state hash = + let mutable matchedm = range0 + try + let processDependencyManagerDirectives directive args m = + if not canHaveScriptMetaCommands then + errorR(HashReferenceNotAllowedInNonScript m) + + let reportError = + let report errorType err msg = + let error = err, msg + match errorType with + | ErrorReportType.Warning -> warning(Error(error, m)) + | ErrorReportType.Error -> errorR(Error(error, m)) + ResolvingErrorReport (report) + + match args with + | [path] -> + matchedm <- m + let output = tcConfig.outputDir |> Option.defaultValue "" + let dm = tcConfig.dependencyProvider.TryFindDependencyManagerInPath(tcConfig.compilerToolPaths, output , reportError, path) + match dm with + | _, dependencyManager when not(isNull dependencyManager) -> + if tcConfig.langVersion.SupportsFeature(LanguageFeature.PackageManagement) then + packageRequireF state (dependencyManager, directive, m, path) + else + errorR(Error(FSComp.SR.packageManagementRequiresVFive(), m)) + state - match args with - | [path] -> - let p = - if String.IsNullOrWhiteSpace(path) then "" - else path + | _, _ when directive = Directive.Include -> + errorR(Error(FSComp.SR.poundiNotSupportedByRegisteredDependencyManagers(), m)) + state - hashReferenceF state (m, p, directive) + // #r "Assembly" + | path, _ -> + let p = + if String.IsNullOrWhiteSpace(path) then "" + else path - | _ -> - errorR(Error(FSComp.SR.buildInvalidHashrDirective(), m)) - state + dllRequireF state (m, p) + + | _ -> + errorR(Error(FSComp.SR.buildInvalidHashrDirective(), m)) + state - let ProcessMetaCommand state hash = - let mutable matchedm = range0 - try match hash with | ParsedHashDirective("I", args, m) -> if not canHaveScriptMetaCommands then @@ -5154,12 +5138,10 @@ let ProcessMetaCommandsFromInput List.fold (fun state d -> nowarnF state (m,d)) state numbers | ParsedHashDirective(("reference" | "r"), args, m) -> - matchedm<-m - ProcessDependencyManagerDirective Directive.Resolution args m state + processDependencyManagerDirectives Directive.Resolution args m | ParsedHashDirective(("i"), args, m) -> - matchedm<-m - ProcessDependencyManagerDirective Directive.Include args m state + processDependencyManagerDirectives Directive.Include args m | ParsedHashDirective("load", args, m) -> if not canHaveScriptMetaCommands then @@ -5235,22 +5217,20 @@ let ApplyNoWarnsToTcConfig (tcConfig: TcConfig, inp: ParsedInput, pathOfMetaComm // Clone let tcConfigB = tcConfig.CloneOfOriginalBuilder let addNoWarn = fun () (m,s) -> tcConfigB.TurnWarningOff(m, s) - let addReference = fun () (_m, _s, _) -> () - let addLoadedSource = fun () (_m, _s) -> () - ProcessMetaCommandsFromInput - (addNoWarn, addReference, addLoadedSource) - (tcConfigB, inp, pathOfMetaCommandSource, ()) + let addReferencedAssemblyByPath = fun () (_m,_s) -> () + let addDependencyManagerText = fun () (_prefix, _lt, _m, _s) -> () + let addLoadedSource = fun () (_m,_s) -> () + ProcessMetaCommandsFromInput (addNoWarn, addReferencedAssemblyByPath, addDependencyManagerText, addLoadedSource) (tcConfigB, inp, pathOfMetaCommandSource, ()) TcConfig.Create(tcConfigB, validate=false) -let ApplyMetaCommandsFromInputToTcConfig (tcConfig: TcConfig, inp: ParsedInput, pathOfMetaCommandSource, dependencyProvider) = +let ApplyMetaCommandsFromInputToTcConfig (tcConfig: TcConfig, inp: ParsedInput, pathOfMetaCommandSource) = // Clone let tcConfigB = tcConfig.CloneOfOriginalBuilder let getWarningNumber = fun () _ -> () - let addReferenceDirective = fun () (m, path, directive) -> tcConfigB.AddReferenceDirective(dependencyProvider, m, path, directive) + let addReferencedAssemblyByPath = fun () (m,s) -> tcConfigB.AddReferencedAssemblyByPath(m,s) + let addDependencyManagerText = fun () (packageManager, lt, m,s) -> tcConfigB.AddDependencyManagerText(packageManager, lt, m, s) let addLoadedSource = fun () (m,s) -> tcConfigB.AddLoadedSource(m,s,pathOfMetaCommandSource) - ProcessMetaCommandsFromInput - (getWarningNumber, addReferenceDirective, addLoadedSource) - (tcConfigB, inp, pathOfMetaCommandSource, ()) + ProcessMetaCommandsFromInput (getWarningNumber, addReferencedAssemblyByPath, addDependencyManagerText, addLoadedSource) (tcConfigB, inp, pathOfMetaCommandSource, ()) TcConfig.Create(tcConfigB, validate=false) //---------------------------------------------------------------------------- @@ -5354,8 +5334,8 @@ module ScriptPreprocessClosure = let tcConfigB = TcConfigBuilder.CreateNew (legacyReferenceResolver, defaultFSharpBinariesDir, reduceMemoryUsage, projectDir, - isInteractive, isInvalidationSupported, CopyFSharpCoreFlag.No, - tryGetMetadataSnapshot) + isInteractive, isInvalidationSupported, defaultCopyFSharpCore=CopyFSharpCoreFlag.No, + tryGetMetadataSnapshot=tryGetMetadataSnapshot) applyCommandLineArgs tcConfigB @@ -5392,16 +5372,16 @@ module ScriptPreprocessClosure = [] let ApplyMetaCommandsFromInputToTcConfigAndGatherNoWarn - (tcConfig: TcConfig, inp: ParsedInput, - pathOfMetaCommandSource, dependencyProvider) = + (tcConfig: TcConfig, inp: ParsedInput, pathOfMetaCommandSource) = let tcConfigB = tcConfig.CloneOfOriginalBuilder let mutable nowarns = [] let getWarningNumber = fun () (m, s) -> nowarns <- (s, m) :: nowarns - let addReferenceDirective = fun () (m, s, directive) -> tcConfigB.AddReferenceDirective(dependencyProvider, m, s, directive) + let addReferencedAssemblyByPath = fun () (m, s) -> tcConfigB.AddReferencedAssemblyByPath(m, s) + let addDependencyManagerText = fun () (packageManagerPrefix, lt, m, s) -> tcConfigB.AddDependencyManagerText(packageManagerPrefix, lt, m, s) let addLoadedSource = fun () (m, s) -> tcConfigB.AddLoadedSource(m, s, pathOfMetaCommandSource) try - ProcessMetaCommandsFromInput (getWarningNumber, addReferenceDirective, addLoadedSource) (tcConfigB, inp, pathOfMetaCommandSource, ()) + ProcessMetaCommandsFromInput (getWarningNumber, addReferencedAssemblyByPath, addDependencyManagerText, addLoadedSource) (tcConfigB, inp, pathOfMetaCommandSource, ()) with ReportedError _ -> // Recover by using whatever did end up in the tcConfig () @@ -5413,10 +5393,7 @@ module ScriptPreprocessClosure = let tcConfigB = tcConfig.CloneOfOriginalBuilder TcConfig.Create(tcConfigB, validate=false), nowarns - let FindClosureFiles - (mainFile, _m, closureSources, origTcConfig:TcConfig, - codeContext, lexResourceManager: Lexhelp.LexResourceManager, dependencyProvider: DependencyProvider) = - + let FindClosureFiles(mainFile, _m, closureSources, origTcConfig:TcConfig, codeContext, lexResourceManager: Lexhelp.LexResourceManager) = let mutable tcConfig = origTcConfig let observedSources = Observed() @@ -5431,19 +5408,20 @@ module ScriptPreprocessClosure = | [] -> () | { Directive=_; LineStatus=_; Line=_; Range=m } :: _ -> let reportError = - ResolvingErrorReport (fun errorType err msg -> + let report errorType err msg = let error = err, msg match errorType with | ErrorReportType.Warning -> warning(Error(error, m)) - | ErrorReportType.Error -> errorR(Error(error, m))) + | ErrorReportType.Error -> errorR(Error(error, m)) + ResolvingErrorReport (report) match origTcConfig.packageManagerLines |> Map.tryFind packageManagerKey with | Some oldDependencyManagerLines when oldDependencyManagerLines = packageManagerLines -> () | _ -> let outputDir = tcConfig.outputDir |> Option.defaultValue "" - match dependencyProvider.TryFindDependencyManagerByKey(tcConfig.compilerToolPaths, outputDir, reportError, packageManagerKey) with + match tcConfig.dependencyProvider.TryFindDependencyManagerByKey(tcConfig.compilerToolPaths, outputDir, reportError, packageManagerKey) with | null -> - errorR(Error(dependencyProvider.CreatePackageManagerUnknownError(tcConfig.compilerToolPaths, outputDir, packageManagerKey, reportError), m)) + errorR(Error(tcConfig.dependencyProvider.CreatePackageManagerUnknownError(tcConfig.compilerToolPaths, outputDir, packageManagerKey, reportError), m)) | dependencyManager -> let directive d = @@ -5452,7 +5430,7 @@ module ScriptPreprocessClosure = | Directive.Include -> "i" let packageManagerTextLines = packageManagerLines |> List.map(fun l -> directive l.Directive, l.Line) - let result = dependencyProvider.Resolve(dependencyManager, ".fsx", packageManagerTextLines, reportError, executionTfm, executionRid, tcConfig.implicitIncludeDir, mainFile, scriptName) + let result = tcConfig.dependencyProvider.Resolve(dependencyManager, ".fsx", packageManagerTextLines, reportError, executionTfm, executionRid, tcConfig.implicitIncludeDir, mainFile, scriptName) match result.Success with | true -> // Resolution produced no errors @@ -5494,7 +5472,7 @@ module ScriptPreprocessClosure = let pathOfMetaCommandSource = Path.GetDirectoryName filename let preSources = tcConfig.GetAvailableLoadedSources() - let tcConfigResult, noWarns = ApplyMetaCommandsFromInputToTcConfigAndGatherNoWarn (tcConfig, parsedScriptAst, pathOfMetaCommandSource, dependencyProvider) + let tcConfigResult, noWarns = ApplyMetaCommandsFromInputToTcConfigAndGatherNoWarn (tcConfig, parsedScriptAst, pathOfMetaCommandSource) tcConfig <- tcConfigResult // We accumulate the tcConfig in order to collect assembly references yield! resolveDependencyManagerSources filename @@ -5604,7 +5582,7 @@ module ScriptPreprocessClosure = useSimpleResolution, useFsiAuxLib, useSdkRefs, lexResourceManager: Lexhelp.LexResourceManager, applyCommandLineArgs, assumeDotNetFramework, - tryGetMetadataSnapshot, reduceMemoryUsage, dependencyProvider) = + tryGetMetadataSnapshot, reduceMemoryUsage) = // Resolve the basic references such as FSharp.Core.dll first, before processing any #I directives in the script // @@ -5628,18 +5606,15 @@ module ScriptPreprocessClosure = tryGetMetadataSnapshot, reduceMemoryUsage) let closureSources = [ClosureSource(filename, range0, sourceText, true)] - let closureFiles, tcConfig = FindClosureFiles(filename, range0, closureSources, tcConfig, codeContext, lexResourceManager, dependencyProvider) + let closureFiles, tcConfig = FindClosureFiles(filename, range0, closureSources, tcConfig, codeContext, lexResourceManager) GetLoadClosure(ctok, filename, closureFiles, tcConfig, codeContext) /// Given source filename, find the full load closure /// Used from fsi.fs and fsc.fs, for #load and command line - let GetFullClosureOfScriptFiles - (ctok, tcConfig:TcConfig, files:(string*range) list, codeContext, - lexResourceManager: Lexhelp.LexResourceManager, dependencyProvider) = - + let GetFullClosureOfScriptFiles(ctok, tcConfig:TcConfig, files:(string*range) list,codeContext,lexResourceManager: Lexhelp.LexResourceManager) = let mainFile, mainFileRange = List.last files let closureSources = files |> List.collect (fun (filename, m) -> ClosureSourceOfFilename(filename, m,tcConfig.inputCodePage,true)) - let closureFiles,tcConfig = FindClosureFiles(mainFile, mainFileRange, closureSources, tcConfig, codeContext, lexResourceManager, dependencyProvider) + let closureFiles,tcConfig = FindClosureFiles(mainFile, mainFileRange, closureSources, tcConfig, codeContext, lexResourceManager) GetLoadClosure(ctok, mainFile, closureFiles, tcConfig, codeContext) type LoadClosure with @@ -5652,22 +5627,20 @@ type LoadClosure with (ctok, legacyReferenceResolver, defaultFSharpBinariesDir, filename: string, sourceText: ISourceText, codeContext, useSimpleResolution: bool, useFsiAuxLib, useSdkRefs, lexResourceManager: Lexhelp.LexResourceManager, - applyCommandLineArgs, assumeDotNetFramework, tryGetMetadataSnapshot, - reduceMemoryUsage, dependencyProvider) = + applyCommandLineArgs, assumeDotNetFramework, tryGetMetadataSnapshot, reduceMemoryUsage) = use unwindBuildPhase = PushThreadBuildPhaseUntilUnwind BuildPhase.Parse ScriptPreprocessClosure.GetFullClosureOfScriptText (ctok, legacyReferenceResolver, defaultFSharpBinariesDir, filename, sourceText, codeContext, useSimpleResolution, useFsiAuxLib, useSdkRefs, lexResourceManager, - applyCommandLineArgs, assumeDotNetFramework, tryGetMetadataSnapshot, reduceMemoryUsage, dependencyProvider) + applyCommandLineArgs, assumeDotNetFramework, tryGetMetadataSnapshot, reduceMemoryUsage) /// Analyze a set of script files and find the closure of their references. static member ComputeClosureOfScriptFiles (ctok, tcConfig: TcConfig, files:(string*range) list, codeContext, - lexResourceManager: Lexhelp.LexResourceManager, dependencyProvider) = - + lexResourceManager: Lexhelp.LexResourceManager) = use unwindBuildPhase = PushThreadBuildPhaseUntilUnwind BuildPhase.Parse - ScriptPreprocessClosure.GetFullClosureOfScriptFiles (ctok, tcConfig, files, codeContext, lexResourceManager, dependencyProvider) + ScriptPreprocessClosure.GetFullClosureOfScriptFiles (ctok, tcConfig, files, codeContext, lexResourceManager) //---------------------------------------------------------------------------- // Initial type checking environment diff --git a/src/fsharp/CompileOps.fsi b/src/fsharp/CompileOps.fsi index 9725f135ac6..ebedf48153d 100644 --- a/src/fsharp/CompileOps.fsi +++ b/src/fsharp/CompileOps.fsi @@ -413,6 +413,8 @@ type TcConfigBuilder = mutable pathMap : PathMap mutable langVersion : LanguageVersion + + mutable dependencyProvider: DependencyProvider } static member Initial: TcConfigBuilder @@ -441,9 +443,6 @@ type TcConfigBuilder = static member SplitCommandLineResourceInfo: string -> string * string * ILResourceAccess - // Directories to start probing in for native DLLs for FSI dynamic loading - member GetNativeProbingRoots: unit -> seq - [] // Immutable TcConfig type TcConfig = @@ -560,8 +559,8 @@ type TcConfig = member isInteractive: bool member isInvalidationSupported: bool - member ComputeLightSyntaxInitialStatus: string -> bool + member ComputeLightSyntaxInitialStatus: string -> bool member GetTargetFrameworkDirectories: unit -> string list /// Get the loaded sources that exist and issue a warning for the ones that don't @@ -576,11 +575,8 @@ type TcConfig = member MakePathAbsolute: string -> string member copyFSharpCore: CopyFSharpCoreFlag - member shadowCopyReferences: bool - member useSdkRefs: bool - member langVersion: LanguageVersion static member Create: TcConfigBuilder * validate: bool -> TcConfig @@ -644,28 +640,18 @@ type TcImports = interface System.IDisposable //new: TcImports option -> TcImports member DllTable: NameMap with get - member GetImportedAssemblies: unit -> ImportedAssembly list - member GetCcusInDeclOrder: unit -> CcuThunk list - /// This excludes any framework imports (which may be shared between multiple builds) member GetCcusExcludingBase: unit -> CcuThunk list - member FindDllInfo: CompilationThreadToken * range * string -> ImportedBinary - member TryFindDllInfo: CompilationThreadToken * range * string * lookupOnly: bool -> option - member FindCcuFromAssemblyRef: CompilationThreadToken * range * ILAssemblyRef -> CcuResolutionResult - #if !NO_EXTENSIONTYPING member ProviderGeneratedTypeRoots: ProviderGeneratedType list #endif - member GetImportMap: unit -> Import.ImportMap - member DependencyProvider: DependencyProvider - /// Try to resolve a referenced assembly based on TcConfig settings. member TryResolveAssemblyReference: CompilationThreadToken * AssemblyReference * ResolveAssemblyReferenceMode -> OperationResult @@ -685,33 +671,13 @@ type TcImports = #endif /// Report unresolved references that also weren't consumed by any type providers. member ReportUnresolvedAssemblyReferences: UnresolvedAssemblyReference list -> unit - member SystemRuntimeContainsType: string -> bool member internal Base: TcImports option - static member BuildFrameworkTcImports: - CompilationThreadToken * - TcConfigProvider * - AssemblyResolution list * - AssemblyResolution list - -> Cancellable - - static member BuildNonFrameworkTcImports: - CompilationThreadToken * - TcConfigProvider * - TcGlobals * - TcImports * - AssemblyResolution list * - UnresolvedAssemblyReference list * - DependencyProvider - -> Cancellable - - static member BuildTcImports: - CompilationThreadToken * - TcConfigProvider * - DependencyProvider - -> Cancellable + static member BuildFrameworkTcImports : CompilationThreadToken * TcConfigProvider * AssemblyResolution list * AssemblyResolution list -> Cancellable + static member BuildNonFrameworkTcImports : CompilationThreadToken * TcConfigProvider * TcGlobals * TcImports * AssemblyResolution list * UnresolvedAssemblyReference list -> Cancellable + static member BuildTcImports : CompilationThreadToken * TcConfigProvider -> Cancellable //---------------------------------------------------------------------------- // Special resources in DLLs @@ -737,22 +703,24 @@ val WriteOptimizationData: TcGlobals * filename: string * inMem: bool * CcuThunk // #r and other directives //-------------------------------------------------------------------------- +//---------------------------------------------------------------------------- +// #r and other directives +//-------------------------------------------------------------------------- + /// Process #r in F# Interactive. /// Adds the reference to the tcImports and add the ccu to the type checking environment. val RequireDLL: CompilationThreadToken * TcImports * TcEnv * thisAssemblyName: string * referenceRange: range * file: string -> TcEnv * (ImportedBinary list * ImportedAssembly list) -/// A general routine to process hash directives +/// Processing # commands val ProcessMetaCommandsFromInput : - (('T -> range * string -> 'T) * - ('T -> range * string * Directive -> 'T) * - ('T -> range * string -> unit)) - -> TcConfigBuilder * ParsedInput * string * 'T - -> 'T + (('T -> range * string -> 'T) * ('T -> range * string -> 'T) * ('T -> IDependencyManagerProvider * Directive * range * string -> 'T) * ('T -> range * string -> unit)) + -> TcConfigBuilder * ParsedInput * string * 'T + -> 'T -/// Process all the #r, #I etc. in an input. For non-scripts report warnings about ignored directives. -val ApplyMetaCommandsFromInputToTcConfig: TcConfig * ParsedInput * string * DependencyProvider -> TcConfig +/// Process all the #r, #I etc. in an input +val ApplyMetaCommandsFromInputToTcConfig: TcConfig * ParsedInput * string -> TcConfig -/// Process the #nowarn in an input and integrate them into the TcConfig +/// Process the #nowarn in an input val ApplyNoWarnsToTcConfig: TcConfig * ParsedInput * string -> TcConfig //---------------------------------------------------------------------------- @@ -885,31 +853,8 @@ type LoadClosure = // /// A temporary TcConfig is created along the way, is why this routine takes so many arguments. We want to be sure to use exactly the /// same arguments as the rest of the application. - static member ComputeClosureOfScriptText: - CompilationThreadToken * - legacyReferenceResolver: ReferenceResolver.Resolver * - defaultFSharpBinariesDir: string * - filename: string * - sourceText: ISourceText * - implicitDefines:CodeContext * - useSimpleResolution: bool * - useFsiAuxLib: bool * - useSdkRefs: bool * - lexResourceManager: Lexhelp.LexResourceManager * - applyCompilerOptions: (TcConfigBuilder -> unit) * - assumeDotNetFramework: bool * - tryGetMetadataSnapshot: ILReaderTryGetMetadataSnapshot * - reduceMemoryUsage: ReduceMemoryFlag * - dependencyProvider: DependencyProvider - -> LoadClosure + static member ComputeClosureOfScriptText: CompilationThreadToken * legacyReferenceResolver: ReferenceResolver.Resolver * defaultFSharpBinariesDir: string * filename: string * sourceText: ISourceText * implicitDefines:CodeContext * useSimpleResolution: bool * useFsiAuxLib: bool * useSdkRefs: bool * lexResourceManager: Lexhelp.LexResourceManager * applyCompilerOptions: (TcConfigBuilder -> unit) * assumeDotNetFramework: bool * tryGetMetadataSnapshot: ILReaderTryGetMetadataSnapshot * reduceMemoryUsage: ReduceMemoryFlag -> LoadClosure /// Analyze a set of script files and find the closure of their references. The resulting references are then added to the given TcConfig. /// Used from fsi.fs and fsc.fs, for #load and command line. - static member ComputeClosureOfScriptFiles: - CompilationThreadToken * - tcConfig:TcConfig * - (string * range) list * - implicitDefines:CodeContext * - lexResourceManager: Lexhelp.LexResourceManager * - dependencyProvider: DependencyProvider - -> LoadClosure + static member ComputeClosureOfScriptFiles: CompilationThreadToken * tcConfig:TcConfig * (string * range) list * implicitDefines:CodeContext * lexResourceManager: Lexhelp.LexResourceManager -> LoadClosure diff --git a/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs b/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs index b89cd09bad7..c3c7046ef29 100644 --- a/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs +++ b/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs @@ -68,14 +68,19 @@ module ReflectionHelper = e.InnerException | _ -> e +open ReflectionHelper +open RidHelpers + /// Indicate the type of error to report [] type ErrorReportType = | Warning | Error + type ResolvingErrorReport = delegate of ErrorReportType * int * string -> unit + (* Shape of Dependency Manager contract, resolved using reflection *) /// The results of ResolveDependencies type IResolveDependenciesResult = @@ -263,17 +268,9 @@ type ReflectionDependencyManagerProvider(theType: Type, /// Class is IDisposable type DependencyProvider (assemblyProbingPaths: AssemblyResolutionProbe, nativeProbingRoots: NativeResolutionProbe) = - // Note: creating a NativeDllResolveHandler currently installs process-wide handlers - let dllResolveHandler = - match assemblyProbingPaths with - | null -> { new IDisposable with member _.Dispose() = () } - | _ -> new NativeDllResolveHandler(nativeProbingRoots) :> IDisposable + let dllResolveHandler = new NativeDllResolveHandler(nativeProbingRoots) :> IDisposable - // Note: creating a AssemblyResolveHandler currently installs process-wide handlers - let assemblyResolveHandler = - match assemblyProbingPaths with - | null -> { new IDisposable with member _.Dispose() = () } - | _ -> new AssemblyResolveHandler(assemblyProbingPaths) :> IDisposable + let assemblyResolveHandler = new AssemblyResolveHandler(assemblyProbingPaths) :> IDisposable // Resolution Path = Location of FSharp.Compiler.Private.dll let assemblySearchPaths = lazy ( @@ -332,6 +329,10 @@ type DependencyProvider (assemblyProbingPaths: AssemblyResolutionProbe, nativePr let cache = ConcurrentDictionary<_,IResolveDependenciesResult>(HashIdentity.Structural) + /// Returns a formatted error message for the host to presentconstruct with just nativeProbing handler + new (nativeProbingRoots: NativeResolutionProbe) = + new DependencyProvider(Unchecked.defaultof, nativeProbingRoots) + /// Returns a formatted help messages for registered dependencymanagers for the host to present member _.GetRegisteredDependencyManagerHelpText (compilerTools, outputDir, errorReport) = [| let managers = RegisteredDependencyManagers compilerTools (Option.ofString outputDir) errorReport diff --git a/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fsi b/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fsi index a47917c05fb..2f16b59fd99 100644 --- a/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fsi +++ b/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fsi @@ -56,18 +56,16 @@ type ErrorReportType = type ResolvingErrorReport = delegate of ErrorReportType * int * string -> unit /// Provides DependencyManagement functions. -/// -/// The class incrementally collects IDependencyManagerProvider, indexed by key, and -/// queries them. These are found and instantiated with respect to the compilerTools and outputDir -/// provided each time the TryFindDependencyManagerByKey and TryFindDependencyManagerInPath are -/// executed, which are assumed to be invariant over the lifetime of the DependencyProvider. +/// Class is IDisposable type DependencyProvider = interface System.IDisposable - /// Construct a new DependencyProvider. assemblyProbingPaths and nativeProbingRoots may be null - /// to indicate no dynamic resolution handlers should be installed. + /// Construct a new DependencyProvider new: assemblyProbingPaths: AssemblyResolutionProbe * nativeProbingRoots: NativeResolutionProbe -> DependencyProvider + /// Construct a new DependencyProvider + new: nativeProbingRoots: NativeResolutionProbe -> DependencyProvider + /// Returns a formatted help messages for registered dependencymanagers for the host to present member GetRegisteredDependencyManagerHelpText: string seq * string * ResolvingErrorReport -> string[] diff --git a/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fs b/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fs index 6a4477631c0..60b52982cc5 100644 --- a/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fs +++ b/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fs @@ -101,9 +101,8 @@ type NativeDllResolveHandlerCoreClr (_nativeProbingRoots: NativeResolutionProbe) let probe = match _nativeProbingRoots with | null -> None - | _ -> - _nativeProbingRoots.Invoke() - |> Seq.tryPick(fun root -> + | _ -> _nativeProbingRoots.Invoke() + |> Seq.tryPick(fun root -> probingFileNames name |> Seq.tryPick(fun name -> let path = Path.Combine(root, name) if File.Exists(path) then diff --git a/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fsi b/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fsi index d1aa22fe49c..c98b5f142e7 100644 --- a/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fsi +++ b/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fsi @@ -18,7 +18,7 @@ type NativeResolutionProbe = delegate of Unit -> seq // Cut down AssemblyLoadContext, for loading native libraries type NativeDllResolveHandler = - /// Construct a new NativeDllResolveHandler + /// Construct a new DependencyProvider new: nativeProbingRoots: NativeResolutionProbe -> NativeDllResolveHandler interface IDisposable diff --git a/src/fsharp/fsc.fs b/src/fsharp/fsc.fs index 26f375ce05e..4892c4a07fb 100644 --- a/src/fsharp/fsc.fs +++ b/src/fsharp/fsc.fs @@ -50,7 +50,6 @@ open FSharp.Compiler.TypedTreeOps open FSharp.Compiler.TcGlobals open FSharp.Compiler.TypeChecker open FSharp.Compiler.XmlDoc -open Microsoft.DotNet.DependencyManager open FSharp.Compiler.AbstractIL.Internal.StrongNameSign @@ -203,7 +202,7 @@ let TypeCheck (ctok, tcConfig, tcImports, tcGlobals, errorLogger: ErrorLogger, a exiter.Exit 1 /// Check for .fsx and, if present, compute the load closure for of #loaded files. -let AdjustForScriptCompile(ctok, tcConfigB: TcConfigBuilder, commandLineSourceFiles, lexResourceManager, dependencyProvider) = +let AdjustForScriptCompile(ctok, tcConfigB: TcConfigBuilder, commandLineSourceFiles, lexResourceManager) = let combineFilePath file = try @@ -228,8 +227,7 @@ let AdjustForScriptCompile(ctok, tcConfigB: TcConfigBuilder, commandLineSourceFi if IsScript filename then let closure = LoadClosure.ComputeClosureOfScriptFiles - (ctok, tcConfig, [filename, rangeStartup], CodeContext.Compilation, - lexResourceManager, dependencyProvider) + (ctok, tcConfig, [filename, rangeStartup], CodeContext.Compilation, lexResourceManager=lexResourceManager) // Record the references from the analysis of the script. The full resolutions are recorded as the corresponding #I paths used to resolve them // are local to the scripts and not added to the tcConfigB (they are added to localized clones of the tcConfigB). @@ -1765,8 +1763,6 @@ let main0(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, // Share intern'd strings across all lexing/parsing let lexResourceManager = new Lexhelp.LexResourceManager() - let dependencyProvider = new DependencyProvider(null, null) - // process command line, flags and collect filenames let sourceFiles = @@ -1775,7 +1771,7 @@ let main0(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, try let sourceFiles = let files = ProcessCommandLineFlags (tcConfigB, setProcessThreadLocals, lcidFromCodePage, argv) - AdjustForScriptCompile(ctok, tcConfigB, files, lexResourceManager, dependencyProvider) + AdjustForScriptCompile(ctok, tcConfigB, files, lexResourceManager) sourceFiles with e -> @@ -1859,12 +1855,12 @@ let main0(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, if tcConfig.printAst then inputs |> List.iter (fun (input, _filename) -> printf "AST:\n"; printfn "%+A" input; printf "\n") - let tcConfig = (tcConfig, inputs) ||> List.fold (fun z (x, m) -> ApplyMetaCommandsFromInputToTcConfig(z, x, m, dependencyProvider)) + let tcConfig = (tcConfig, inputs) ||> List.fold (fun z (x, m) -> ApplyMetaCommandsFromInputToTcConfig(z, x, m)) let tcConfigP = TcConfigProvider.Constant tcConfig // Import other assemblies ReportTime tcConfig "Import non-system references" - let tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, otherRes, knownUnresolved, dependencyProvider) |> Cancellable.runWithoutCancellation + let tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, otherRes, knownUnresolved) |> Cancellable.runWithoutCancellation // register tcImports to be disposed in future disposables.Register tcImports @@ -1992,7 +1988,6 @@ let main0OfAst (ctok, legacyReferenceResolver, reduceMemoryUsage, assemblyName, delayForFlagsLogger.ForwardDelayedDiagnostics tcConfigB exiter.Exit 1 - let dependencyProvider = new DependencyProvider(null, null) let errorLogger = errorLoggerProvider.CreateErrorLoggerUpToMaxErrors(tcConfigB, exiter) // Install the global error logger and never remove it. This logger does have all command-line flags considered. @@ -2015,12 +2010,12 @@ let main0OfAst (ctok, legacyReferenceResolver, reduceMemoryUsage, assemblyName, use unwindParsePhase = PushThreadBuildPhaseUntilUnwind (BuildPhase.Parse) let meta = Directory.GetCurrentDirectory() - let tcConfig = (tcConfig,inputs) ||> List.fold (fun tcc inp -> ApplyMetaCommandsFromInputToTcConfig (tcc, inp, meta, dependencyProvider)) + let tcConfig = (tcConfig,inputs) ||> List.fold (fun tcc inp -> ApplyMetaCommandsFromInputToTcConfig (tcc, inp,meta)) let tcConfigP = TcConfigProvider.Constant tcConfig // Import other assemblies ReportTime tcConfig "Import non-system references" - let tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, otherRes, knownUnresolved, dependencyProvider) |> Cancellable.runWithoutCancellation + let tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, otherRes, knownUnresolved) |> Cancellable.runWithoutCancellation // register tcImports to be disposed in future disposables.Register tcImports diff --git a/src/fsharp/fsi/fsi.fs b/src/fsharp/fsi/fsi.fs index f16c1c33b0c..8e714f71dd1 100644 --- a/src/fsharp/fsi/fsi.fs +++ b/src/fsharp/fsi/fsi.fs @@ -601,11 +601,7 @@ let internal directoryName (s:string) = //---------------------------------------------------------------------------- /// Process the command line options -type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, - argv: string[], - tcConfigB, - fsiConsoleOutput: FsiConsoleOutput) = - +type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, argv: string[], tcConfigB, fsiConsoleOutput: FsiConsoleOutput) = let mutable enableConsoleKeyProcessing = // Mono on Win32 doesn't implement correct console processing not (runningOnMono && System.Environment.OSVersion.Platform = System.PlatformID.Win32NT) @@ -761,8 +757,6 @@ type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, stopProcessingRecovery e range0; failwithf "Error creating evaluation session: %A" e inputFilesAcc - let dependencyProvider = new DependencyProvider(null, NativeResolutionProbe(tcConfigB.GetNativeProbingRoots)) - do if tcConfigB.utf8output then let prev = Console.OutputEncoding @@ -803,7 +797,7 @@ type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, fsiConsoleOutput.uprintfn """ #help;; // %s""" (FSIstrings.SR.fsiIntroTextHashhelpInfo()) if tcConfigB.langVersion.SupportsFeature(LanguageFeature.PackageManagement) then - for msg in dependencyProvider.GetRegisteredDependencyManagerHelpText(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m) do + for msg in tcConfigB.dependencyProvider.GetRegisteredDependencyManagerHelpText(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m) do fsiConsoleOutput.uprintfn "%s" msg fsiConsoleOutput.uprintfn """ #quit;; // %s""" (FSIstrings.SR.fsiIntroTextHashquitInfo()) (* last thing you want to do, last thing in the list - stands out more *) @@ -830,8 +824,6 @@ type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, member __.SourceFiles = sourceFiles member __.Gui = gui - member _.DependencyProvider = dependencyProvider - /// Set the current ui culture for the current thread. let internal SetCurrentUICultureForThread (lcid : int option) = let culture = Thread.CurrentThread.CurrentUICulture @@ -1469,9 +1461,9 @@ type internal FsiDynamicCompiler | { Directive=_; LineStatus=_; Line=_; Range=m } :: _ -> let outputDir = tcConfigB.outputDir |> Option.defaultValue "" - match fsiOptions.DependencyProvider.TryFindDependencyManagerByKey(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, packageManagerKey) with + match tcConfigB.dependencyProvider.TryFindDependencyManagerByKey(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, packageManagerKey) with | null -> - errorR(Error(fsiOptions.DependencyProvider.CreatePackageManagerUnknownError(tcConfigB.compilerToolPaths, outputDir, packageManagerKey, reportError m), m)) + errorR(Error(tcConfigB.dependencyProvider.CreatePackageManagerUnknownError(tcConfigB.compilerToolPaths, outputDir, packageManagerKey, reportError m), m)) istate | dependencyManager -> let directive d = @@ -1483,7 +1475,7 @@ type internal FsiDynamicCompiler packageManagerLines |> List.map (fun line -> directive line.Directive, line.Line) try - let result = fsiOptions.DependencyProvider.Resolve(dependencyManager, ".fsx", packageManagerTextLines, reportError m, executionTfm, executionRid, tcConfigB.implicitIncludeDir, "stdin.fsx", "stdin.fsx") + let result = tcConfigB.dependencyProvider.Resolve(dependencyManager, ".fsx", packageManagerTextLines, reportError m, executionTfm, executionRid, tcConfigB.implicitIncludeDir, "stdin.fsx", "stdin.fsx") match result.Success with | false -> tcConfigB.packageManagerLines <- PackageManagerLine.RemoveUnprocessedLines packageManagerKey tcConfigB.packageManagerLines @@ -1510,27 +1502,8 @@ type internal FsiDynamicCompiler (fun () -> ProcessMetaCommandsFromInput ((fun st (m,nm) -> tcConfigB.TurnWarningOff(m,nm); st), - (fun st (m, path, directive) -> - - let dm = tcImports.DependencyProvider.TryFindDependencyManagerInPath(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, path) - - match dm with - | _, dependencyManager when not(isNull dependencyManager) -> - if tcConfigB.langVersion.SupportsFeature(LanguageFeature.PackageManagement) then - fsiDynamicCompiler.EvalDependencyManagerTextFragment (dependencyManager, directive, m, path) - st - else - errorR(Error(FSComp.SR.packageManagementRequiresVFive(), m)) - st - - | _, _ when directive = Directive.Include -> - errorR(Error(FSComp.SR.poundiNotSupportedByRegisteredDependencyManagers(), m)) - st - - // #r "Assembly" - | path, _ -> - snd (fsiDynamicCompiler.EvalRequireReference (ctok, st, m, path)) - ), + (fun st (m,nm) -> snd (fsiDynamicCompiler.EvalRequireReference (ctok, st, m, nm))), + (fun st (packageManagerPrefix, lt, m, nm) -> fsiDynamicCompiler.EvalDependencyManagerTextFragment (packageManagerPrefix, lt, m, nm); st), (fun _ _ -> ())) (tcConfigB, inp, Path.GetDirectoryName sourceFile, istate)) @@ -1544,11 +1517,7 @@ type internal FsiDynamicCompiler // Close the #load graph on each file and gather the inputs from the scripts. let tcConfig = TcConfig.Create(tcConfigB,validate=false) - - let closure = - LoadClosure.ComputeClosureOfScriptFiles(ctok, tcConfig, - sourceFiles, CodeContext.CompilationAndEvaluation, - lexResourceManager, fsiOptions.DependencyProvider) + let closure = LoadClosure.ComputeClosureOfScriptFiles(ctok, tcConfig, sourceFiles, CodeContext.CompilationAndEvaluation, lexResourceManager=lexResourceManager) // Intent "[Loading %s]\n" (String.concat "\n and " sourceFiles) fsiConsoleOutput.uprintf "[%s " (FSIstrings.SR.fsiLoadingFilesPrefixText()) @@ -2137,7 +2106,7 @@ type internal FsiInteractionProcessor /// Execute a single parsed interaction. Called on the GUI/execute/main thread. let ExecInteraction (ctok, tcConfig:TcConfig, istate, action:ParsedFsiInteraction, errorLogger: ErrorLogger) = let packageManagerDirective directive path m = - let dm = fsiOptions.DependencyProvider.TryFindDependencyManagerInPath(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, path) + let dm = tcConfigB.dependencyProvider.TryFindDependencyManagerInPath(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, path) match dm with | null, null -> // error already reported @@ -2780,8 +2749,7 @@ type FsiEvaluationSession (fsi: FsiEvaluationSessionHostConfig, argv:string[], i do updateBannerText() // setting the correct banner so that 'fsi -?' display the right thing - let fsiOptions = FsiCommandLineOptions(fsi, argv, tcConfigB, fsiConsoleOutput) - + let fsiOptions = FsiCommandLineOptions(fsi, argv, tcConfigB, fsiConsoleOutput) let fsiConsolePrompt = FsiConsolePrompt(fsiOptions, fsiConsoleOutput) do @@ -2823,7 +2791,7 @@ type FsiEvaluationSession (fsi: FsiEvaluationSessionHostConfig, argv:string[], i let tcImports = try - TcImports.BuildNonFrameworkTcImports(ctokStartup, tcConfigP, tcGlobals, frameworkTcImports, nonFrameworkResolutions, unresolvedReferences, fsiOptions.DependencyProvider) |> Cancellable.runWithoutCancellation + TcImports.BuildNonFrameworkTcImports(ctokStartup, tcConfigP, tcGlobals, frameworkTcImports, nonFrameworkResolutions, unresolvedReferences) |> Cancellable.runWithoutCancellation with e -> stopProcessingRecovery e range0; failwithf "Error creating evaluation session: %A" e diff --git a/src/fsharp/service/FSharpCheckerResults.fs b/src/fsharp/service/FSharpCheckerResults.fs index 3fb85438d9d..f3c78473b27 100644 --- a/src/fsharp/service/FSharpCheckerResults.fs +++ b/src/fsharp/service/FSharpCheckerResults.fs @@ -1621,7 +1621,7 @@ module internal ParseAndCheckFile = | None -> // For non-scripts, check for disallow #r and #load. - ApplyMetaCommandsFromInputToTcConfig (tcConfig, parsedMainInput, Path.GetDirectoryName mainInputFileName, tcImports.DependencyProvider) |> ignore + ApplyMetaCommandsFromInputToTcConfig (tcConfig, parsedMainInput,Path.GetDirectoryName mainInputFileName) |> ignore // Type check a single file against an initial context, gleaning both errors and intellisense information. let CheckOneFile @@ -2161,8 +2161,8 @@ type FSharpCheckProjectResults type FsiInteractiveChecker(legacyReferenceResolver, reactorOps: IReactorOperations, tcConfig: TcConfig, - tcGlobals: TcGlobals, - tcImports: TcImports, + tcGlobals, + tcImports, tcState) = let keepAssemblyContents = false @@ -2192,9 +2192,7 @@ type FsiInteractiveChecker(legacyReferenceResolver, tcConfig.useSimpleResolution, tcConfig.useFsiAuxLib, tcConfig.useSdkRefs, new Lexhelp.LexResourceManager(), applyCompilerOptions, assumeDotNetFramework, - tryGetMetadataSnapshot=(fun _ -> None), - reduceMemoryUsage=reduceMemoryUsage, - dependencyProvider=tcImports.DependencyProvider) + tryGetMetadataSnapshot=(fun _ -> None), reduceMemoryUsage=reduceMemoryUsage) let! tcErrors, tcFileInfo = ParseAndCheckFile.CheckOneFile diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs index 85c4e36dcea..f60d85adfc1 100755 --- a/src/fsharp/service/IncrementalBuild.fs +++ b/src/fsharp/service/IncrementalBuild.fs @@ -26,8 +26,6 @@ open FSharp.Compiler.TypeChecker open FSharp.Compiler.TypedTree open FSharp.Compiler.TypedTreeOps -open Microsoft.DotNet.DependencyManager - open Internal.Utilities.Collections [] @@ -1222,12 +1220,9 @@ type RawFSharpAssemblyDataBackedByLanguageService (tcConfig, tcGlobals, tcState: /// Manages an incremental build graph for the build of a single F# project type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInputs, nonFrameworkResolutions, unresolvedReferences, tcConfig: TcConfig, projectDirectory, outfile, - assemblyName, niceNameGen: NiceNameGenerator, lexResourceManager, - sourceFiles, loadClosureOpt: LoadClosure option, - keepAssemblyContents, keepAllBackgroundResolutions, - maxTimeShareMilliseconds, keepAllBackgroundSymbolUses, - enableBackgroundItemKeyStoreAndSemanticClassification, - dependencyProviderOpt: DependencyProvider option) = + assemblyName, niceNameGen: NiceNameGenerator, lexResourceManager, + sourceFiles, loadClosureOpt: LoadClosure option, + keepAssemblyContents, keepAllBackgroundResolutions, maxTimeShareMilliseconds, keepAllBackgroundSymbolUses, enableBackgroundItemKeyStoreAndSemanticClassification) = let tcConfigP = TcConfigProvider.Constant tcConfig let fileParsed = new Event() @@ -1264,13 +1259,6 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput for (_, f, _) in sourceFiles do yield f |] - // For scripts, the dependency provider is already available. - // For projects create a fresh one for the project. - let dependencyProvider = - match dependencyProviderOpt with - | None -> new DependencyProvider(null, null) - | Some dependencyProvider -> dependencyProvider - //---------------------------------------------------- // START OF BUILD TASK FUNCTIONS @@ -1321,7 +1309,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput let! tcImports = cancellable { try - let! tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, nonFrameworkResolutions, unresolvedReferences, dependencyProvider) + let! tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, nonFrameworkResolutions, unresolvedReferences) #if !NO_EXTENSIONTYPING tcImports.GetCcusExcludingBase() |> Seq.iter (fun ccu -> // When a CCU reports an invalidation, merge them together and just report a @@ -1395,7 +1383,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput eventually { beforeFileChecked.Trigger filename - ApplyMetaCommandsFromInputToTcConfig (tcConfig, input, Path.GetDirectoryName filename, tcAcc.tcImports.DependencyProvider) |> ignore + ApplyMetaCommandsFromInputToTcConfig (tcConfig, input, Path.GetDirectoryName filename) |> ignore let sink = TcResultsSinkImpl(tcAcc.tcGlobals) let hadParseErrors = not (Array.isEmpty parseErrors) @@ -1752,7 +1740,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput /// CreateIncrementalBuilder (for background type checking). Note that fsc.fs also /// creates an incremental builder used by the command line compiler. - static member TryCreateIncrementalBuilderForProjectOptions + static member TryCreateBackgroundBuilderForProjectOptions (ctok, legacyReferenceResolver, defaultFSharpBinariesDir, frameworkTcImportsCache: FrameworkImportsCache, loadClosureOpt: LoadClosure option, @@ -1761,11 +1749,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput projectReferences, projectDirectory, useScriptResolutionRules, keepAssemblyContents, keepAllBackgroundResolutions, maxTimeShareMilliseconds, - tryGetMetadataSnapshot, suggestNamesForErrors, - keepAllBackgroundSymbolUses, - enableBackgroundItemKeyStoreAndSemanticClassification, - dependencyProviderOpt) = - + tryGetMetadataSnapshot, suggestNamesForErrors, keepAllBackgroundSymbolUses, enableBackgroundItemKeyStoreAndSemanticClassification) = let useSimpleResolutionSwitch = "--simpleresolution" cancellable { @@ -1880,16 +1864,14 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput yield Choice2Of2 pr, (fun (cache: TimeStampCache) ctok -> cache.GetProjectReferenceTimeStamp (pr, ctok)) ] let builder = - new IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInputs, - nonFrameworkResolutions, unresolvedReferences, - tcConfig, projectDirectory, outfile, assemblyName, niceNameGen, - resourceManager, sourceFilesNew, loadClosureOpt, - keepAssemblyContents, - keepAllBackgroundResolutions, - maxTimeShareMilliseconds, - keepAllBackgroundSymbolUses, - enableBackgroundItemKeyStoreAndSemanticClassification, - dependencyProviderOpt) + new IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInputs, nonFrameworkResolutions, unresolvedReferences, + tcConfig, projectDirectory, outfile, assemblyName, niceNameGen, + resourceManager, sourceFilesNew, loadClosureOpt, + keepAssemblyContents=keepAssemblyContents, + keepAllBackgroundResolutions=keepAllBackgroundResolutions, + maxTimeShareMilliseconds=maxTimeShareMilliseconds, + keepAllBackgroundSymbolUses=keepAllBackgroundSymbolUses, + enableBackgroundItemKeyStoreAndSemanticClassification=enableBackgroundItemKeyStoreAndSemanticClassification) return Some builder with e -> errorRecoveryNoRange e diff --git a/src/fsharp/service/IncrementalBuild.fsi b/src/fsharp/service/IncrementalBuild.fsi index c6bfe1e1f5a..e9f945cd970 100755 --- a/src/fsharp/service/IncrementalBuild.fsi +++ b/src/fsharp/service/IncrementalBuild.fsi @@ -16,8 +16,6 @@ open FSharp.Compiler.SyntaxTree open FSharp.Compiler.TcGlobals open FSharp.Compiler.TypedTree -open Microsoft.DotNet.DependencyManager - /// Lookup the global static cache for building the FrameworkTcImports type internal FrameworkImportsCache = new : size: int -> FrameworkImportsCache @@ -180,29 +178,9 @@ type internal IncrementalBuilder = /// Await the untyped parse results for a particular slot in the vector of parse results. /// /// This may be a marginally long-running operation (parses are relatively quick, only one file needs to be parsed) - member GetParseResultsForFile: CompilationThreadToken * filename:string -> Cancellable - - /// Create the incremental builder - static member TryCreateIncrementalBuilderForProjectOptions: - CompilationThreadToken * - ReferenceResolver.Resolver * - defaultFSharpBinariesDir: string * - FrameworkImportsCache * - scriptClosureOptions:LoadClosure option * - sourceFiles:string list * - commandLineArgs:string list * - projectReferences: IProjectReference list * - projectDirectory:string * - useScriptResolutionRules:bool * - keepAssemblyContents: bool * - keepAllBackgroundResolutions: bool * - maxTimeShareMilliseconds: int64 * - tryGetMetadataSnapshot: ILBinaryReader.ILReaderTryGetMetadataSnapshot * - suggestNamesForErrors: bool * - keepAllBackgroundSymbolUses: bool * - enableBackgroundItemKeyStoreAndSemanticClassification: bool * - dependencyProvider: DependencyProvider option - -> Cancellable + member GetParseResultsForFile : CompilationThreadToken * filename:string -> Cancellable + + static member TryCreateBackgroundBuilderForProjectOptions : CompilationThreadToken * ReferenceResolver.Resolver * defaultFSharpBinariesDir: string * FrameworkImportsCache * scriptClosureOptions:LoadClosure option * sourceFiles:string list * commandLineArgs:string list * projectReferences: IProjectReference list * projectDirectory:string * useScriptResolutionRules:bool * keepAssemblyContents: bool * keepAllBackgroundResolutions: bool * maxTimeShareMilliseconds: int64 * tryGetMetadataSnapshot: ILBinaryReader.ILReaderTryGetMetadataSnapshot * suggestNamesForErrors: bool * keepAllBackgroundSymbolUses: bool * enableBackgroundItemKeyStoreAndSemanticClassification: bool -> Cancellable /// Generalized Incremental Builder. This is exposed only for unit testing purposes. module internal IncrementalBuild = diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index 99e4cc388c4..246f6d7440e 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -24,8 +24,6 @@ open FSharp.Compiler.SyntaxTree open FSharp.Compiler.TcGlobals open FSharp.Compiler.Text -open Microsoft.DotNet.DependencyManager - open Internal.Utilities open Internal.Utilities.Collections @@ -276,14 +274,6 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC let scriptClosureCacheLock = Lock() let frameworkTcImportsCache = FrameworkImportsCache(frameworkTcImportsCacheStrongSize) - // We currently share one global dependency provider for all scripts for the FSharpChecker. - // For projects, one is used per project. - // - // Sharing one for all scripts is necessary for good performance from GetProjectOptionsFromScript, - // which requires a dependency provider to process through the project options prior to working out - // if the cached incremental builder can be used for the project. - let dependencyProviderForScripts = new DependencyProvider(null, null) - /// CreateOneIncrementalBuilder (for background type checking). Note that fsc.fs also /// creates an incremental builder used by the command line compiler. let CreateOneIncrementalBuilder (ctok, options:FSharpProjectOptions, userOpName) = @@ -311,15 +301,12 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC member x.FileName = nm } ] let loadClosure = scriptClosureCacheLock.AcquireLock (fun ltok -> scriptClosureCache.TryGet (ltok, options)) - let! builderOpt, diagnostics = - IncrementalBuilder.TryCreateIncrementalBuilderForProjectOptions + IncrementalBuilder.TryCreateBackgroundBuilderForProjectOptions (ctok, legacyReferenceResolver, FSharpCheckerResultsSettings.defaultFSharpBinariesDir, frameworkTcImportsCache, loadClosure, Array.toList options.SourceFiles, Array.toList options.OtherOptions, projectReferences, options.ProjectDirectory, options.UseScriptResolutionRules, keepAssemblyContents, keepAllBackgroundResolutions, FSharpCheckerResultsSettings.maxTimeShareMilliseconds, - tryGetMetadataSnapshot, suggestNamesForErrors, keepAllBackgroundSymbolUses, - enableBackgroundItemKeyStoreAndSemanticClassification, - (if options.UseScriptResolutionRules then Some dependencyProviderForScripts else None)) + tryGetMetadataSnapshot, suggestNamesForErrors, keepAllBackgroundSymbolUses, enableBackgroundItemKeyStoreAndSemanticClassification) match builderOpt with | None -> () @@ -830,7 +817,8 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC FSharpCheckerResultsSettings.defaultFSharpBinariesDir, filename, sourceText, CodeContext.Editing, useSimpleResolution, useFsiAuxLib, useSdkRefs, new Lexhelp.LexResourceManager(), applyCompilerOptions, assumeDotNetFramework, - tryGetMetadataSnapshot, reduceMemoryUsage, dependencyProviderForScripts) + tryGetMetadataSnapshot=tryGetMetadataSnapshot, + reduceMemoryUsage=reduceMemoryUsage) let otherFlags = [| yield "--noframework"; yield "--warn:3"; From a1f62980e79d745631f339764d8bcc4c750efef9 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Sun, 20 Sep 2020 00:20:58 +0100 Subject: [PATCH 05/12] one DependencyProvider per project --- src/fsharp/CompileOps.fs | 205 ++++++++++-------- src/fsharp/CompileOps.fsi | 93 ++++++-- .../FSharp.Compiler.Private.fsproj | 16 +- .../FSharp.Compiler.Service.fsproj | 16 +- .../DependencyProvider.fs | 23 +- .../DependencyProvider.fsi | 15 +- .../NativeDllResolveHandler.fs | 5 +- .../NativeDllResolveHandler.fsi | 2 +- src/fsharp/fsc.fs | 19 +- src/fsharp/fsi/fsi.fs | 55 ++++- src/fsharp/service/FSharpCheckerResults.fs | 10 +- src/fsharp/service/IncrementalBuild.fs | 48 ++-- src/fsharp/service/IncrementalBuild.fsi | 28 ++- src/fsharp/service/service.fs | 20 +- 14 files changed, 370 insertions(+), 185 deletions(-) diff --git a/src/fsharp/CompileOps.fs b/src/fsharp/CompileOps.fs index 63dba3fed83..cdf760b3f23 100644 --- a/src/fsharp/CompileOps.fs +++ b/src/fsharp/CompileOps.fs @@ -2308,8 +2308,6 @@ type TcConfigBuilder = mutable pathMap: PathMap mutable langVersion: LanguageVersion - - mutable dependencyProvider: DependencyProvider } static member Initial = @@ -2449,7 +2447,6 @@ type TcConfigBuilder = noConditionalErasure = false pathMap = PathMap.empty langVersion = LanguageVersion("default") - dependencyProvider = Unchecked.defaultof } // Directories to start probing in @@ -2459,13 +2456,17 @@ type TcConfigBuilder = // 2. compilerToolPath directories // 3. reference dll's // 4. The implicit include directory - member private tcConfigB.nativeProbingRoots () = + // + // NOTE: it is important this is a delayed IEnumerable sequence. It is recomputed + // each time a resolution happens and additional paths may be added as a result. + member tcConfigB.GetNativeProbingRoots () = seq { yield! tcConfigB.includes yield! tcConfigB.compilerToolPaths yield! (tcConfigB.referencedDLLs |> Seq.map(fun ref -> Path.GetDirectoryName(ref.Text))) yield tcConfigB.implicitIncludeDir - } |> Seq.distinct + } + |> Seq.distinct static member CreateNew(legacyReferenceResolver, defaultFSharpBinariesDir, reduceMemoryUsage, implicitIncludeDir, isInteractive, isInvalidationSupported, defaultCopyFSharpCore, tryGetMetadataSnapshot) = @@ -2487,7 +2488,6 @@ type TcConfigBuilder = tryGetMetadataSnapshot = tryGetMetadataSnapshot useFsiAuxLib = isInteractive } - tcConfigBuilder.dependencyProvider <- new DependencyProvider(NativeResolutionProbe(tcConfigBuilder.nativeProbingRoots)) tcConfigBuilder member tcConfigB.ResolveSourceFile(m, nm, pathLoadedFrom) = @@ -2599,6 +2599,32 @@ type TcConfigBuilder = member tcConfigB.AddDependencyManagerText (packageManager: IDependencyManagerProvider, lt, m, path: string) = tcConfigB.packageManagerLines <- PackageManagerLine.AddLineWithKey packageManager.Key lt path m tcConfigB.packageManagerLines + member tcConfigB.AddReferenceDirective (dependencyProvider: DependencyProvider, m, path: string, directive) = + let output = tcConfigB.outputDir |> Option.defaultValue "" + + let reportError = + ResolvingErrorReport (fun errorType err msg -> + let error = err, msg + match errorType with + | ErrorReportType.Warning -> warning(Error(error, m)) + | ErrorReportType.Error -> errorR(Error(error, m))) + + let dm = dependencyProvider.TryFindDependencyManagerInPath(tcConfigB.compilerToolPaths, output , reportError, path) + + match dm with + | _, dependencyManager when not(isNull dependencyManager) -> + if tcConfigB.langVersion.SupportsFeature(LanguageFeature.PackageManagement) then + tcConfigB.AddDependencyManagerText (dependencyManager, directive, m, path) + else + errorR(Error(FSComp.SR.packageManagementRequiresVFive(), m)) + + | _, _ when directive = Directive.Include -> + errorR(Error(FSComp.SR.poundiNotSupportedByRegisteredDependencyManagers(), m)) + + // #r "Assembly" + | path, _ -> + tcConfigB.AddReferencedAssemblyByPath (m, path) + member tcConfigB.RemoveReferencedAssemblyByPath (m, path) = tcConfigB.referencedDLLs <- tcConfigB.referencedDLLs |> List.filter (fun ar -> not (Range.equals ar.Range m) || ar.Text <> path) @@ -2920,8 +2946,6 @@ type TcConfig private (data: TcConfigBuilder, validate: bool) = member x.legacyReferenceResolver = data.legacyReferenceResolver - member x.dependencyProvider = data.dependencyProvider - member tcConfig.CloneOfOriginalBuilder = { data with conditionalCompilationDefines=data.conditionalCompilationDefines } @@ -3290,6 +3314,8 @@ type TcConfig private (data: TcConfigBuilder, validate: bool) = member tcConfig.CoreLibraryDllReference() = fslibReference + member tcConfig.GetNativeProbingRoots() = data.GetNativeProbingRoots() + let ReportWarning options err = warningOn err (options.WarnLevel) (options.WarnOn) && not (List.contains (GetDiagnosticNumber err) (options.WarnOff)) @@ -3999,7 +4025,9 @@ and TcImportsWeakHack (tcImports: WeakReference) = /// Represents a table of imported assemblies with their resolutions. /// Is a disposable object, but it is recommended not to explicitly call Dispose unless you absolutely know nothing will be using its contents after the disposal. /// Otherwise, simply allow the GC to collect this and it will properly call Dispose from the finalizer. -and [] TcImports(tcConfigP: TcConfigProvider, initialResolutions: TcAssemblyResolutions, importsBase: TcImports option, ilGlobalsOpt, compilationThread: ICompilationThread) as this = +and [] TcImports(tcConfigP: TcConfigProvider, initialResolutions: TcAssemblyResolutions, importsBase: TcImports option, + ilGlobalsOpt, compilationThread: ICompilationThread, + dependencyProviderOpt: DependencyProvider option) as this = let mutable resolutions = initialResolutions let mutable importsBase: TcImports option = importsBase @@ -4330,6 +4358,14 @@ and [] TcImports(tcConfigP: TcConfigProvider, initialResolutions: TcAsse | ILScopeRef.Assembly a -> a.Name = nm | _ -> false) + member tcImports.DependencyProvider = + CheckDisposed() + match dependencyProviderOpt with + | None -> + Debug.Assert(false, "this should never be called on FrameworkTcImports") + new DependencyProvider(null, null) + | Some dependencyProvider -> dependencyProvider + member tcImports.GetImportMap() = CheckDisposed() let loaderInterface = @@ -4893,7 +4929,7 @@ and [] TcImports(tcConfigP: TcConfigProvider, initialResolutions: TcAsse let tcResolutions = TcAssemblyResolutions.BuildFromPriorResolutions(ctok, tcConfig, frameworkDLLs, []) let tcAltResolutions = TcAssemblyResolutions.BuildFromPriorResolutions(ctok, tcConfig, nonFrameworkDLLs, []) - let frameworkTcImports = new TcImports(tcConfigP, tcResolutions, None, None, tcConfig.compilationThread) + let frameworkTcImports = new TcImports(tcConfigP, tcResolutions, None, None, tcConfig.compilationThread, None) // Fetch the primaryAssembly from the referenced assemblies otherwise let primaryAssemblyReference = @@ -5019,24 +5055,27 @@ and [] TcImports(tcConfigP: TcConfigProvider, initialResolutions: TcAsse |> List.map (function UnresolvedAssemblyReference(file, originalReferences) -> file, originalReferences) |> List.iter reportAssemblyNotResolved - static member BuildNonFrameworkTcImports (ctok, tcConfigP: TcConfigProvider, tcGlobals: TcGlobals, baseTcImports, nonFrameworkReferences, knownUnresolved) = + static member BuildNonFrameworkTcImports + (ctok, tcConfigP: TcConfigProvider, tcGlobals: TcGlobals, baseTcImports, + nonFrameworkReferences, knownUnresolved, dependencyProvider) = + cancellable { let tcConfig = tcConfigP.Get ctok let tcResolutions = TcAssemblyResolutions.BuildFromPriorResolutions(ctok, tcConfig, nonFrameworkReferences, knownUnresolved) let references = tcResolutions.GetAssemblyResolutions() - let tcImports = new TcImports(tcConfigP, tcResolutions, Some baseTcImports, Some tcGlobals.ilg, tcConfig.compilationThread) + let tcImports = new TcImports(tcConfigP, tcResolutions, Some baseTcImports, Some tcGlobals.ilg, tcConfig.compilationThread, Some dependencyProvider) let! _assemblies = tcImports.RegisterAndImportReferencedAssemblies(ctok, references) tcImports.ReportUnresolvedAssemblyReferences knownUnresolved return tcImports } - static member BuildTcImports(ctok, tcConfigP: TcConfigProvider) = + static member BuildTcImports(ctok, tcConfigP: TcConfigProvider, dependencyProvider) = cancellable { let tcConfig = tcConfigP.Get ctok //let foundationalTcImports, tcGlobals = TcImports.BuildFoundationalTcImports tcConfigP let frameworkDLLs, nonFrameworkReferences, knownUnresolved = TcAssemblyResolutions.SplitNonFoundationalResolutions(ctok, tcConfig) let! tcGlobals, frameworkTcImports = TcImports.BuildFrameworkTcImports (ctok, tcConfigP, frameworkDLLs, nonFrameworkReferences) - let! tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, nonFrameworkReferences, knownUnresolved) + let! tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, nonFrameworkReferences, knownUnresolved, dependencyProvider) return tcGlobals, tcImports } @@ -5066,10 +5105,12 @@ let RequireDLL (ctok, tcImports: TcImports, tcEnv, thisAssemblyName, m, file) = let ProcessMetaCommandsFromInput (nowarnF: 'state -> range * string -> 'state, - dllRequireF: 'state -> range * string -> 'state, - packageRequireF: 'state -> IDependencyManagerProvider * Directive * range * string -> 'state, + hashReferenceF: 'state -> range * string * Directive -> 'state, loadSourceF: 'state -> range * string -> unit) - (tcConfig:TcConfigBuilder, inp, pathOfMetaCommandSource, state0) = + (tcConfig:TcConfigBuilder, + inp: ParsedInput, + pathOfMetaCommandSource, + state0) = use unwindBuildPhase = PushThreadBuildPhaseUntilUnwind BuildPhase.Parse @@ -5078,50 +5119,25 @@ let ProcessMetaCommandsFromInput | ParsedInput.SigFile (_) -> false | ParsedInput.ImplFile (ParsedImplFileInput (isScript = isScript)) -> isScript - let ProcessMetaCommand state hash = - let mutable matchedm = range0 - try - let processDependencyManagerDirectives directive args m = - if not canHaveScriptMetaCommands then - errorR(HashReferenceNotAllowedInNonScript m) - - let reportError = - let report errorType err msg = - let error = err, msg - match errorType with - | ErrorReportType.Warning -> warning(Error(error, m)) - | ErrorReportType.Error -> errorR(Error(error, m)) - ResolvingErrorReport (report) - - match args with - | [path] -> - matchedm <- m - let output = tcConfig.outputDir |> Option.defaultValue "" - let dm = tcConfig.dependencyProvider.TryFindDependencyManagerInPath(tcConfig.compilerToolPaths, output , reportError, path) - match dm with - | _, dependencyManager when not(isNull dependencyManager) -> - if tcConfig.langVersion.SupportsFeature(LanguageFeature.PackageManagement) then - packageRequireF state (dependencyManager, directive, m, path) - else - errorR(Error(FSComp.SR.packageManagementRequiresVFive(), m)) - state - - | _, _ when directive = Directive.Include -> - errorR(Error(FSComp.SR.poundiNotSupportedByRegisteredDependencyManagers(), m)) - state + let ProcessDependencyManagerDirective directive args m state = + if not canHaveScriptMetaCommands then + errorR(HashReferenceNotAllowedInNonScript m) - // #r "Assembly" - | path, _ -> - let p = - if String.IsNullOrWhiteSpace(path) then "" - else path + match args with + | [path] -> + let p = + if String.IsNullOrWhiteSpace(path) then "" + else path - dllRequireF state (m, p) + hashReferenceF state (m, p, directive) - | _ -> - errorR(Error(FSComp.SR.buildInvalidHashrDirective(), m)) - state + | _ -> + errorR(Error(FSComp.SR.buildInvalidHashrDirective(), m)) + state + let ProcessMetaCommand state hash = + let mutable matchedm = range0 + try match hash with | ParsedHashDirective("I", args, m) -> if not canHaveScriptMetaCommands then @@ -5138,10 +5154,12 @@ let ProcessMetaCommandsFromInput List.fold (fun state d -> nowarnF state (m,d)) state numbers | ParsedHashDirective(("reference" | "r"), args, m) -> - processDependencyManagerDirectives Directive.Resolution args m + matchedm<-m + ProcessDependencyManagerDirective Directive.Resolution args m state | ParsedHashDirective(("i"), args, m) -> - processDependencyManagerDirectives Directive.Include args m + matchedm<-m + ProcessDependencyManagerDirective Directive.Include args m state | ParsedHashDirective("load", args, m) -> if not canHaveScriptMetaCommands then @@ -5217,20 +5235,22 @@ let ApplyNoWarnsToTcConfig (tcConfig: TcConfig, inp: ParsedInput, pathOfMetaComm // Clone let tcConfigB = tcConfig.CloneOfOriginalBuilder let addNoWarn = fun () (m,s) -> tcConfigB.TurnWarningOff(m, s) - let addReferencedAssemblyByPath = fun () (_m,_s) -> () - let addDependencyManagerText = fun () (_prefix, _lt, _m, _s) -> () - let addLoadedSource = fun () (_m,_s) -> () - ProcessMetaCommandsFromInput (addNoWarn, addReferencedAssemblyByPath, addDependencyManagerText, addLoadedSource) (tcConfigB, inp, pathOfMetaCommandSource, ()) + let addReference = fun () (_m, _s, _) -> () + let addLoadedSource = fun () (_m, _s) -> () + ProcessMetaCommandsFromInput + (addNoWarn, addReference, addLoadedSource) + (tcConfigB, inp, pathOfMetaCommandSource, ()) TcConfig.Create(tcConfigB, validate=false) -let ApplyMetaCommandsFromInputToTcConfig (tcConfig: TcConfig, inp: ParsedInput, pathOfMetaCommandSource) = +let ApplyMetaCommandsFromInputToTcConfig (tcConfig: TcConfig, inp: ParsedInput, pathOfMetaCommandSource, dependencyProvider) = // Clone let tcConfigB = tcConfig.CloneOfOriginalBuilder let getWarningNumber = fun () _ -> () - let addReferencedAssemblyByPath = fun () (m,s) -> tcConfigB.AddReferencedAssemblyByPath(m,s) - let addDependencyManagerText = fun () (packageManager, lt, m,s) -> tcConfigB.AddDependencyManagerText(packageManager, lt, m, s) + let addReferenceDirective = fun () (m, path, directive) -> tcConfigB.AddReferenceDirective(dependencyProvider, m, path, directive) let addLoadedSource = fun () (m,s) -> tcConfigB.AddLoadedSource(m,s,pathOfMetaCommandSource) - ProcessMetaCommandsFromInput (getWarningNumber, addReferencedAssemblyByPath, addDependencyManagerText, addLoadedSource) (tcConfigB, inp, pathOfMetaCommandSource, ()) + ProcessMetaCommandsFromInput + (getWarningNumber, addReferenceDirective, addLoadedSource) + (tcConfigB, inp, pathOfMetaCommandSource, ()) TcConfig.Create(tcConfigB, validate=false) //---------------------------------------------------------------------------- @@ -5334,8 +5354,8 @@ module ScriptPreprocessClosure = let tcConfigB = TcConfigBuilder.CreateNew (legacyReferenceResolver, defaultFSharpBinariesDir, reduceMemoryUsage, projectDir, - isInteractive, isInvalidationSupported, defaultCopyFSharpCore=CopyFSharpCoreFlag.No, - tryGetMetadataSnapshot=tryGetMetadataSnapshot) + isInteractive, isInvalidationSupported, CopyFSharpCoreFlag.No, + tryGetMetadataSnapshot) applyCommandLineArgs tcConfigB @@ -5372,16 +5392,16 @@ module ScriptPreprocessClosure = [] let ApplyMetaCommandsFromInputToTcConfigAndGatherNoWarn - (tcConfig: TcConfig, inp: ParsedInput, pathOfMetaCommandSource) = + (tcConfig: TcConfig, inp: ParsedInput, + pathOfMetaCommandSource, dependencyProvider) = let tcConfigB = tcConfig.CloneOfOriginalBuilder let mutable nowarns = [] let getWarningNumber = fun () (m, s) -> nowarns <- (s, m) :: nowarns - let addReferencedAssemblyByPath = fun () (m, s) -> tcConfigB.AddReferencedAssemblyByPath(m, s) - let addDependencyManagerText = fun () (packageManagerPrefix, lt, m, s) -> tcConfigB.AddDependencyManagerText(packageManagerPrefix, lt, m, s) + let addReferenceDirective = fun () (m, s, directive) -> tcConfigB.AddReferenceDirective(dependencyProvider, m, s, directive) let addLoadedSource = fun () (m, s) -> tcConfigB.AddLoadedSource(m, s, pathOfMetaCommandSource) try - ProcessMetaCommandsFromInput (getWarningNumber, addReferencedAssemblyByPath, addDependencyManagerText, addLoadedSource) (tcConfigB, inp, pathOfMetaCommandSource, ()) + ProcessMetaCommandsFromInput (getWarningNumber, addReferenceDirective, addLoadedSource) (tcConfigB, inp, pathOfMetaCommandSource, ()) with ReportedError _ -> // Recover by using whatever did end up in the tcConfig () @@ -5393,7 +5413,10 @@ module ScriptPreprocessClosure = let tcConfigB = tcConfig.CloneOfOriginalBuilder TcConfig.Create(tcConfigB, validate=false), nowarns - let FindClosureFiles(mainFile, _m, closureSources, origTcConfig:TcConfig, codeContext, lexResourceManager: Lexhelp.LexResourceManager) = + let FindClosureFiles + (mainFile, _m, closureSources, origTcConfig:TcConfig, + codeContext, lexResourceManager: Lexhelp.LexResourceManager, dependencyProvider: DependencyProvider) = + let mutable tcConfig = origTcConfig let observedSources = Observed() @@ -5408,20 +5431,19 @@ module ScriptPreprocessClosure = | [] -> () | { Directive=_; LineStatus=_; Line=_; Range=m } :: _ -> let reportError = - let report errorType err msg = + ResolvingErrorReport (fun errorType err msg -> let error = err, msg match errorType with | ErrorReportType.Warning -> warning(Error(error, m)) - | ErrorReportType.Error -> errorR(Error(error, m)) - ResolvingErrorReport (report) + | ErrorReportType.Error -> errorR(Error(error, m))) match origTcConfig.packageManagerLines |> Map.tryFind packageManagerKey with | Some oldDependencyManagerLines when oldDependencyManagerLines = packageManagerLines -> () | _ -> let outputDir = tcConfig.outputDir |> Option.defaultValue "" - match tcConfig.dependencyProvider.TryFindDependencyManagerByKey(tcConfig.compilerToolPaths, outputDir, reportError, packageManagerKey) with + match dependencyProvider.TryFindDependencyManagerByKey(tcConfig.compilerToolPaths, outputDir, reportError, packageManagerKey) with | null -> - errorR(Error(tcConfig.dependencyProvider.CreatePackageManagerUnknownError(tcConfig.compilerToolPaths, outputDir, packageManagerKey, reportError), m)) + errorR(Error(dependencyProvider.CreatePackageManagerUnknownError(tcConfig.compilerToolPaths, outputDir, packageManagerKey, reportError), m)) | dependencyManager -> let directive d = @@ -5430,7 +5452,7 @@ module ScriptPreprocessClosure = | Directive.Include -> "i" let packageManagerTextLines = packageManagerLines |> List.map(fun l -> directive l.Directive, l.Line) - let result = tcConfig.dependencyProvider.Resolve(dependencyManager, ".fsx", packageManagerTextLines, reportError, executionTfm, executionRid, tcConfig.implicitIncludeDir, mainFile, scriptName) + let result = dependencyProvider.Resolve(dependencyManager, ".fsx", packageManagerTextLines, reportError, executionTfm, executionRid, tcConfig.implicitIncludeDir, mainFile, scriptName) match result.Success with | true -> // Resolution produced no errors @@ -5472,7 +5494,7 @@ module ScriptPreprocessClosure = let pathOfMetaCommandSource = Path.GetDirectoryName filename let preSources = tcConfig.GetAvailableLoadedSources() - let tcConfigResult, noWarns = ApplyMetaCommandsFromInputToTcConfigAndGatherNoWarn (tcConfig, parsedScriptAst, pathOfMetaCommandSource) + let tcConfigResult, noWarns = ApplyMetaCommandsFromInputToTcConfigAndGatherNoWarn (tcConfig, parsedScriptAst, pathOfMetaCommandSource, dependencyProvider) tcConfig <- tcConfigResult // We accumulate the tcConfig in order to collect assembly references yield! resolveDependencyManagerSources filename @@ -5582,7 +5604,7 @@ module ScriptPreprocessClosure = useSimpleResolution, useFsiAuxLib, useSdkRefs, lexResourceManager: Lexhelp.LexResourceManager, applyCommandLineArgs, assumeDotNetFramework, - tryGetMetadataSnapshot, reduceMemoryUsage) = + tryGetMetadataSnapshot, reduceMemoryUsage, dependencyProvider) = // Resolve the basic references such as FSharp.Core.dll first, before processing any #I directives in the script // @@ -5606,15 +5628,18 @@ module ScriptPreprocessClosure = tryGetMetadataSnapshot, reduceMemoryUsage) let closureSources = [ClosureSource(filename, range0, sourceText, true)] - let closureFiles, tcConfig = FindClosureFiles(filename, range0, closureSources, tcConfig, codeContext, lexResourceManager) + let closureFiles, tcConfig = FindClosureFiles(filename, range0, closureSources, tcConfig, codeContext, lexResourceManager, dependencyProvider) GetLoadClosure(ctok, filename, closureFiles, tcConfig, codeContext) /// Given source filename, find the full load closure /// Used from fsi.fs and fsc.fs, for #load and command line - let GetFullClosureOfScriptFiles(ctok, tcConfig:TcConfig, files:(string*range) list,codeContext,lexResourceManager: Lexhelp.LexResourceManager) = + let GetFullClosureOfScriptFiles + (ctok, tcConfig:TcConfig, files:(string*range) list, codeContext, + lexResourceManager: Lexhelp.LexResourceManager, dependencyProvider) = + let mainFile, mainFileRange = List.last files let closureSources = files |> List.collect (fun (filename, m) -> ClosureSourceOfFilename(filename, m,tcConfig.inputCodePage,true)) - let closureFiles,tcConfig = FindClosureFiles(mainFile, mainFileRange, closureSources, tcConfig, codeContext, lexResourceManager) + let closureFiles,tcConfig = FindClosureFiles(mainFile, mainFileRange, closureSources, tcConfig, codeContext, lexResourceManager, dependencyProvider) GetLoadClosure(ctok, mainFile, closureFiles, tcConfig, codeContext) type LoadClosure with @@ -5627,20 +5652,22 @@ type LoadClosure with (ctok, legacyReferenceResolver, defaultFSharpBinariesDir, filename: string, sourceText: ISourceText, codeContext, useSimpleResolution: bool, useFsiAuxLib, useSdkRefs, lexResourceManager: Lexhelp.LexResourceManager, - applyCommandLineArgs, assumeDotNetFramework, tryGetMetadataSnapshot, reduceMemoryUsage) = + applyCommandLineArgs, assumeDotNetFramework, tryGetMetadataSnapshot, + reduceMemoryUsage, dependencyProvider) = use unwindBuildPhase = PushThreadBuildPhaseUntilUnwind BuildPhase.Parse ScriptPreprocessClosure.GetFullClosureOfScriptText (ctok, legacyReferenceResolver, defaultFSharpBinariesDir, filename, sourceText, codeContext, useSimpleResolution, useFsiAuxLib, useSdkRefs, lexResourceManager, - applyCommandLineArgs, assumeDotNetFramework, tryGetMetadataSnapshot, reduceMemoryUsage) + applyCommandLineArgs, assumeDotNetFramework, tryGetMetadataSnapshot, reduceMemoryUsage, dependencyProvider) /// Analyze a set of script files and find the closure of their references. static member ComputeClosureOfScriptFiles (ctok, tcConfig: TcConfig, files:(string*range) list, codeContext, - lexResourceManager: Lexhelp.LexResourceManager) = + lexResourceManager: Lexhelp.LexResourceManager, dependencyProvider) = + use unwindBuildPhase = PushThreadBuildPhaseUntilUnwind BuildPhase.Parse - ScriptPreprocessClosure.GetFullClosureOfScriptFiles (ctok, tcConfig, files, codeContext, lexResourceManager) + ScriptPreprocessClosure.GetFullClosureOfScriptFiles (ctok, tcConfig, files, codeContext, lexResourceManager, dependencyProvider) //---------------------------------------------------------------------------- // Initial type checking environment diff --git a/src/fsharp/CompileOps.fsi b/src/fsharp/CompileOps.fsi index ebedf48153d..9725f135ac6 100644 --- a/src/fsharp/CompileOps.fsi +++ b/src/fsharp/CompileOps.fsi @@ -413,8 +413,6 @@ type TcConfigBuilder = mutable pathMap : PathMap mutable langVersion : LanguageVersion - - mutable dependencyProvider: DependencyProvider } static member Initial: TcConfigBuilder @@ -443,6 +441,9 @@ type TcConfigBuilder = static member SplitCommandLineResourceInfo: string -> string * string * ILResourceAccess + // Directories to start probing in for native DLLs for FSI dynamic loading + member GetNativeProbingRoots: unit -> seq + [] // Immutable TcConfig type TcConfig = @@ -559,8 +560,8 @@ type TcConfig = member isInteractive: bool member isInvalidationSupported: bool - member ComputeLightSyntaxInitialStatus: string -> bool + member GetTargetFrameworkDirectories: unit -> string list /// Get the loaded sources that exist and issue a warning for the ones that don't @@ -575,8 +576,11 @@ type TcConfig = member MakePathAbsolute: string -> string member copyFSharpCore: CopyFSharpCoreFlag + member shadowCopyReferences: bool + member useSdkRefs: bool + member langVersion: LanguageVersion static member Create: TcConfigBuilder * validate: bool -> TcConfig @@ -640,18 +644,28 @@ type TcImports = interface System.IDisposable //new: TcImports option -> TcImports member DllTable: NameMap with get + member GetImportedAssemblies: unit -> ImportedAssembly list + member GetCcusInDeclOrder: unit -> CcuThunk list + /// This excludes any framework imports (which may be shared between multiple builds) member GetCcusExcludingBase: unit -> CcuThunk list + member FindDllInfo: CompilationThreadToken * range * string -> ImportedBinary + member TryFindDllInfo: CompilationThreadToken * range * string * lookupOnly: bool -> option + member FindCcuFromAssemblyRef: CompilationThreadToken * range * ILAssemblyRef -> CcuResolutionResult + #if !NO_EXTENSIONTYPING member ProviderGeneratedTypeRoots: ProviderGeneratedType list #endif + member GetImportMap: unit -> Import.ImportMap + member DependencyProvider: DependencyProvider + /// Try to resolve a referenced assembly based on TcConfig settings. member TryResolveAssemblyReference: CompilationThreadToken * AssemblyReference * ResolveAssemblyReferenceMode -> OperationResult @@ -671,13 +685,33 @@ type TcImports = #endif /// Report unresolved references that also weren't consumed by any type providers. member ReportUnresolvedAssemblyReferences: UnresolvedAssemblyReference list -> unit + member SystemRuntimeContainsType: string -> bool member internal Base: TcImports option - static member BuildFrameworkTcImports : CompilationThreadToken * TcConfigProvider * AssemblyResolution list * AssemblyResolution list -> Cancellable - static member BuildNonFrameworkTcImports : CompilationThreadToken * TcConfigProvider * TcGlobals * TcImports * AssemblyResolution list * UnresolvedAssemblyReference list -> Cancellable - static member BuildTcImports : CompilationThreadToken * TcConfigProvider -> Cancellable + static member BuildFrameworkTcImports: + CompilationThreadToken * + TcConfigProvider * + AssemblyResolution list * + AssemblyResolution list + -> Cancellable + + static member BuildNonFrameworkTcImports: + CompilationThreadToken * + TcConfigProvider * + TcGlobals * + TcImports * + AssemblyResolution list * + UnresolvedAssemblyReference list * + DependencyProvider + -> Cancellable + + static member BuildTcImports: + CompilationThreadToken * + TcConfigProvider * + DependencyProvider + -> Cancellable //---------------------------------------------------------------------------- // Special resources in DLLs @@ -703,24 +737,22 @@ val WriteOptimizationData: TcGlobals * filename: string * inMem: bool * CcuThunk // #r and other directives //-------------------------------------------------------------------------- -//---------------------------------------------------------------------------- -// #r and other directives -//-------------------------------------------------------------------------- - /// Process #r in F# Interactive. /// Adds the reference to the tcImports and add the ccu to the type checking environment. val RequireDLL: CompilationThreadToken * TcImports * TcEnv * thisAssemblyName: string * referenceRange: range * file: string -> TcEnv * (ImportedBinary list * ImportedAssembly list) -/// Processing # commands +/// A general routine to process hash directives val ProcessMetaCommandsFromInput : - (('T -> range * string -> 'T) * ('T -> range * string -> 'T) * ('T -> IDependencyManagerProvider * Directive * range * string -> 'T) * ('T -> range * string -> unit)) - -> TcConfigBuilder * ParsedInput * string * 'T - -> 'T + (('T -> range * string -> 'T) * + ('T -> range * string * Directive -> 'T) * + ('T -> range * string -> unit)) + -> TcConfigBuilder * ParsedInput * string * 'T + -> 'T -/// Process all the #r, #I etc. in an input -val ApplyMetaCommandsFromInputToTcConfig: TcConfig * ParsedInput * string -> TcConfig +/// Process all the #r, #I etc. in an input. For non-scripts report warnings about ignored directives. +val ApplyMetaCommandsFromInputToTcConfig: TcConfig * ParsedInput * string * DependencyProvider -> TcConfig -/// Process the #nowarn in an input +/// Process the #nowarn in an input and integrate them into the TcConfig val ApplyNoWarnsToTcConfig: TcConfig * ParsedInput * string -> TcConfig //---------------------------------------------------------------------------- @@ -853,8 +885,31 @@ type LoadClosure = // /// A temporary TcConfig is created along the way, is why this routine takes so many arguments. We want to be sure to use exactly the /// same arguments as the rest of the application. - static member ComputeClosureOfScriptText: CompilationThreadToken * legacyReferenceResolver: ReferenceResolver.Resolver * defaultFSharpBinariesDir: string * filename: string * sourceText: ISourceText * implicitDefines:CodeContext * useSimpleResolution: bool * useFsiAuxLib: bool * useSdkRefs: bool * lexResourceManager: Lexhelp.LexResourceManager * applyCompilerOptions: (TcConfigBuilder -> unit) * assumeDotNetFramework: bool * tryGetMetadataSnapshot: ILReaderTryGetMetadataSnapshot * reduceMemoryUsage: ReduceMemoryFlag -> LoadClosure + static member ComputeClosureOfScriptText: + CompilationThreadToken * + legacyReferenceResolver: ReferenceResolver.Resolver * + defaultFSharpBinariesDir: string * + filename: string * + sourceText: ISourceText * + implicitDefines:CodeContext * + useSimpleResolution: bool * + useFsiAuxLib: bool * + useSdkRefs: bool * + lexResourceManager: Lexhelp.LexResourceManager * + applyCompilerOptions: (TcConfigBuilder -> unit) * + assumeDotNetFramework: bool * + tryGetMetadataSnapshot: ILReaderTryGetMetadataSnapshot * + reduceMemoryUsage: ReduceMemoryFlag * + dependencyProvider: DependencyProvider + -> LoadClosure /// Analyze a set of script files and find the closure of their references. The resulting references are then added to the given TcConfig. /// Used from fsi.fs and fsc.fs, for #load and command line. - static member ComputeClosureOfScriptFiles: CompilationThreadToken * tcConfig:TcConfig * (string * range) list * implicitDefines:CodeContext * lexResourceManager: Lexhelp.LexResourceManager -> LoadClosure + static member ComputeClosureOfScriptFiles: + CompilationThreadToken * + tcConfig:TcConfig * + (string * range) list * + implicitDefines:CodeContext * + lexResourceManager: Lexhelp.LexResourceManager * + dependencyProvider: DependencyProvider + -> LoadClosure diff --git a/src/fsharp/FSharp.Compiler.Private/FSharp.Compiler.Private.fsproj b/src/fsharp/FSharp.Compiler.Private/FSharp.Compiler.Private.fsproj index aa0b3e9edbc..78ebbfc4fca 100644 --- a/src/fsharp/FSharp.Compiler.Private/FSharp.Compiler.Private.fsproj +++ b/src/fsharp/FSharp.Compiler.Private/FSharp.Compiler.Private.fsproj @@ -58,12 +58,6 @@ FSStrings.resx - - Logger.fsi - - - Logger.fs - ErrorText\sformat.fsi @@ -76,11 +70,17 @@ ErrorText\sr.fs + + Facilities\Logger.fsi + + + Facilities\Logger.fs + - Driver\LanguageFeatures.fsi + Facilities\LanguageFeatures.fsi - Driver\LanguageFeatures.fs + Facilities\LanguageFeatures.fs LexYaccRuntime\prim-lexing.fsi diff --git a/src/fsharp/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj b/src/fsharp/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj index 9d1b6851ac0..b1f2c20fc07 100644 --- a/src/fsharp/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj +++ b/src/fsharp/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj @@ -58,12 +58,6 @@ FSStrings.resx FSStrings.resources - - Logger.fsi - - - Logger.fs - ErrorText\sformat.fsi @@ -76,11 +70,17 @@ ErrorText\sr.fs + + Facilities\Logger.fsi + + + Facilities\Logger.fs + - Driver\LanguageFeatures.fsi + Facilities\LanguageFeatures.fsi - Driver\LanguageFeatures.fs + Facilities\LanguageFeatures.fs LexYaccRuntime\prim-lexing.fsi diff --git a/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs b/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs index c3c7046ef29..be24bd46432 100644 --- a/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs +++ b/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs @@ -68,19 +68,14 @@ module ReflectionHelper = e.InnerException | _ -> e -open ReflectionHelper -open RidHelpers - /// Indicate the type of error to report [] type ErrorReportType = | Warning | Error - type ResolvingErrorReport = delegate of ErrorReportType * int * string -> unit - (* Shape of Dependency Manager contract, resolved using reflection *) /// The results of ResolveDependencies type IResolveDependenciesResult = @@ -268,9 +263,17 @@ type ReflectionDependencyManagerProvider(theType: Type, /// Class is IDisposable type DependencyProvider (assemblyProbingPaths: AssemblyResolutionProbe, nativeProbingRoots: NativeResolutionProbe) = - let dllResolveHandler = new NativeDllResolveHandler(nativeProbingRoots) :> IDisposable + // Note: creating a NativeDllResolveHandler currently installs process-wide handlers + let dllResolveHandler = + match assemblyProbingPaths with + | null -> { new IDisposable with member _.Dispose() = () } + | _ -> new NativeDllResolveHandler(nativeProbingRoots) :> IDisposable - let assemblyResolveHandler = new AssemblyResolveHandler(assemblyProbingPaths) :> IDisposable + // Note: creating a AssemblyResolveHandler currently installs process-wide handlers + let assemblyResolveHandler = + match assemblyProbingPaths with + | null -> { new IDisposable with member _.Dispose() = () } + | _ -> new AssemblyResolveHandler(assemblyProbingPaths) :> IDisposable // Resolution Path = Location of FSharp.Compiler.Private.dll let assemblySearchPaths = lazy ( @@ -329,9 +332,9 @@ type DependencyProvider (assemblyProbingPaths: AssemblyResolutionProbe, nativePr let cache = ConcurrentDictionary<_,IResolveDependenciesResult>(HashIdentity.Structural) - /// Returns a formatted error message for the host to presentconstruct with just nativeProbing handler - new (nativeProbingRoots: NativeResolutionProbe) = - new DependencyProvider(Unchecked.defaultof, nativeProbingRoots) + new (nativeProbingRoots: NativeResolutionProbe) = new DependencyProvider(null, nativeProbingRoots) + + new () = new DependencyProvider(null, null) /// Returns a formatted help messages for registered dependencymanagers for the host to present member _.GetRegisteredDependencyManagerHelpText (compilerTools, outputDir, errorReport) = [| diff --git a/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fsi b/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fsi index 2f16b59fd99..aa9b38f88ba 100644 --- a/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fsi +++ b/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fsi @@ -56,16 +56,23 @@ type ErrorReportType = type ResolvingErrorReport = delegate of ErrorReportType * int * string -> unit /// Provides DependencyManagement functions. -/// Class is IDisposable +/// +/// The class incrementally collects IDependencyManagerProvider, indexed by key, and +/// queries them. These are found and instantiated with respect to the compilerTools and outputDir +/// provided each time the TryFindDependencyManagerByKey and TryFindDependencyManagerInPath are +/// executed, which are assumed to be invariant over the lifetime of the DependencyProvider. type DependencyProvider = interface System.IDisposable - /// Construct a new DependencyProvider - new: assemblyProbingPaths: AssemblyResolutionProbe * nativeProbingRoots: NativeResolutionProbe -> DependencyProvider + /// Construct a new DependencyProvider with no dynamic load handlers (only for compilation/analysis) + new: unit -> DependencyProvider - /// Construct a new DependencyProvider + /// Construct a new DependencyProvider with only native resolution new: nativeProbingRoots: NativeResolutionProbe -> DependencyProvider + /// Construct a new DependencyProvider with managed and native resolution + new: assemblyProbingPaths: AssemblyResolutionProbe * nativeProbingRoots: NativeResolutionProbe -> DependencyProvider + /// Returns a formatted help messages for registered dependencymanagers for the host to present member GetRegisteredDependencyManagerHelpText: string seq * string * ResolvingErrorReport -> string[] diff --git a/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fs b/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fs index 60b52982cc5..6a4477631c0 100644 --- a/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fs +++ b/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fs @@ -101,8 +101,9 @@ type NativeDllResolveHandlerCoreClr (_nativeProbingRoots: NativeResolutionProbe) let probe = match _nativeProbingRoots with | null -> None - | _ -> _nativeProbingRoots.Invoke() - |> Seq.tryPick(fun root -> + | _ -> + _nativeProbingRoots.Invoke() + |> Seq.tryPick(fun root -> probingFileNames name |> Seq.tryPick(fun name -> let path = Path.Combine(root, name) if File.Exists(path) then diff --git a/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fsi b/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fsi index c98b5f142e7..d1aa22fe49c 100644 --- a/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fsi +++ b/src/fsharp/Microsoft.DotNet.DependencyManager/NativeDllResolveHandler.fsi @@ -18,7 +18,7 @@ type NativeResolutionProbe = delegate of Unit -> seq // Cut down AssemblyLoadContext, for loading native libraries type NativeDllResolveHandler = - /// Construct a new DependencyProvider + /// Construct a new NativeDllResolveHandler new: nativeProbingRoots: NativeResolutionProbe -> NativeDllResolveHandler interface IDisposable diff --git a/src/fsharp/fsc.fs b/src/fsharp/fsc.fs index 4892c4a07fb..f30e913a7a4 100644 --- a/src/fsharp/fsc.fs +++ b/src/fsharp/fsc.fs @@ -50,6 +50,7 @@ open FSharp.Compiler.TypedTreeOps open FSharp.Compiler.TcGlobals open FSharp.Compiler.TypeChecker open FSharp.Compiler.XmlDoc +open Microsoft.DotNet.DependencyManager open FSharp.Compiler.AbstractIL.Internal.StrongNameSign @@ -202,7 +203,7 @@ let TypeCheck (ctok, tcConfig, tcImports, tcGlobals, errorLogger: ErrorLogger, a exiter.Exit 1 /// Check for .fsx and, if present, compute the load closure for of #loaded files. -let AdjustForScriptCompile(ctok, tcConfigB: TcConfigBuilder, commandLineSourceFiles, lexResourceManager) = +let AdjustForScriptCompile(ctok, tcConfigB: TcConfigBuilder, commandLineSourceFiles, lexResourceManager, dependencyProvider) = let combineFilePath file = try @@ -227,7 +228,8 @@ let AdjustForScriptCompile(ctok, tcConfigB: TcConfigBuilder, commandLineSourceFi if IsScript filename then let closure = LoadClosure.ComputeClosureOfScriptFiles - (ctok, tcConfig, [filename, rangeStartup], CodeContext.Compilation, lexResourceManager=lexResourceManager) + (ctok, tcConfig, [filename, rangeStartup], CodeContext.Compilation, + lexResourceManager, dependencyProvider) // Record the references from the analysis of the script. The full resolutions are recorded as the corresponding #I paths used to resolve them // are local to the scripts and not added to the tcConfigB (they are added to localized clones of the tcConfigB). @@ -1763,6 +1765,8 @@ let main0(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, // Share intern'd strings across all lexing/parsing let lexResourceManager = new Lexhelp.LexResourceManager() + let dependencyProvider = new DependencyProvider() + // process command line, flags and collect filenames let sourceFiles = @@ -1771,7 +1775,7 @@ let main0(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, try let sourceFiles = let files = ProcessCommandLineFlags (tcConfigB, setProcessThreadLocals, lcidFromCodePage, argv) - AdjustForScriptCompile(ctok, tcConfigB, files, lexResourceManager) + AdjustForScriptCompile(ctok, tcConfigB, files, lexResourceManager, dependencyProvider) sourceFiles with e -> @@ -1855,12 +1859,12 @@ let main0(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, if tcConfig.printAst then inputs |> List.iter (fun (input, _filename) -> printf "AST:\n"; printfn "%+A" input; printf "\n") - let tcConfig = (tcConfig, inputs) ||> List.fold (fun z (x, m) -> ApplyMetaCommandsFromInputToTcConfig(z, x, m)) + let tcConfig = (tcConfig, inputs) ||> List.fold (fun z (x, m) -> ApplyMetaCommandsFromInputToTcConfig(z, x, m, dependencyProvider)) let tcConfigP = TcConfigProvider.Constant tcConfig // Import other assemblies ReportTime tcConfig "Import non-system references" - let tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, otherRes, knownUnresolved) |> Cancellable.runWithoutCancellation + let tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, otherRes, knownUnresolved, dependencyProvider) |> Cancellable.runWithoutCancellation // register tcImports to be disposed in future disposables.Register tcImports @@ -1988,6 +1992,7 @@ let main0OfAst (ctok, legacyReferenceResolver, reduceMemoryUsage, assemblyName, delayForFlagsLogger.ForwardDelayedDiagnostics tcConfigB exiter.Exit 1 + let dependencyProvider = new DependencyProvider() let errorLogger = errorLoggerProvider.CreateErrorLoggerUpToMaxErrors(tcConfigB, exiter) // Install the global error logger and never remove it. This logger does have all command-line flags considered. @@ -2010,12 +2015,12 @@ let main0OfAst (ctok, legacyReferenceResolver, reduceMemoryUsage, assemblyName, use unwindParsePhase = PushThreadBuildPhaseUntilUnwind (BuildPhase.Parse) let meta = Directory.GetCurrentDirectory() - let tcConfig = (tcConfig,inputs) ||> List.fold (fun tcc inp -> ApplyMetaCommandsFromInputToTcConfig (tcc, inp,meta)) + let tcConfig = (tcConfig,inputs) ||> List.fold (fun tcc inp -> ApplyMetaCommandsFromInputToTcConfig (tcc, inp, meta, dependencyProvider)) let tcConfigP = TcConfigProvider.Constant tcConfig // Import other assemblies ReportTime tcConfig "Import non-system references" - let tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, otherRes, knownUnresolved) |> Cancellable.runWithoutCancellation + let tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, otherRes, knownUnresolved, dependencyProvider) |> Cancellable.runWithoutCancellation // register tcImports to be disposed in future disposables.Register tcImports diff --git a/src/fsharp/fsi/fsi.fs b/src/fsharp/fsi/fsi.fs index 8e714f71dd1..8b31e56f731 100644 --- a/src/fsharp/fsi/fsi.fs +++ b/src/fsharp/fsi/fsi.fs @@ -601,7 +601,11 @@ let internal directoryName (s:string) = //---------------------------------------------------------------------------- /// Process the command line options -type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, argv: string[], tcConfigB, fsiConsoleOutput: FsiConsoleOutput) = +type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, + argv: string[], + tcConfigB, + fsiConsoleOutput: FsiConsoleOutput) = + let mutable enableConsoleKeyProcessing = // Mono on Win32 doesn't implement correct console processing not (runningOnMono && System.Environment.OSVersion.Platform = System.PlatformID.Win32NT) @@ -757,6 +761,9 @@ type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, argv: s stopProcessingRecovery e range0; failwithf "Error creating evaluation session: %A" e inputFilesAcc + // We need a dependency provider with native resolution. Managed resolution is handled by generated `#r` + let dependencyProvider = new DependencyProvider(null, NativeResolutionProbe(tcConfigB.GetNativeProbingRoots)) + do if tcConfigB.utf8output then let prev = Console.OutputEncoding @@ -797,7 +804,7 @@ type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, argv: s fsiConsoleOutput.uprintfn """ #help;; // %s""" (FSIstrings.SR.fsiIntroTextHashhelpInfo()) if tcConfigB.langVersion.SupportsFeature(LanguageFeature.PackageManagement) then - for msg in tcConfigB.dependencyProvider.GetRegisteredDependencyManagerHelpText(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m) do + for msg in dependencyProvider.GetRegisteredDependencyManagerHelpText(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m) do fsiConsoleOutput.uprintfn "%s" msg fsiConsoleOutput.uprintfn """ #quit;; // %s""" (FSIstrings.SR.fsiIntroTextHashquitInfo()) (* last thing you want to do, last thing in the list - stands out more *) @@ -824,6 +831,8 @@ type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, argv: s member __.SourceFiles = sourceFiles member __.Gui = gui + member _.DependencyProvider = dependencyProvider + /// Set the current ui culture for the current thread. let internal SetCurrentUICultureForThread (lcid : int option) = let culture = Thread.CurrentThread.CurrentUICulture @@ -1461,9 +1470,9 @@ type internal FsiDynamicCompiler | { Directive=_; LineStatus=_; Line=_; Range=m } :: _ -> let outputDir = tcConfigB.outputDir |> Option.defaultValue "" - match tcConfigB.dependencyProvider.TryFindDependencyManagerByKey(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, packageManagerKey) with + match fsiOptions.DependencyProvider.TryFindDependencyManagerByKey(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, packageManagerKey) with | null -> - errorR(Error(tcConfigB.dependencyProvider.CreatePackageManagerUnknownError(tcConfigB.compilerToolPaths, outputDir, packageManagerKey, reportError m), m)) + errorR(Error(fsiOptions.DependencyProvider.CreatePackageManagerUnknownError(tcConfigB.compilerToolPaths, outputDir, packageManagerKey, reportError m), m)) istate | dependencyManager -> let directive d = @@ -1475,7 +1484,7 @@ type internal FsiDynamicCompiler packageManagerLines |> List.map (fun line -> directive line.Directive, line.Line) try - let result = tcConfigB.dependencyProvider.Resolve(dependencyManager, ".fsx", packageManagerTextLines, reportError m, executionTfm, executionRid, tcConfigB.implicitIncludeDir, "stdin.fsx", "stdin.fsx") + let result = fsiOptions.DependencyProvider.Resolve(dependencyManager, ".fsx", packageManagerTextLines, reportError m, executionTfm, executionRid, tcConfigB.implicitIncludeDir, "stdin.fsx", "stdin.fsx") match result.Success with | false -> tcConfigB.packageManagerLines <- PackageManagerLine.RemoveUnprocessedLines packageManagerKey tcConfigB.packageManagerLines @@ -1502,8 +1511,27 @@ type internal FsiDynamicCompiler (fun () -> ProcessMetaCommandsFromInput ((fun st (m,nm) -> tcConfigB.TurnWarningOff(m,nm); st), - (fun st (m,nm) -> snd (fsiDynamicCompiler.EvalRequireReference (ctok, st, m, nm))), - (fun st (packageManagerPrefix, lt, m, nm) -> fsiDynamicCompiler.EvalDependencyManagerTextFragment (packageManagerPrefix, lt, m, nm); st), + (fun st (m, path, directive) -> + + let dm = tcImports.DependencyProvider.TryFindDependencyManagerInPath(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, path) + + match dm with + | _, dependencyManager when not(isNull dependencyManager) -> + if tcConfigB.langVersion.SupportsFeature(LanguageFeature.PackageManagement) then + fsiDynamicCompiler.EvalDependencyManagerTextFragment (dependencyManager, directive, m, path) + st + else + errorR(Error(FSComp.SR.packageManagementRequiresVFive(), m)) + st + + | _, _ when directive = Directive.Include -> + errorR(Error(FSComp.SR.poundiNotSupportedByRegisteredDependencyManagers(), m)) + st + + // #r "Assembly" + | path, _ -> + snd (fsiDynamicCompiler.EvalRequireReference (ctok, st, m, path)) + ), (fun _ _ -> ())) (tcConfigB, inp, Path.GetDirectoryName sourceFile, istate)) @@ -1517,7 +1545,11 @@ type internal FsiDynamicCompiler // Close the #load graph on each file and gather the inputs from the scripts. let tcConfig = TcConfig.Create(tcConfigB,validate=false) - let closure = LoadClosure.ComputeClosureOfScriptFiles(ctok, tcConfig, sourceFiles, CodeContext.CompilationAndEvaluation, lexResourceManager=lexResourceManager) + + let closure = + LoadClosure.ComputeClosureOfScriptFiles(ctok, tcConfig, + sourceFiles, CodeContext.CompilationAndEvaluation, + lexResourceManager, fsiOptions.DependencyProvider) // Intent "[Loading %s]\n" (String.concat "\n and " sourceFiles) fsiConsoleOutput.uprintf "[%s " (FSIstrings.SR.fsiLoadingFilesPrefixText()) @@ -2106,7 +2138,7 @@ type internal FsiInteractionProcessor /// Execute a single parsed interaction. Called on the GUI/execute/main thread. let ExecInteraction (ctok, tcConfig:TcConfig, istate, action:ParsedFsiInteraction, errorLogger: ErrorLogger) = let packageManagerDirective directive path m = - let dm = tcConfigB.dependencyProvider.TryFindDependencyManagerInPath(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, path) + let dm = fsiOptions.DependencyProvider.TryFindDependencyManagerInPath(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, path) match dm with | null, null -> // error already reported @@ -2749,7 +2781,8 @@ type FsiEvaluationSession (fsi: FsiEvaluationSessionHostConfig, argv:string[], i do updateBannerText() // setting the correct banner so that 'fsi -?' display the right thing - let fsiOptions = FsiCommandLineOptions(fsi, argv, tcConfigB, fsiConsoleOutput) + let fsiOptions = FsiCommandLineOptions(fsi, argv, tcConfigB, fsiConsoleOutput) + let fsiConsolePrompt = FsiConsolePrompt(fsiOptions, fsiConsoleOutput) do @@ -2791,7 +2824,7 @@ type FsiEvaluationSession (fsi: FsiEvaluationSessionHostConfig, argv:string[], i let tcImports = try - TcImports.BuildNonFrameworkTcImports(ctokStartup, tcConfigP, tcGlobals, frameworkTcImports, nonFrameworkResolutions, unresolvedReferences) |> Cancellable.runWithoutCancellation + TcImports.BuildNonFrameworkTcImports(ctokStartup, tcConfigP, tcGlobals, frameworkTcImports, nonFrameworkResolutions, unresolvedReferences, fsiOptions.DependencyProvider) |> Cancellable.runWithoutCancellation with e -> stopProcessingRecovery e range0; failwithf "Error creating evaluation session: %A" e diff --git a/src/fsharp/service/FSharpCheckerResults.fs b/src/fsharp/service/FSharpCheckerResults.fs index f3c78473b27..3fb85438d9d 100644 --- a/src/fsharp/service/FSharpCheckerResults.fs +++ b/src/fsharp/service/FSharpCheckerResults.fs @@ -1621,7 +1621,7 @@ module internal ParseAndCheckFile = | None -> // For non-scripts, check for disallow #r and #load. - ApplyMetaCommandsFromInputToTcConfig (tcConfig, parsedMainInput,Path.GetDirectoryName mainInputFileName) |> ignore + ApplyMetaCommandsFromInputToTcConfig (tcConfig, parsedMainInput, Path.GetDirectoryName mainInputFileName, tcImports.DependencyProvider) |> ignore // Type check a single file against an initial context, gleaning both errors and intellisense information. let CheckOneFile @@ -2161,8 +2161,8 @@ type FSharpCheckProjectResults type FsiInteractiveChecker(legacyReferenceResolver, reactorOps: IReactorOperations, tcConfig: TcConfig, - tcGlobals, - tcImports, + tcGlobals: TcGlobals, + tcImports: TcImports, tcState) = let keepAssemblyContents = false @@ -2192,7 +2192,9 @@ type FsiInteractiveChecker(legacyReferenceResolver, tcConfig.useSimpleResolution, tcConfig.useFsiAuxLib, tcConfig.useSdkRefs, new Lexhelp.LexResourceManager(), applyCompilerOptions, assumeDotNetFramework, - tryGetMetadataSnapshot=(fun _ -> None), reduceMemoryUsage=reduceMemoryUsage) + tryGetMetadataSnapshot=(fun _ -> None), + reduceMemoryUsage=reduceMemoryUsage, + dependencyProvider=tcImports.DependencyProvider) let! tcErrors, tcFileInfo = ParseAndCheckFile.CheckOneFile diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs index f60d85adfc1..107f381364d 100755 --- a/src/fsharp/service/IncrementalBuild.fs +++ b/src/fsharp/service/IncrementalBuild.fs @@ -26,6 +26,8 @@ open FSharp.Compiler.TypeChecker open FSharp.Compiler.TypedTree open FSharp.Compiler.TypedTreeOps +open Microsoft.DotNet.DependencyManager + open Internal.Utilities.Collections [] @@ -1220,9 +1222,12 @@ type RawFSharpAssemblyDataBackedByLanguageService (tcConfig, tcGlobals, tcState: /// Manages an incremental build graph for the build of a single F# project type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInputs, nonFrameworkResolutions, unresolvedReferences, tcConfig: TcConfig, projectDirectory, outfile, - assemblyName, niceNameGen: NiceNameGenerator, lexResourceManager, - sourceFiles, loadClosureOpt: LoadClosure option, - keepAssemblyContents, keepAllBackgroundResolutions, maxTimeShareMilliseconds, keepAllBackgroundSymbolUses, enableBackgroundItemKeyStoreAndSemanticClassification) = + assemblyName, niceNameGen: NiceNameGenerator, lexResourceManager, + sourceFiles, loadClosureOpt: LoadClosure option, + keepAssemblyContents, keepAllBackgroundResolutions, + maxTimeShareMilliseconds, keepAllBackgroundSymbolUses, + enableBackgroundItemKeyStoreAndSemanticClassification, + dependencyProviderOpt: DependencyProvider option) = let tcConfigP = TcConfigProvider.Constant tcConfig let fileParsed = new Event() @@ -1259,6 +1264,13 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput for (_, f, _) in sourceFiles do yield f |] + // For scripts, the dependency provider is already available. + // For projects create a fresh one for the project. + let dependencyProvider = + match dependencyProviderOpt with + | None -> new DependencyProvider() + | Some dependencyProvider -> dependencyProvider + //---------------------------------------------------- // START OF BUILD TASK FUNCTIONS @@ -1309,7 +1321,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput let! tcImports = cancellable { try - let! tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, nonFrameworkResolutions, unresolvedReferences) + let! tcImports = TcImports.BuildNonFrameworkTcImports(ctok, tcConfigP, tcGlobals, frameworkTcImports, nonFrameworkResolutions, unresolvedReferences, dependencyProvider) #if !NO_EXTENSIONTYPING tcImports.GetCcusExcludingBase() |> Seq.iter (fun ccu -> // When a CCU reports an invalidation, merge them together and just report a @@ -1383,7 +1395,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput eventually { beforeFileChecked.Trigger filename - ApplyMetaCommandsFromInputToTcConfig (tcConfig, input, Path.GetDirectoryName filename) |> ignore + ApplyMetaCommandsFromInputToTcConfig (tcConfig, input, Path.GetDirectoryName filename, tcAcc.tcImports.DependencyProvider) |> ignore let sink = TcResultsSinkImpl(tcAcc.tcGlobals) let hadParseErrors = not (Array.isEmpty parseErrors) @@ -1740,7 +1752,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput /// CreateIncrementalBuilder (for background type checking). Note that fsc.fs also /// creates an incremental builder used by the command line compiler. - static member TryCreateBackgroundBuilderForProjectOptions + static member TryCreateIncrementalBuilderForProjectOptions (ctok, legacyReferenceResolver, defaultFSharpBinariesDir, frameworkTcImportsCache: FrameworkImportsCache, loadClosureOpt: LoadClosure option, @@ -1749,7 +1761,11 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput projectReferences, projectDirectory, useScriptResolutionRules, keepAssemblyContents, keepAllBackgroundResolutions, maxTimeShareMilliseconds, - tryGetMetadataSnapshot, suggestNamesForErrors, keepAllBackgroundSymbolUses, enableBackgroundItemKeyStoreAndSemanticClassification) = + tryGetMetadataSnapshot, suggestNamesForErrors, + keepAllBackgroundSymbolUses, + enableBackgroundItemKeyStoreAndSemanticClassification, + dependencyProviderOpt) = + let useSimpleResolutionSwitch = "--simpleresolution" cancellable { @@ -1864,14 +1880,16 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput yield Choice2Of2 pr, (fun (cache: TimeStampCache) ctok -> cache.GetProjectReferenceTimeStamp (pr, ctok)) ] let builder = - new IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInputs, nonFrameworkResolutions, unresolvedReferences, - tcConfig, projectDirectory, outfile, assemblyName, niceNameGen, - resourceManager, sourceFilesNew, loadClosureOpt, - keepAssemblyContents=keepAssemblyContents, - keepAllBackgroundResolutions=keepAllBackgroundResolutions, - maxTimeShareMilliseconds=maxTimeShareMilliseconds, - keepAllBackgroundSymbolUses=keepAllBackgroundSymbolUses, - enableBackgroundItemKeyStoreAndSemanticClassification=enableBackgroundItemKeyStoreAndSemanticClassification) + new IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInputs, + nonFrameworkResolutions, unresolvedReferences, + tcConfig, projectDirectory, outfile, assemblyName, niceNameGen, + resourceManager, sourceFilesNew, loadClosureOpt, + keepAssemblyContents, + keepAllBackgroundResolutions, + maxTimeShareMilliseconds, + keepAllBackgroundSymbolUses, + enableBackgroundItemKeyStoreAndSemanticClassification, + dependencyProviderOpt) return Some builder with e -> errorRecoveryNoRange e diff --git a/src/fsharp/service/IncrementalBuild.fsi b/src/fsharp/service/IncrementalBuild.fsi index e9f945cd970..c6bfe1e1f5a 100755 --- a/src/fsharp/service/IncrementalBuild.fsi +++ b/src/fsharp/service/IncrementalBuild.fsi @@ -16,6 +16,8 @@ open FSharp.Compiler.SyntaxTree open FSharp.Compiler.TcGlobals open FSharp.Compiler.TypedTree +open Microsoft.DotNet.DependencyManager + /// Lookup the global static cache for building the FrameworkTcImports type internal FrameworkImportsCache = new : size: int -> FrameworkImportsCache @@ -178,9 +180,29 @@ type internal IncrementalBuilder = /// Await the untyped parse results for a particular slot in the vector of parse results. /// /// This may be a marginally long-running operation (parses are relatively quick, only one file needs to be parsed) - member GetParseResultsForFile : CompilationThreadToken * filename:string -> Cancellable - - static member TryCreateBackgroundBuilderForProjectOptions : CompilationThreadToken * ReferenceResolver.Resolver * defaultFSharpBinariesDir: string * FrameworkImportsCache * scriptClosureOptions:LoadClosure option * sourceFiles:string list * commandLineArgs:string list * projectReferences: IProjectReference list * projectDirectory:string * useScriptResolutionRules:bool * keepAssemblyContents: bool * keepAllBackgroundResolutions: bool * maxTimeShareMilliseconds: int64 * tryGetMetadataSnapshot: ILBinaryReader.ILReaderTryGetMetadataSnapshot * suggestNamesForErrors: bool * keepAllBackgroundSymbolUses: bool * enableBackgroundItemKeyStoreAndSemanticClassification: bool -> Cancellable + member GetParseResultsForFile: CompilationThreadToken * filename:string -> Cancellable + + /// Create the incremental builder + static member TryCreateIncrementalBuilderForProjectOptions: + CompilationThreadToken * + ReferenceResolver.Resolver * + defaultFSharpBinariesDir: string * + FrameworkImportsCache * + scriptClosureOptions:LoadClosure option * + sourceFiles:string list * + commandLineArgs:string list * + projectReferences: IProjectReference list * + projectDirectory:string * + useScriptResolutionRules:bool * + keepAssemblyContents: bool * + keepAllBackgroundResolutions: bool * + maxTimeShareMilliseconds: int64 * + tryGetMetadataSnapshot: ILBinaryReader.ILReaderTryGetMetadataSnapshot * + suggestNamesForErrors: bool * + keepAllBackgroundSymbolUses: bool * + enableBackgroundItemKeyStoreAndSemanticClassification: bool * + dependencyProvider: DependencyProvider option + -> Cancellable /// Generalized Incremental Builder. This is exposed only for unit testing purposes. module internal IncrementalBuild = diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index 246f6d7440e..463e57a52d9 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -24,6 +24,8 @@ open FSharp.Compiler.SyntaxTree open FSharp.Compiler.TcGlobals open FSharp.Compiler.Text +open Microsoft.DotNet.DependencyManager + open Internal.Utilities open Internal.Utilities.Collections @@ -274,6 +276,14 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC let scriptClosureCacheLock = Lock() let frameworkTcImportsCache = FrameworkImportsCache(frameworkTcImportsCacheStrongSize) + // We currently share one global dependency provider for all scripts for the FSharpChecker. + // For projects, one is used per project. + // + // Sharing one for all scripts is necessary for good performance from GetProjectOptionsFromScript, + // which requires a dependency provider to process through the project options prior to working out + // if the cached incremental builder can be used for the project. + let dependencyProviderForScripts = new DependencyProvider() + /// CreateOneIncrementalBuilder (for background type checking). Note that fsc.fs also /// creates an incremental builder used by the command line compiler. let CreateOneIncrementalBuilder (ctok, options:FSharpProjectOptions, userOpName) = @@ -301,12 +311,15 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC member x.FileName = nm } ] let loadClosure = scriptClosureCacheLock.AcquireLock (fun ltok -> scriptClosureCache.TryGet (ltok, options)) + let! builderOpt, diagnostics = - IncrementalBuilder.TryCreateBackgroundBuilderForProjectOptions + IncrementalBuilder.TryCreateIncrementalBuilderForProjectOptions (ctok, legacyReferenceResolver, FSharpCheckerResultsSettings.defaultFSharpBinariesDir, frameworkTcImportsCache, loadClosure, Array.toList options.SourceFiles, Array.toList options.OtherOptions, projectReferences, options.ProjectDirectory, options.UseScriptResolutionRules, keepAssemblyContents, keepAllBackgroundResolutions, FSharpCheckerResultsSettings.maxTimeShareMilliseconds, - tryGetMetadataSnapshot, suggestNamesForErrors, keepAllBackgroundSymbolUses, enableBackgroundItemKeyStoreAndSemanticClassification) + tryGetMetadataSnapshot, suggestNamesForErrors, keepAllBackgroundSymbolUses, + enableBackgroundItemKeyStoreAndSemanticClassification, + (if options.UseScriptResolutionRules then Some dependencyProviderForScripts else None)) match builderOpt with | None -> () @@ -817,8 +830,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC FSharpCheckerResultsSettings.defaultFSharpBinariesDir, filename, sourceText, CodeContext.Editing, useSimpleResolution, useFsiAuxLib, useSdkRefs, new Lexhelp.LexResourceManager(), applyCompilerOptions, assumeDotNetFramework, - tryGetMetadataSnapshot=tryGetMetadataSnapshot, - reduceMemoryUsage=reduceMemoryUsage) + tryGetMetadataSnapshot, reduceMemoryUsage, dependencyProviderForScripts) let otherFlags = [| yield "--noframework"; yield "--warn:3"; From b432077e533d9e5ccc8596374c35cd30fa403262 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Sun, 20 Sep 2020 01:43:54 +0100 Subject: [PATCH 06/12] fix diagnostics in IDE --- src/fsharp/CompileOps.fs | 16 +++++++-- src/fsharp/FSComp.txt | 2 +- .../FSharp.DependencyManager.Utilities.fs | 7 +--- .../DependencyProvider.fs | 36 ++++++++++--------- src/fsharp/fsi/fsi.fs | 14 ++++++-- src/fsharp/xlf/FSComp.txt.cs.xlf | 10 +++--- src/fsharp/xlf/FSComp.txt.de.xlf | 10 +++--- src/fsharp/xlf/FSComp.txt.es.xlf | 10 +++--- src/fsharp/xlf/FSComp.txt.fr.xlf | 10 +++--- src/fsharp/xlf/FSComp.txt.it.xlf | 10 +++--- src/fsharp/xlf/FSComp.txt.ja.xlf | 10 +++--- src/fsharp/xlf/FSComp.txt.ko.xlf | 10 +++--- src/fsharp/xlf/FSComp.txt.pl.xlf | 10 +++--- src/fsharp/xlf/FSComp.txt.pt-BR.xlf | 10 +++--- src/fsharp/xlf/FSComp.txt.ru.xlf | 10 +++--- src/fsharp/xlf/FSComp.txt.tr.xlf | 10 +++--- src/fsharp/xlf/FSComp.txt.zh-Hans.xlf | 10 +++--- src/fsharp/xlf/FSComp.txt.zh-Hant.xlf | 10 +++--- 18 files changed, 111 insertions(+), 94 deletions(-) diff --git a/src/fsharp/CompileOps.fs b/src/fsharp/CompileOps.fs index cdf760b3f23..22e9b8636fa 100644 --- a/src/fsharp/CompileOps.fs +++ b/src/fsharp/CompileOps.fs @@ -5453,8 +5453,12 @@ module ScriptPreprocessClosure = let packageManagerTextLines = packageManagerLines |> List.map(fun l -> directive l.Directive, l.Line) let result = dependencyProvider.Resolve(dependencyManager, ".fsx", packageManagerTextLines, reportError, executionTfm, executionRid, tcConfig.implicitIncludeDir, mainFile, scriptName) - match result.Success with - | true -> + if result.Success then + //Write outputs in F# Interactive and compiler + if codeContext <> CodeContext.Editing then + for line in result.StdOut do Console.Out.WriteLine(line) + for line in result.StdError do Console.Error.WriteLine(line) + // Resolution produced no errors if not (Seq.isEmpty result.Roots) then let tcConfigB = tcConfig.CloneOfOriginalBuilder @@ -5468,7 +5472,13 @@ module ScriptPreprocessClosure = let iSourceText = SourceText.ofString scriptText yield! loop (ClosureSource(script, m, iSourceText, true)) - | false -> + else + // Send outputs via diagnostics + if (result.StdOut.Length > 0 || result.StdError.Length > 0) then + for line in Array.append result.StdOut result.StdError do + errorR(Error(FSComp.SR.packageManagerError(line), m)) + else + warning(Error(FSComp.SR.packageManagerFailedNoOutput(), m)) // Resolution produced errors update packagerManagerLines entries to note these failure // failed resolutions will no longer be considered let tcConfigB = tcConfig.CloneOfOriginalBuilder diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 7914b2e6919..9509bd378a9 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1546,4 +1546,4 @@ forFormatInvalidForInterpolated4,"Interpolated strings used as type IFormattable 3390,xmlDocInvalidParameterName,"This XML comment is invalid: unknown parameter '%s'" 3390,xmlDocDuplicateParameter,"This XML comment is invalid: multiple documentation entries for parameter '%s'" 3390,xmlDocUnresolvedCrossReference,"This XML comment is invalid: unresolved cross-reference '%s'" -3390,xmlDocMissingParameter,"This XML comment is incomplete: no documentation for parameter '%s'" \ No newline at end of file +3393,packageManagerFailedNoOutput,"Package manager failed without output" \ No newline at end of file diff --git a/src/fsharp/FSharp.DependencyManager.Nuget/FSharp.DependencyManager.Utilities.fs b/src/fsharp/FSharp.DependencyManager.Nuget/FSharp.DependencyManager.Utilities.fs index 7a8946d1e59..d6c2f2f303d 100644 --- a/src/fsharp/FSharp.DependencyManager.Nuget/FSharp.DependencyManager.Utilities.fs +++ b/src/fsharp/FSharp.DependencyManager.Nuget/FSharp.DependencyManager.Utilities.fs @@ -183,11 +183,6 @@ module internal Utilities = p.WaitForExit() - if p.ExitCode <> 0 then - //Write StandardError.txt to err stream - for line in stdOut do Console.Out.WriteLine(line) - for line in stdErr do Console.Error.WriteLine(line) - p.ExitCode = 0, stdOut, stdErr | None -> false, Array.empty, Array.empty @@ -203,7 +198,7 @@ module internal Utilities = | None -> "" let arguments prefix = - sprintf "%s -restore %s %c%s%c /t:InteractivePackageManagement" prefix binLoggingArguments '\"' projectPath '\"' + sprintf "%s -restore %s %c%s%c /nologo /t:InteractivePackageManagement" prefix binLoggingArguments '\"' projectPath '\"' let workingDir = Path.GetDirectoryName projectPath diff --git a/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs b/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs index be24bd46432..f080981550c 100644 --- a/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs +++ b/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs @@ -330,7 +330,7 @@ type DependencyProvider (assemblyProbingPaths: AssemblyResolutionProbe, nativePr None managers - let cache = ConcurrentDictionary<_,IResolveDependenciesResult>(HashIdentity.Structural) + let cache = ConcurrentDictionary<_,Result>(HashIdentity.Structural) new (nativeProbingRoots: NativeResolutionProbe) = new DependencyProvider(null, nativeProbingRoots) @@ -399,21 +399,25 @@ type DependencyProvider (assemblyProbingPaths: AssemblyResolutionProbe, nativePr let key = (packageManager.Key, scriptExt, Seq.toArray packageManagerTextLines, executionTfm, executionRid, implicitIncludeDir, mainScriptName, fileName) - cache.GetOrAdd(key, System.Func<_,_>(fun _ -> - try - let executionRid = - if isNull executionRid then - RidHelpers.platformRid - else - executionRid - packageManager.ResolveDependencies(implicitIncludeDir, mainScriptName, fileName, scriptExt, packageManagerTextLines, executionTfm, executionRid) - - with e -> - let e = stripTieWrapper e - let err, msg = (DependencyManager.SR.packageManagerError(e.Message)) - reportError.Invoke(ErrorReportType.Error, err, msg) - ReflectionDependencyManagerProvider.MakeResultFromFields(false, arrEmpty, arrEmpty, seqEmpty, seqEmpty, seqEmpty) - )) + let result = + cache.GetOrAdd(key, System.Func<_,_>(fun _ -> + try + let executionRid = + if isNull executionRid then + RidHelpers.platformRid + else + executionRid + Ok (packageManager.ResolveDependencies(implicitIncludeDir, mainScriptName, fileName, scriptExt, packageManagerTextLines, executionTfm, executionRid)) + + with e -> + let e = stripTieWrapper e + Error (DependencyManager.SR.packageManagerError(e.Message)) + )) + match result with + | Ok res -> res + | Error (errorNumber, errorData) -> + reportError.Invoke(ErrorReportType.Error, errorNumber, errorData) + ReflectionDependencyManagerProvider.MakeResultFromFields(false, arrEmpty, arrEmpty, seqEmpty, seqEmpty, seqEmpty) interface IDisposable with diff --git a/src/fsharp/fsi/fsi.fs b/src/fsharp/fsi/fsi.fs index 8b31e56f731..52b126cf4b8 100644 --- a/src/fsharp/fsi/fsi.fs +++ b/src/fsharp/fsi/fsi.fs @@ -1485,12 +1485,20 @@ type internal FsiDynamicCompiler try let result = fsiOptions.DependencyProvider.Resolve(dependencyManager, ".fsx", packageManagerTextLines, reportError m, executionTfm, executionRid, tcConfigB.implicitIncludeDir, "stdin.fsx", "stdin.fsx") - match result.Success with - | false -> + if result.Success then + // Send outputs via diagnostics + if (result.StdOut.Length > 0 || result.StdError.Length > 0) then + for line in Array.append result.StdOut result.StdError do + errorR(Error(FSComp.SR.packageManagerError(line), m)) + else + warning(Error(FSComp.SR.packageManagerFailedNoOutput(), m)) + //Write outputs in F# Interactive and compiler tcConfigB.packageManagerLines <- PackageManagerLine.RemoveUnprocessedLines packageManagerKey tcConfigB.packageManagerLines istate // error already reported - | true -> + else + for line in result.StdOut do Console.Out.WriteLine(line) + for line in result.StdError do Console.Error.WriteLine(line) tcConfigB.packageManagerLines <- PackageManagerLine.SetLinesAsProcessed packageManagerKey tcConfigB.packageManagerLines for folder in result.Roots do tcConfigB.AddIncludePath(m, folder, "") diff --git a/src/fsharp/xlf/FSComp.txt.cs.xlf b/src/fsharp/xlf/FSComp.txt.cs.xlf index 9839f7d0bca..61c2bae4b46 100644 --- a/src/fsharp/xlf/FSComp.txt.cs.xlf +++ b/src/fsharp/xlf/FSComp.txt.cs.xlf @@ -247,6 +247,11 @@ Funkce správy balíčků vyžaduje jazykovou verzi 5.0, použijte /langversion:preview. + + Package manager failed without output + Package manager failed without output + + Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. @@ -542,11 +547,6 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference - - This XML comment is incomplete: no documentation for parameter '{0}' - This XML comment is incomplete: no documentation for parameter '{0}' - - This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.de.xlf b/src/fsharp/xlf/FSComp.txt.de.xlf index f0ddc681111..6a92990438f 100644 --- a/src/fsharp/xlf/FSComp.txt.de.xlf +++ b/src/fsharp/xlf/FSComp.txt.de.xlf @@ -247,6 +247,11 @@ Für das Paketverwaltungsfeature ist Sprachversion 5.0 erforderlich. Verwenden Sie /langversion:preview. + + Package manager failed without output + Package manager failed without output + + Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. @@ -542,11 +547,6 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference - - This XML comment is incomplete: no documentation for parameter '{0}' - This XML comment is incomplete: no documentation for parameter '{0}' - - This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.es.xlf b/src/fsharp/xlf/FSComp.txt.es.xlf index 24077dfabb0..3b3121581b0 100644 --- a/src/fsharp/xlf/FSComp.txt.es.xlf +++ b/src/fsharp/xlf/FSComp.txt.es.xlf @@ -247,6 +247,11 @@ La característica de administración de paquetes requiere la versión de lenguaje 5.0; use /langversion:preview + + Package manager failed without output + Package manager failed without output + + Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. @@ -542,11 +547,6 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference - - This XML comment is incomplete: no documentation for parameter '{0}' - This XML comment is incomplete: no documentation for parameter '{0}' - - This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.fr.xlf b/src/fsharp/xlf/FSComp.txt.fr.xlf index 505de283f8c..406af22207c 100644 --- a/src/fsharp/xlf/FSComp.txt.fr.xlf +++ b/src/fsharp/xlf/FSComp.txt.fr.xlf @@ -247,6 +247,11 @@ La fonctionnalité de gestion des packages nécessite la version 5.0 du langage. Utilisez /langversion:preview + + Package manager failed without output + Package manager failed without output + + Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. @@ -542,11 +547,6 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference - - This XML comment is incomplete: no documentation for parameter '{0}' - This XML comment is incomplete: no documentation for parameter '{0}' - - This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.it.xlf b/src/fsharp/xlf/FSComp.txt.it.xlf index b6527118704..979e79be664 100644 --- a/src/fsharp/xlf/FSComp.txt.it.xlf +++ b/src/fsharp/xlf/FSComp.txt.it.xlf @@ -247,6 +247,11 @@ Con la funzionalità di gestione pacchetti è richiesta la versione 5.0 del linguaggio. Usare /langversion:preview + + Package manager failed without output + Package manager failed without output + + Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. @@ -542,11 +547,6 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference - - This XML comment is incomplete: no documentation for parameter '{0}' - This XML comment is incomplete: no documentation for parameter '{0}' - - This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.ja.xlf b/src/fsharp/xlf/FSComp.txt.ja.xlf index a361c41ff6b..7838deb1ae3 100644 --- a/src/fsharp/xlf/FSComp.txt.ja.xlf +++ b/src/fsharp/xlf/FSComp.txt.ja.xlf @@ -3857,6 +3857,11 @@ {0} + + Package manager failed without output + Package manager failed without output + + Package manager key '{0}' was not registered in {1}. Currently registered: {2} Package manager key '{0}' was not registered in {1}. Currently registered: {2} @@ -7572,11 +7577,6 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference - - This XML comment is incomplete: no documentation for parameter '{0}' - This XML comment is incomplete: no documentation for parameter '{0}' - - This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.ko.xlf b/src/fsharp/xlf/FSComp.txt.ko.xlf index a6fcf98469d..c07b4d8f477 100644 --- a/src/fsharp/xlf/FSComp.txt.ko.xlf +++ b/src/fsharp/xlf/FSComp.txt.ko.xlf @@ -247,6 +247,11 @@ 패키지 관리 기능을 사용하려면 언어 버전 5.0이 필요합니다. /langversion:preview를 사용하세요. + + Package manager failed without output + Package manager failed without output + + Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. @@ -542,11 +547,6 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference - - This XML comment is incomplete: no documentation for parameter '{0}' - This XML comment is incomplete: no documentation for parameter '{0}' - - This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.pl.xlf b/src/fsharp/xlf/FSComp.txt.pl.xlf index 3727ead1dac..3a2ea249485 100644 --- a/src/fsharp/xlf/FSComp.txt.pl.xlf +++ b/src/fsharp/xlf/FSComp.txt.pl.xlf @@ -247,6 +247,11 @@ Funkcja zarządzania pakietami wymaga języka w wersji 5.0, użyj parametru /langversion:preview + + Package manager failed without output + Package manager failed without output + + Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. @@ -542,11 +547,6 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference - - This XML comment is incomplete: no documentation for parameter '{0}' - This XML comment is incomplete: no documentation for parameter '{0}' - - This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf index c6281378ea8..d0cc3dcb8d6 100644 --- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf +++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf @@ -247,6 +247,11 @@ O recurso de gerenciamento de pacotes requer a versão de idioma 5.0. Use /langversion:preview + + Package manager failed without output + Package manager failed without output + + Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. @@ -542,11 +547,6 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference - - This XML comment is incomplete: no documentation for parameter '{0}' - This XML comment is incomplete: no documentation for parameter '{0}' - - This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.ru.xlf b/src/fsharp/xlf/FSComp.txt.ru.xlf index afe00bca155..f0c7592f7aa 100644 --- a/src/fsharp/xlf/FSComp.txt.ru.xlf +++ b/src/fsharp/xlf/FSComp.txt.ru.xlf @@ -247,6 +247,11 @@ Для функции управления пакетами требуется версия языка 5.0, используйте параметр /langversion:preview + + Package manager failed without output + Package manager failed without output + + Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. @@ -542,11 +547,6 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference - - This XML comment is incomplete: no documentation for parameter '{0}' - This XML comment is incomplete: no documentation for parameter '{0}' - - This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.tr.xlf b/src/fsharp/xlf/FSComp.txt.tr.xlf index bc142bfc6a0..a7607195a55 100644 --- a/src/fsharp/xlf/FSComp.txt.tr.xlf +++ b/src/fsharp/xlf/FSComp.txt.tr.xlf @@ -247,6 +247,11 @@ Paket yönetimi özelliği dil sürümü 5.0 gerektiriyor, /langversion:preview kullanın + + Package manager failed without output + Package manager failed without output + + Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. @@ -542,11 +547,6 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference - - This XML comment is incomplete: no documentation for parameter '{0}' - This XML comment is incomplete: no documentation for parameter '{0}' - - This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf index 8df687974e5..a844ffd56a5 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf @@ -247,6 +247,11 @@ 包管理功能需要语言版本 5.0,请使用 /langversion:preview + + Package manager failed without output + Package manager failed without output + + Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. @@ -542,11 +547,6 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference - - This XML comment is incomplete: no documentation for parameter '{0}' - This XML comment is incomplete: no documentation for parameter '{0}' - - This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf index 035bd7f69dc..971f74e3461 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf @@ -247,6 +247,11 @@ 套件管理功能需要語言版本 5.0,請使用 /langversion:preview + + Package manager failed without output + Package manager failed without output + + Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. @@ -542,11 +547,6 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference - - This XML comment is incomplete: no documentation for parameter '{0}' - This XML comment is incomplete: no documentation for parameter '{0}' - - This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference From 5767d43738b2a81b520abb844fc91672bf18a431 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Sun, 20 Sep 2020 01:46:25 +0100 Subject: [PATCH 07/12] fix fscomp --- src/fsharp/FSComp.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 9509bd378a9..3bfebdb442a 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1546,4 +1546,5 @@ forFormatInvalidForInterpolated4,"Interpolated strings used as type IFormattable 3390,xmlDocInvalidParameterName,"This XML comment is invalid: unknown parameter '%s'" 3390,xmlDocDuplicateParameter,"This XML comment is invalid: multiple documentation entries for parameter '%s'" 3390,xmlDocUnresolvedCrossReference,"This XML comment is invalid: unresolved cross-reference '%s'" +3390,xmlDocMissingParameter,"This XML comment is incomplete: no documentation for parameter '%s'" 3393,packageManagerFailedNoOutput,"Package manager failed without output" \ No newline at end of file From c3433d07463f8a00c4176d3e2de0720356e7190b Mon Sep 17 00:00:00 2001 From: Don Syme Date: Sun, 20 Sep 2020 03:28:12 +0100 Subject: [PATCH 08/12] tooltips for script references --- src/fsharp/CompileOps.fs | 34 +++++++++--- src/fsharp/CompileOps.fsi | 3 ++ src/fsharp/fsi/fsi.fs | 22 ++++---- src/fsharp/service/FSharpCheckerResults.fs | 16 +++++- src/fsharp/xlf/FSComp.txt.cs.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.de.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.es.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.fr.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.it.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.ja.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.ko.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.pl.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.pt-BR.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.ru.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.tr.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.zh-Hans.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.zh-Hant.xlf | 5 ++ .../CodeFix/AddOpenCodeFixProvider.fs | 2 +- .../ImplementInterfaceCodeFixProvider.fs | 2 +- .../CodeFix/RenameUnusedValue.fs | 2 +- .../DocumentHighlightsService.fs | 2 +- .../InlineRename/InlineRenameService.fs | 2 +- .../LanguageService/SymbolHelpers.fs | 4 +- .../LanguageService/Tokenizer.fs | 19 +++++-- .../Navigation/FindUsagesService.fs | 2 +- .../Navigation/GoToDefinition.fs | 4 +- .../QuickInfo/QuickInfoProvider.fs | 52 +++++++++++-------- .../UnitTests/GoToDefinitionServiceTests.fs | 2 +- 28 files changed, 175 insertions(+), 58 deletions(-) diff --git a/src/fsharp/CompileOps.fs b/src/fsharp/CompileOps.fs index 22e9b8636fa..3904c18d06d 100644 --- a/src/fsharp/CompileOps.fs +++ b/src/fsharp/CompileOps.fs @@ -5274,22 +5274,34 @@ type LoadClosureInput = type LoadClosure = { /// The source files along with the ranges of the #load positions in each file. SourceFiles: (string * range list) list + /// The resolved references along with the ranges of the #r positions in each file. References: (string * AssemblyResolution list) list + + /// The resolved pacakge references along with the ranges of the #r positions in each file. + PackageReferences: (range * string list)[] + /// The list of references that were not resolved during load closure. These may still be extension references. UnresolvedReferences: UnresolvedAssemblyReference list + /// The list of all sources in the closure with inputs when available Inputs: LoadClosureInput list + /// The #load, including those that didn't resolve OriginalLoadReferences: (range * string * string) list + /// The #nowarns NoWarns: (string * range list) list + /// Diagnostics seen while processing resolutions ResolutionDiagnostics: (PhasedDiagnostic * bool) list + /// Diagnostics seen while parsing root of closure AllRootFileDiagnostics: (PhasedDiagnostic * bool) list + /// Diagnostics seen while processing the compiler options implied root of closure - LoadClosureRootFileDiagnostics: (PhasedDiagnostic * bool) list } + LoadClosureRootFileDiagnostics: (PhasedDiagnostic * bool) list + } [] @@ -5421,6 +5433,7 @@ module ScriptPreprocessClosure = let observedSources = Observed() let loadScripts = HashSet<_>() + let packageReferences = Dictionary(HashIdentity.Structural) // Resolve the packages let rec resolveDependencyManagerSources scriptName = @@ -5454,12 +5467,13 @@ module ScriptPreprocessClosure = let packageManagerTextLines = packageManagerLines |> List.map(fun l -> directive l.Directive, l.Line) let result = dependencyProvider.Resolve(dependencyManager, ".fsx", packageManagerTextLines, reportError, executionTfm, executionRid, tcConfig.implicitIncludeDir, mainFile, scriptName) if result.Success then + // Resolution produced no errors //Write outputs in F# Interactive and compiler if codeContext <> CodeContext.Editing then for line in result.StdOut do Console.Out.WriteLine(line) for line in result.StdError do Console.Error.WriteLine(line) - // Resolution produced no errors + packageReferences.[m] <- [ for script in result.SourceFiles do yield! File.ReadAllLines script ] if not (Seq.isEmpty result.Roots) then let tcConfigB = tcConfig.CloneOfOriginalBuilder for folder in result.Roots do @@ -5529,10 +5543,13 @@ module ScriptPreprocessClosure = printfn "yielding non-script source %s" filename yield ClosureFile(filename, m, None, [], [], []) ] - closureSources |> List.collect loop, tcConfig + let sources = closureSources |> List.collect loop + let packageReferences = packageReferences |> Seq.map (fun kvp -> kvp.Key, kvp.Value) |> Seq.toArray + sources, tcConfig, packageReferences + /// Reduce the full directive closure into LoadClosure - let GetLoadClosure(ctok, rootFilename, closureFiles, tcConfig: TcConfig, codeContext) = + let GetLoadClosure(ctok, rootFilename, closureFiles, tcConfig: TcConfig, codeContext, packageReferences) = // Mark the last file as isLastCompiland. let closureFiles = @@ -5597,6 +5614,7 @@ module ScriptPreprocessClosure = let result: LoadClosure = { SourceFiles = List.groupBy fst sourceFiles |> List.map (map2Of2 (List.map snd)) References = List.groupBy fst references |> List.map (map2Of2 (List.map snd)) + PackageReferences = packageReferences UnresolvedReferences = unresolvedReferences Inputs = sourceInputs NoWarns = List.groupBy fst globalNoWarns |> List.map (map2Of2 (List.map snd)) @@ -5638,8 +5656,8 @@ module ScriptPreprocessClosure = tryGetMetadataSnapshot, reduceMemoryUsage) let closureSources = [ClosureSource(filename, range0, sourceText, true)] - let closureFiles, tcConfig = FindClosureFiles(filename, range0, closureSources, tcConfig, codeContext, lexResourceManager, dependencyProvider) - GetLoadClosure(ctok, filename, closureFiles, tcConfig, codeContext) + let closureFiles, tcConfig, packageReferences = FindClosureFiles(filename, range0, closureSources, tcConfig, codeContext, lexResourceManager, dependencyProvider) + GetLoadClosure(ctok, filename, closureFiles, tcConfig, codeContext, packageReferences) /// Given source filename, find the full load closure /// Used from fsi.fs and fsc.fs, for #load and command line @@ -5649,8 +5667,8 @@ module ScriptPreprocessClosure = let mainFile, mainFileRange = List.last files let closureSources = files |> List.collect (fun (filename, m) -> ClosureSourceOfFilename(filename, m,tcConfig.inputCodePage,true)) - let closureFiles,tcConfig = FindClosureFiles(mainFile, mainFileRange, closureSources, tcConfig, codeContext, lexResourceManager, dependencyProvider) - GetLoadClosure(ctok, mainFile, closureFiles, tcConfig, codeContext) + let closureFiles, tcConfig, packageReferences = FindClosureFiles(mainFile, mainFileRange, closureSources, tcConfig, codeContext, lexResourceManager, dependencyProvider) + GetLoadClosure(ctok, mainFile, closureFiles, tcConfig, codeContext, packageReferences) type LoadClosure with /// Analyze a script text and find the closure of its references. diff --git a/src/fsharp/CompileOps.fsi b/src/fsharp/CompileOps.fsi index 9725f135ac6..6d138c411a6 100644 --- a/src/fsharp/CompileOps.fsi +++ b/src/fsharp/CompileOps.fsi @@ -859,6 +859,9 @@ type LoadClosure = /// The resolved references along with the ranges of the #r positions in each file. References: (string * AssemblyResolution list) list + /// The resolved pacakge references along with the ranges of the #r positions in each file. + PackageReferences: (range * string list)[] + /// The list of references that were not resolved during load closure. UnresolvedReferences: UnresolvedAssemblyReference list diff --git a/src/fsharp/fsi/fsi.fs b/src/fsharp/fsi/fsi.fs index 52b126cf4b8..785f321b6af 100644 --- a/src/fsharp/fsi/fsi.fs +++ b/src/fsharp/fsi/fsi.fs @@ -762,7 +762,7 @@ type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, inputFilesAcc // We need a dependency provider with native resolution. Managed resolution is handled by generated `#r` - let dependencyProvider = new DependencyProvider(null, NativeResolutionProbe(tcConfigB.GetNativeProbingRoots)) + let dependencyProvider = new DependencyProvider(NativeResolutionProbe(tcConfigB.GetNativeProbingRoots)) do if tcConfigB.utf8output then @@ -1486,6 +1486,16 @@ type internal FsiDynamicCompiler try let result = fsiOptions.DependencyProvider.Resolve(dependencyManager, ".fsx", packageManagerTextLines, reportError m, executionTfm, executionRid, tcConfigB.implicitIncludeDir, "stdin.fsx", "stdin.fsx") if result.Success then + for line in result.StdOut do Console.Out.WriteLine(line) + for line in result.StdError do Console.Error.WriteLine(line) + tcConfigB.packageManagerLines <- PackageManagerLine.SetLinesAsProcessed packageManagerKey tcConfigB.packageManagerLines + for folder in result.Roots do + tcConfigB.AddIncludePath(m, folder, "") + let scripts = result.SourceFiles |> Seq.toList + if not (isNil scripts) then + fsiDynamicCompiler.EvalSourceFiles(ctok, istate, m, scripts, lexResourceManager, errorLogger) + else istate + else // Send outputs via diagnostics if (result.StdOut.Length > 0 || result.StdError.Length > 0) then for line in Array.append result.StdOut result.StdError do @@ -1496,16 +1506,6 @@ type internal FsiDynamicCompiler tcConfigB.packageManagerLines <- PackageManagerLine.RemoveUnprocessedLines packageManagerKey tcConfigB.packageManagerLines istate // error already reported - else - for line in result.StdOut do Console.Out.WriteLine(line) - for line in result.StdError do Console.Error.WriteLine(line) - tcConfigB.packageManagerLines <- PackageManagerLine.SetLinesAsProcessed packageManagerKey tcConfigB.packageManagerLines - for folder in result.Roots do - tcConfigB.AddIncludePath(m, folder, "") - let scripts = result.SourceFiles |> Seq.toList - if not (isNil scripts) then - fsiDynamicCompiler.EvalSourceFiles(ctok, istate, m, scripts, lexResourceManager, errorLogger) - else istate with _ -> // An exception occured during processing, so remove the lines causing the error from the package manager list. diff --git a/src/fsharp/service/FSharpCheckerResults.fs b/src/fsharp/service/FSharpCheckerResults.fs index 3fb85438d9d..4835516ef03 100644 --- a/src/fsharp/service/FSharpCheckerResults.fs +++ b/src/fsharp/service/FSharpCheckerResults.fs @@ -1051,7 +1051,21 @@ type internal TypeCheckInfo let tip = wordL (TaggedTextOps.tagStringLiteral((resolved.prepareToolTip ()).TrimEnd([|'\n'|]))) FSharpStructuredToolTipText.FSharpToolTipText [FSharpStructuredToolTipElement.Single(tip, FSharpXmlDoc.None)] - | [] -> FSharpStructuredToolTipText.FSharpToolTipText [] + | [] -> + let matches = + match loadClosure with + | None -> None + | Some(loadClosure) -> + loadClosure.PackageReferences + |> Array.tryFind (fun (m, _) -> Range.rangeContainsPos m pos) + match matches with + | None -> FSharpStructuredToolTipText.FSharpToolTipText [] + | Some (_, lines) -> + let lines = lines |> List.filter (fun line -> not (line.StartsWith("//")) && not (String.IsNullOrEmpty line)) + FSharpStructuredToolTipText.FSharpToolTipText + [ for line in lines -> + let tip = wordL (TaggedTextOps.tagStringLiteral line) + FSharpStructuredToolTipElement.Single(tip, FSharpXmlDoc.None)] ErrorScope.Protect Range.range0 dataTipOfReferences diff --git a/src/fsharp/xlf/FSComp.txt.cs.xlf b/src/fsharp/xlf/FSComp.txt.cs.xlf index 61c2bae4b46..e9acb86e59e 100644 --- a/src/fsharp/xlf/FSComp.txt.cs.xlf +++ b/src/fsharp/xlf/FSComp.txt.cs.xlf @@ -547,6 +547,11 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference + + This XML comment is incomplete: no documentation for parameter '{0}' + This XML comment is incomplete: no documentation for parameter '{0}' + + This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.de.xlf b/src/fsharp/xlf/FSComp.txt.de.xlf index 6a92990438f..3c0d46acc35 100644 --- a/src/fsharp/xlf/FSComp.txt.de.xlf +++ b/src/fsharp/xlf/FSComp.txt.de.xlf @@ -547,6 +547,11 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference + + This XML comment is incomplete: no documentation for parameter '{0}' + This XML comment is incomplete: no documentation for parameter '{0}' + + This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.es.xlf b/src/fsharp/xlf/FSComp.txt.es.xlf index 3b3121581b0..0031981ab89 100644 --- a/src/fsharp/xlf/FSComp.txt.es.xlf +++ b/src/fsharp/xlf/FSComp.txt.es.xlf @@ -547,6 +547,11 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference + + This XML comment is incomplete: no documentation for parameter '{0}' + This XML comment is incomplete: no documentation for parameter '{0}' + + This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.fr.xlf b/src/fsharp/xlf/FSComp.txt.fr.xlf index 406af22207c..6e88e4dc6d9 100644 --- a/src/fsharp/xlf/FSComp.txt.fr.xlf +++ b/src/fsharp/xlf/FSComp.txt.fr.xlf @@ -547,6 +547,11 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference + + This XML comment is incomplete: no documentation for parameter '{0}' + This XML comment is incomplete: no documentation for parameter '{0}' + + This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.it.xlf b/src/fsharp/xlf/FSComp.txt.it.xlf index 979e79be664..99cbcf543c3 100644 --- a/src/fsharp/xlf/FSComp.txt.it.xlf +++ b/src/fsharp/xlf/FSComp.txt.it.xlf @@ -547,6 +547,11 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference + + This XML comment is incomplete: no documentation for parameter '{0}' + This XML comment is incomplete: no documentation for parameter '{0}' + + This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.ja.xlf b/src/fsharp/xlf/FSComp.txt.ja.xlf index 7838deb1ae3..4c29a908bd4 100644 --- a/src/fsharp/xlf/FSComp.txt.ja.xlf +++ b/src/fsharp/xlf/FSComp.txt.ja.xlf @@ -7577,6 +7577,11 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference + + This XML comment is incomplete: no documentation for parameter '{0}' + This XML comment is incomplete: no documentation for parameter '{0}' + + This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.ko.xlf b/src/fsharp/xlf/FSComp.txt.ko.xlf index c07b4d8f477..8ed7956c52e 100644 --- a/src/fsharp/xlf/FSComp.txt.ko.xlf +++ b/src/fsharp/xlf/FSComp.txt.ko.xlf @@ -547,6 +547,11 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference + + This XML comment is incomplete: no documentation for parameter '{0}' + This XML comment is incomplete: no documentation for parameter '{0}' + + This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.pl.xlf b/src/fsharp/xlf/FSComp.txt.pl.xlf index 3a2ea249485..583c9f600ac 100644 --- a/src/fsharp/xlf/FSComp.txt.pl.xlf +++ b/src/fsharp/xlf/FSComp.txt.pl.xlf @@ -547,6 +547,11 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference + + This XML comment is incomplete: no documentation for parameter '{0}' + This XML comment is incomplete: no documentation for parameter '{0}' + + This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf index d0cc3dcb8d6..a0de9958e4a 100644 --- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf +++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf @@ -547,6 +547,11 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference + + This XML comment is incomplete: no documentation for parameter '{0}' + This XML comment is incomplete: no documentation for parameter '{0}' + + This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.ru.xlf b/src/fsharp/xlf/FSComp.txt.ru.xlf index f0c7592f7aa..ebcf5516d57 100644 --- a/src/fsharp/xlf/FSComp.txt.ru.xlf +++ b/src/fsharp/xlf/FSComp.txt.ru.xlf @@ -547,6 +547,11 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference + + This XML comment is incomplete: no documentation for parameter '{0}' + This XML comment is incomplete: no documentation for parameter '{0}' + + This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.tr.xlf b/src/fsharp/xlf/FSComp.txt.tr.xlf index a7607195a55..b40d65f419f 100644 --- a/src/fsharp/xlf/FSComp.txt.tr.xlf +++ b/src/fsharp/xlf/FSComp.txt.tr.xlf @@ -547,6 +547,11 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference + + This XML comment is incomplete: no documentation for parameter '{0}' + This XML comment is incomplete: no documentation for parameter '{0}' + + This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf index a844ffd56a5..e73e1ce34ac 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf @@ -547,6 +547,11 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference + + This XML comment is incomplete: no documentation for parameter '{0}' + This XML comment is incomplete: no documentation for parameter '{0}' + + This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf index 971f74e3461..5e7fdd53e0d 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf @@ -547,6 +547,11 @@ This XML comment is invalid: missing 'cref' attribute for cross-reference + + This XML comment is incomplete: no documentation for parameter '{0}' + This XML comment is incomplete: no documentation for parameter '{0}' + + This XML comment is invalid: missing 'name' attribute for parameter or parameter reference This XML comment is invalid: missing 'name' attribute for parameter or parameter reference diff --git a/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs b/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs index 5810202d7af..387caea14d9 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs @@ -105,7 +105,7 @@ type internal FSharpAddOpenCodeFixProvider let! symbol = asyncMaybe { - let! lexerSymbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, context.Span.End, document.FilePath, defines, SymbolLookupKind.Greedy, false) + let! lexerSymbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, context.Span.End, document.FilePath, defines, SymbolLookupKind.Greedy, false, false) return! checkResults.GetSymbolUseAtLocation(Line.fromZ linePos.Line, lexerSymbol.Ident.idRange.EndColumn, line.ToString(), lexerSymbol.FullIsland, userOpName=userOpName) } |> liftAsync diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs b/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs index 4f995284b90..2415fa3baca 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs @@ -169,7 +169,7 @@ type internal FSharpImplementInterfaceCodeFixProvider | _ -> Some context.Span.End let! interfaceState = queryInterfaceState appendBracketAt interfacePos tokens parsedInput - let! symbol = Tokenizer.getSymbolAtPosition(context.Document.Id, sourceText, fixupPosition, context.Document.FilePath, defines, SymbolLookupKind.Greedy, false) + let! symbol = Tokenizer.getSymbolAtPosition(context.Document.Id, sourceText, fixupPosition, context.Document.FilePath, defines, SymbolLookupKind.Greedy, false, false) let fcsTextLineNumber = textLine.LineNumber + 1 let lineContents = textLine.ToString() let! options = context.Document.GetOptionsAsync(cancellationToken) diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs b/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs index d4f564f75f3..2a185cdbb8e 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs @@ -61,7 +61,7 @@ type internal FSharpRenameUnusedValueCodeFixProvider let! _, _, checkResults = checker.ParseAndCheckDocument(document, projectOptions, sourceText = sourceText, userOpName=userOpName) let m = RoslynHelpers.TextSpanToFSharpRange(document.FilePath, context.Span, sourceText) let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions - let! lexerSymbol = Tokenizer.getSymbolAtPosition (document.Id, sourceText, context.Span.Start, document.FilePath, defines, SymbolLookupKind.Greedy, false) + let! lexerSymbol = Tokenizer.getSymbolAtPosition (document.Id, sourceText, context.Span.Start, document.FilePath, defines, SymbolLookupKind.Greedy, false, false) let lineText = (sourceText.Lines.GetLineFromPosition context.Span.Start).ToString() let! symbolUse = checkResults.GetSymbolUseAtLocation(m.StartLine, m.EndColumn, lineText, lexerSymbol.FullIsland, userOpName=userOpName) let symbolName = symbolUse.Symbol.DisplayName diff --git a/vsintegration/src/FSharp.Editor/DocumentHighlights/DocumentHighlightsService.fs b/vsintegration/src/FSharp.Editor/DocumentHighlights/DocumentHighlightsService.fs index 6ceb996cf1e..ade8eb32a8f 100644 --- a/vsintegration/src/FSharp.Editor/DocumentHighlights/DocumentHighlightsService.fs +++ b/vsintegration/src/FSharp.Editor/DocumentHighlights/DocumentHighlightsService.fs @@ -58,7 +58,7 @@ type internal FSharpDocumentHighlightsService [] (checkerP let textLine = sourceText.Lines.GetLineFromPosition(position) let textLinePos = sourceText.Lines.GetLinePosition(position) let fcsTextLineNumber = Line.fromZ textLinePos.Line - let! symbol = Tokenizer.getSymbolAtPosition(documentKey, sourceText, position, filePath, defines, SymbolLookupKind.Greedy, false) + let! symbol = Tokenizer.getSymbolAtPosition(documentKey, sourceText, position, filePath, defines, SymbolLookupKind.Greedy, false, false) let! _, _, checkFileResults = checker.ParseAndCheckDocument(filePath, textVersionHash, sourceText, options, languageServicePerformanceOptions, userOpName = userOpName) let! symbolUse = checkFileResults.GetSymbolUseAtLocation(fcsTextLineNumber, symbol.Ident.idRange.EndColumn, textLine.ToString(), symbol.FullIsland, userOpName=userOpName) let! symbolUses = checkFileResults.GetUsesOfSymbolInFile(symbolUse.Symbol) |> liftAsync diff --git a/vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs b/vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs index 9d05c920b8e..15704641c09 100644 --- a/vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs +++ b/vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs @@ -155,7 +155,7 @@ type internal InlineRenameService let textLine = sourceText.Lines.GetLineFromPosition(position) let textLinePos = sourceText.Lines.GetLinePosition(position) let fcsTextLineNumber = Line.fromZ textLinePos.Line - let! symbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, false) + let! symbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, false, false) let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, options, userOpName = userOpName) let! symbolUse = checkFileResults.GetSymbolUseAtLocation(fcsTextLineNumber, symbol.Ident.idRange.EndColumn, textLine.Text.ToString(), symbol.FullIsland, userOpName=userOpName) let! declLoc = symbolUse.GetDeclarationLocation(document) diff --git a/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs b/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs index 22100b4f158..37635ea5d69 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs @@ -27,7 +27,7 @@ module internal SymbolHelpers = let fcsTextLineNumber = Line.fromZ textLinePos.Line let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions - let! symbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, false) + let! symbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, false, false) let settings = document.FSharpOptions let! _, _, checkFileResults = checker.ParseAndCheckDocument(document.FilePath, textVersionHash, sourceText, projectOptions, settings.LanguageServicePerformance, userOpName = userOpName) let! symbolUse = checkFileResults.GetSymbolUseAtLocation(fcsTextLineNumber, symbol.Ident.idRange.EndColumn, textLine.ToString(), symbol.FullIsland, userOpName=userOpName) @@ -120,7 +120,7 @@ module internal SymbolHelpers = do! Option.guard (originalText.Length > 0) let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions - let! symbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, symbolSpan.Start, document.FilePath, defines, SymbolLookupKind.Greedy, false) + let! symbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, symbolSpan.Start, document.FilePath, defines, SymbolLookupKind.Greedy, false, false) let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, projectOptions, userOpName = userOpName) let textLine = sourceText.Lines.GetLineFromPosition(symbolSpan.Start) let textLinePos = sourceText.Lines.GetLinePosition(symbolSpan.Start) diff --git a/vsintegration/src/FSharp.Editor/LanguageService/Tokenizer.fs b/vsintegration/src/FSharp.Editor/LanguageService/Tokenizer.fs index 0c48144db02..2ecc21caf0d 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/Tokenizer.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/Tokenizer.fs @@ -33,7 +33,8 @@ type internal LexerSymbolKind = | GenericTypeParameter = 3 | StaticallyResolvedTypeParameter = 4 | ActivePattern = 5 - | Other = 6 + | String = 6 + | Other = 7 type internal LexerSymbol = { Kind: LexerSymbolKind @@ -147,11 +148,14 @@ module internal Tokenizer = | FSharpGlyph.Variable -> Glyph.Local | FSharpGlyph.Error -> Glyph.Error - let GetImageIdForSymbol(symbol:FSharpSymbol, kind:LexerSymbolKind) = + let GetImageIdForSymbol(symbolOpt:FSharpSymbol option, kind:LexerSymbolKind) = let imageId = match kind with | LexerSymbolKind.Operator -> KnownImageIds.Operator | _ -> + match symbolOpt with + | None -> KnownImageIds.Package + | Some symbol -> match symbol with | :? FSharpUnionCase as x -> match Some x.Accessibility with @@ -345,6 +349,7 @@ module internal Tokenizer = member token.IsIdentifier = (token.CharClass = FSharpTokenCharKind.Identifier) member token.IsOperator = (token.ColorClass = FSharpTokenColorKind.Operator) member token.IsPunctuation = (token.ColorClass = FSharpTokenColorKind.Punctuation) + member token.IsString = (token.ColorClass = FSharpTokenColorKind.String) /// This is the information we save for each token in a line for each active document. /// It is a memory-critical data structure - do not make larger. This used to be ~100 bytes class, is now 8-byte struct @@ -375,6 +380,7 @@ module internal Tokenizer = if token.IsOperator then LexerSymbolKind.Operator elif token.IsIdentifier then LexerSymbolKind.Ident elif token.IsPunctuation then LexerSymbolKind.Punctuation + elif token.IsString then LexerSymbolKind.String else LexerSymbolKind.Other Debug.Assert(uint32 token.Tag < 0xFFFFu) Debug.Assert(uint32 kind < 0xFFu) @@ -612,7 +618,8 @@ module internal Tokenizer = linePos: LinePosition, lineStr: string, lookupKind: SymbolLookupKind, - wholeActivePatterns: bool + wholeActivePatterns: bool, + allowStringToken: bool ) : LexerSymbol option = @@ -704,6 +711,7 @@ module internal Tokenizer = | LexerSymbolKind.StaticallyResolvedTypeParameter -> true | _ -> false) |> Option.orElseWith (fun _ -> tokensUnderCursor |> List.tryFind (fun token -> token.Kind = LexerSymbolKind.Operator)) + |> Option.orElseWith (fun _ -> if allowStringToken then tokensUnderCursor |> List.tryFind (fun token -> token.Kind = LexerSymbolKind.String) else None) |> Option.map (fun token -> let partialName = QuickParse.GetPartialLongNameEx(lineStr, token.RightColumn) let identStr = lineStr.Substring(token.LeftColumn, token.MatchedLength) @@ -767,13 +775,14 @@ module internal Tokenizer = fileName: string, defines: string list, lookupKind: SymbolLookupKind, - wholeActivePatterns: bool + wholeActivePatterns: bool, + allowStringToken: bool ) : LexerSymbol option = try let lineData, textLinePos, lineContents = getCachedSourceLineData(documentKey, sourceText, position, fileName, defines) - getSymbolFromSavedTokens(fileName, lineData.SavedTokens, textLinePos, lineContents, lookupKind, wholeActivePatterns) + getSymbolFromSavedTokens(fileName, lineData.SavedTokens, textLinePos, lineContents, lookupKind, wholeActivePatterns, allowStringToken) with | :? System.OperationCanceledException -> reraise() | ex -> diff --git a/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs b/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs index f742a679474..9988f74d6c6 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs @@ -57,7 +57,7 @@ type internal FSharpFindUsagesService let lineNumber = sourceText.Lines.GetLinePosition(position).Line + 1 let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions - let! symbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, false) + let! symbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, false, false) let! symbolUse = checkFileResults.GetSymbolUseAtLocation(lineNumber, symbol.Ident.idRange.EndColumn, textLine, symbol.FullIsland, userOpName=userOpName) let! declaration = checkFileResults.GetDeclarationLocation (lineNumber, symbol.Ident.idRange.EndColumn, textLine, symbol.FullIsland, false, userOpName=userOpName) |> liftAsync let tags = FSharpGlyphTags.GetTags(Tokenizer.GetGlyphForSymbol (symbolUse.Symbol, symbol.Kind)) diff --git a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs index 4c3c00e6943..18221c0f316 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs @@ -172,7 +172,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions let! originTextSpan = RoslynHelpers.TryFSharpRangeToTextSpan (sourceText, originRange) let position = originTextSpan.Start - let! lexerSymbol = Tokenizer.getSymbolAtPosition (originDocument.Id, sourceText, position, originDocument.FilePath, defines, SymbolLookupKind.Greedy, false) + let! lexerSymbol = Tokenizer.getSymbolAtPosition (originDocument.Id, sourceText, position, originDocument.FilePath, defines, SymbolLookupKind.Greedy, false, false) let textLinePos = sourceText.Lines.GetLinePosition position let fcsTextLineNumber = Line.fromZ textLinePos.Line @@ -232,7 +232,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP let! _, _, checkFileResults = checker.ParseAndCheckDocument (originDocument, projectOptions, sourceText=sourceText, userOpName=userOpName) - let! lexerSymbol = Tokenizer.getSymbolAtPosition (originDocument.Id, sourceText, position,originDocument.FilePath, defines, SymbolLookupKind.Greedy, false) + let! lexerSymbol = Tokenizer.getSymbolAtPosition (originDocument.Id, sourceText, position,originDocument.FilePath, defines, SymbolLookupKind.Greedy, false, false) let idRange = lexerSymbol.Ident.idRange let! declarations = checkFileResults.GetDeclarationLocation (fcsTextLineNumber, lexerSymbol.Ident.idRange.EndColumn, textLine.ToString(), lexerSymbol.FullIsland, preferSignature, userOpName=userOpName) |> liftAsync diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs index cd5d0fc143e..f5e4b1611f1 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs @@ -26,7 +26,7 @@ open Internal.Utilities.StructuredFormat type internal QuickInfo = { StructuredText: FSharpStructuredToolTipText Span: TextSpan - Symbol: FSharpSymbol + Symbol: FSharpSymbol option SymbolKind: LexerSymbolKind } module internal FSharpQuickInfo = @@ -58,7 +58,7 @@ module internal FSharpQuickInfo = // project options need to be retrieved because the signature file could be in another project let! extParsingOptions, extProjectOptions = projectInfoManager.TryGetOptionsByProject(document.Project, cancellationToken) let extDefines = CompilerEnvironment.GetCompilationDefinesForEditing extParsingOptions - let! extLexerSymbol = Tokenizer.getSymbolAtPosition(extDocId, extSourceText, extSpan.Start, declRange.FileName, extDefines, SymbolLookupKind.Greedy, true) + let! extLexerSymbol = Tokenizer.getSymbolAtPosition(extDocId, extSourceText, extSpan.Start, declRange.FileName, extDefines, SymbolLookupKind.Greedy, true, true) let! _, _, extCheckFileResults = checker.ParseAndCheckDocument(extDocument, extProjectOptions, allowStaleResults=true, sourceText=extSourceText, userOpName = userOpName) let! extQuickInfoText = @@ -75,7 +75,7 @@ module internal FSharpQuickInfo = return { StructuredText = extQuickInfoText Span = span - Symbol = extSymbolUse.Symbol + Symbol = Some extSymbolUse.Symbol SymbolKind = extLexerSymbol.Kind } } @@ -88,26 +88,25 @@ module internal FSharpQuickInfo = position: int, cancellationToken: CancellationToken ) - : Async<(FSharpSymbolUse * QuickInfo option * QuickInfo option) option> = + : Async<(range * QuickInfo option * QuickInfo option) option> = asyncMaybe { let! sourceText = document.GetTextAsync cancellationToken let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions - let! lexerSymbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, true) + let! lexerSymbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, true, true) let idRange = lexerSymbol.Ident.idRange let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, projectOptions, allowStaleResults = true, sourceText=sourceText, userOpName = userOpName) let textLinePos = sourceText.Lines.GetLinePosition position let fcsTextLineNumber = Line.fromZ textLinePos.Line let lineText = (sourceText.Lines.GetLineFromPosition position).ToString() - let! symbolUse = checkFileResults.GetSymbolUseAtLocation (fcsTextLineNumber, idRange.EndColumn, lineText, lexerSymbol.FullIsland, userOpName=userOpName) /// Gets the QuickInfo information for the orignal target - let getTargetSymbolQuickInfo () = + let getTargetSymbolQuickInfo (symbol, tag) = asyncMaybe { let! targetQuickInfo = checkFileResults.GetStructuredToolTipText - (fcsTextLineNumber, idRange.EndColumn, lineText, lexerSymbol.FullIsland, FSharpTokenTag.IDENT, userOpName=userOpName) |> liftAsync + (fcsTextLineNumber, idRange.EndColumn, lineText, lexerSymbol.FullIsland,tag, userOpName=userOpName) |> liftAsync match targetQuickInfo with | FSharpToolTipText [] @@ -116,21 +115,29 @@ module internal FSharpQuickInfo = let! targetTextSpan = RoslynHelpers.TryFSharpRangeToTextSpan (sourceText, lexerSymbol.Range) return { StructuredText = targetQuickInfo Span = targetTextSpan - Symbol = symbolUse.Symbol + Symbol = symbol SymbolKind = lexerSymbol.Kind } } + match lexerSymbol.Kind with + | LexerSymbolKind.String -> + let! targetQuickInfo = getTargetSymbolQuickInfo (None, FSharpTokenTag.STRING) + return lexerSymbol.Range, None, Some targetQuickInfo + + | _ -> + let! symbolUse = checkFileResults.GetSymbolUseAtLocation (fcsTextLineNumber, idRange.EndColumn, lineText, lexerSymbol.FullIsland, userOpName=userOpName) + // if the target is in a signature file, adjusting the quick info is unnecessary if isSignatureFile document.FilePath then - let! targetQuickInfo = getTargetSymbolQuickInfo() - return symbolUse, None, Some targetQuickInfo + let! targetQuickInfo = getTargetSymbolQuickInfo (Some symbolUse.Symbol, FSharpTokenTag.IDENT) + return symbolUse.RangeAlternate, None, Some targetQuickInfo else // find the declaration location of the target symbol, with a preference for signature files let! findSigDeclarationResult = checkFileResults.GetDeclarationLocation (idRange.StartLine, idRange.EndColumn, lineText, lexerSymbol.FullIsland, preferFlag=true, userOpName=userOpName) |> liftAsync // it is necessary to retrieve the backup quick info because this acquires // the textSpan designating where we want the quick info to appear. - let! targetQuickInfo = getTargetSymbolQuickInfo() + let! targetQuickInfo = getTargetSymbolQuickInfo (Some symbolUse.Symbol, FSharpTokenTag.IDENT) let! result = match findSigDeclarationResult with @@ -146,15 +153,16 @@ module internal FSharpQuickInfo = match findImplDefinitionResult with | FSharpFindDeclResult.DeclNotFound _ - | FSharpFindDeclResult.ExternalDecl _ -> return symbolUse, Some sigQuickInfo, None + | FSharpFindDeclResult.ExternalDecl _ -> + return symbolUse.RangeAlternate, Some sigQuickInfo, None | FSharpFindDeclResult.DeclFound declRange -> let! implQuickInfo = getQuickInfoFromRange(checker, projectInfoManager, document, declRange, cancellationToken) - return symbolUse, Some sigQuickInfo, Some { implQuickInfo with Span = targetQuickInfo.Span } + return symbolUse.RangeAlternate, Some sigQuickInfo, Some { implQuickInfo with Span = targetQuickInfo.Span } } | _ -> async.Return None |> liftAsync - return result |> Option.defaultValue (symbolUse, None, Some targetQuickInfo) + return result |> Option.defaultValue (symbolUse.RangeAlternate, None, Some targetQuickInfo) } type internal FSharpAsyncQuickInfoSource @@ -180,7 +188,7 @@ type internal FSharpAsyncQuickInfoSource let textLine = sourceText.Lines.GetLineFromPosition position let textLineNumber = textLine.LineNumber + 1 // Roslyn line numbers are zero-based let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions - let! symbol = Tokenizer.getSymbolAtPosition (documentId, sourceText, position, filePath, defines, SymbolLookupKind.Precise, true) + let! symbol = Tokenizer.getSymbolAtPosition (documentId, sourceText, position, filePath, defines, SymbolLookupKind.Precise, true, true) let! res = checkFileResults.GetStructuredToolTipText (textLineNumber, symbol.Ident.idRange.EndColumn, textLine.ToString(), symbol.FullIsland, FSharpTokenTag.IDENT, userOpName=FSharpQuickInfo.userOpName) |> liftAsync match res with | FSharpToolTipText [] @@ -190,7 +198,7 @@ type internal FSharpAsyncQuickInfoSource let! symbolSpan = RoslynHelpers.TryFSharpRangeToTextSpan (sourceText, symbol.Range) return { StructuredText = res Span = symbolSpan - Symbol = symbolUse.Symbol + Symbol = Some symbolUse.Symbol SymbolKind = symbol.Kind } } @@ -211,20 +219,20 @@ type internal FSharpAsyncQuickInfoSource | false -> Task.FromResult(null) | true -> let triggerPoint = triggerPoint.GetValueOrDefault() - let documentationBuilder = XmlDocumentation.CreateDocumentationBuilder(xmlMemberIndexService) asyncMaybe { let document = textBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges() - let! symbolUse, sigQuickInfo, targetQuickInfo = FSharpQuickInfo.getQuickInfo(checkerProvider.Checker, projectInfoManager, document, triggerPoint.Position, cancellationToken) + let! symbolUseRange, sigQuickInfo, targetQuickInfo = FSharpQuickInfo.getQuickInfo(checkerProvider.Checker, projectInfoManager, document, triggerPoint.Position, cancellationToken) let getTrackingSpan (span:TextSpan) = textBuffer.CurrentSnapshot.CreateTrackingSpan(span.Start, span.Length, SpanTrackingMode.EdgeInclusive) + let documentationBuilder = XmlDocumentation.CreateDocumentationBuilder(xmlMemberIndexService) match sigQuickInfo, targetQuickInfo with | None, None -> return null | Some quickInfo, None - | None, Some quickInfo-> + | None, Some quickInfo -> let mainDescription, docs = FSharpAsyncQuickInfoSource.BuildSingleQuickInfoItem documentationBuilder quickInfo let imageId = Tokenizer.GetImageIdForSymbol(quickInfo.Symbol, quickInfo.SymbolKind) - let navigation = QuickInfoNavigation(statusBar, checkerProvider.Checker, projectInfoManager, document, symbolUse.RangeAlternate) + let navigation = QuickInfoNavigation(statusBar, checkerProvider.Checker, projectInfoManager, document, symbolUseRange) let content = QuickInfoViewProvider.provideContent(imageId, mainDescription, docs, navigation) let span = getTrackingSpan quickInfo.Span return QuickInfoItem(span, content) @@ -254,7 +262,7 @@ type internal FSharpAsyncQuickInfoSource ] |> ResizeArray let docs = joinWithLineBreaks [documentation; typeParameterMap; usage; exceptions] let imageId = Tokenizer.GetImageIdForSymbol(targetQuickInfo.Symbol, targetQuickInfo.SymbolKind) - let navigation = QuickInfoNavigation(statusBar, checkerProvider.Checker, projectInfoManager, document, symbolUse.RangeAlternate) + let navigation = QuickInfoNavigation(statusBar, checkerProvider.Checker, projectInfoManager, document, symbolUseRange) let content = QuickInfoViewProvider.provideContent(imageId, mainDescription, docs, navigation) let span = getTrackingSpan targetQuickInfo.Span return QuickInfoItem(span, content) diff --git a/vsintegration/tests/UnitTests/GoToDefinitionServiceTests.fs b/vsintegration/tests/UnitTests/GoToDefinitionServiceTests.fs index 755b66ca085..4408b27e5ac 100644 --- a/vsintegration/tests/UnitTests/GoToDefinitionServiceTests.fs +++ b/vsintegration/tests/UnitTests/GoToDefinitionServiceTests.fs @@ -52,7 +52,7 @@ module GoToDefinitionServiceTests = let textLine = sourceText.Lines.GetLineFromPosition position let textLinePos = sourceText.Lines.GetLinePosition position let fcsTextLineNumber = Line.fromZ textLinePos.Line - let! lexerSymbol = Tokenizer.getSymbolAtPosition(documentKey, sourceText, position, filePath, defines, SymbolLookupKind.Greedy, false) + let! lexerSymbol = Tokenizer.getSymbolAtPosition(documentKey, sourceText, position, filePath, defines, SymbolLookupKind.Greedy, false, false) let! _, _, checkFileResults = checker.ParseAndCheckDocument (filePath, textVersionHash, sourceText, options, LanguageServicePerformanceOptions.Default, userOpName=userOpName) |> Async.RunSynchronously let declarations = checkFileResults.GetDeclarationLocation (fcsTextLineNumber, lexerSymbol.Ident.idRange.EndColumn, textLine.ToString(), lexerSymbol.FullIsland, false, userOpName=userOpName) |> Async.RunSynchronously From 24c13ac26cd2e5e1eb508df069305f923e3e185b Mon Sep 17 00:00:00 2001 From: Don Syme Date: Sun, 20 Sep 2020 12:36:44 +0100 Subject: [PATCH 09/12] update baseline --- tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs index 3a26973ad29..8582f212786 100644 --- a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs +++ b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs @@ -42401,6 +42401,7 @@ Microsoft.DotNet.DependencyManager.DependencyProvider: System.Tuple`2[System.Int Microsoft.DotNet.DependencyManager.DependencyProvider: System.Tuple`2[System.String,Microsoft.DotNet.DependencyManager.IDependencyManagerProvider] TryFindDependencyManagerInPath(System.Collections.Generic.IEnumerable`1[System.String], System.String, Microsoft.DotNet.DependencyManager.ResolvingErrorReport, System.String) Microsoft.DotNet.DependencyManager.DependencyProvider: Void .ctor(Microsoft.DotNet.DependencyManager.AssemblyResolutionProbe, Microsoft.DotNet.DependencyManager.NativeResolutionProbe) Microsoft.DotNet.DependencyManager.DependencyProvider: Void .ctor(Microsoft.DotNet.DependencyManager.NativeResolutionProbe) +Microsoft.DotNet.DependencyManager.DependencyProvider: Void .ctor() Microsoft.DotNet.DependencyManager.ErrorReportType+Tags: Int32 Error Microsoft.DotNet.DependencyManager.ErrorReportType+Tags: Int32 Warning Microsoft.DotNet.DependencyManager.ErrorReportType: Boolean Equals(Microsoft.DotNet.DependencyManager.ErrorReportType) From 9a5db5b25c229c46190814fcd0bd9a2726f09252 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Sun, 20 Sep 2020 13:07:51 +0100 Subject: [PATCH 10/12] fix test --- src/fsharp/CompileOps.fs | 2 -- src/fsharp/FSComp.txt | 3 +-- src/fsharp/fsi/fsi.fs | 2 -- src/fsharp/xlf/FSComp.txt.cs.xlf | 5 ----- src/fsharp/xlf/FSComp.txt.de.xlf | 5 ----- src/fsharp/xlf/FSComp.txt.es.xlf | 5 ----- src/fsharp/xlf/FSComp.txt.fr.xlf | 5 ----- src/fsharp/xlf/FSComp.txt.it.xlf | 5 ----- src/fsharp/xlf/FSComp.txt.ja.xlf | 5 ----- src/fsharp/xlf/FSComp.txt.ko.xlf | 5 ----- src/fsharp/xlf/FSComp.txt.pl.xlf | 5 ----- src/fsharp/xlf/FSComp.txt.pt-BR.xlf | 5 ----- src/fsharp/xlf/FSComp.txt.ru.xlf | 5 ----- src/fsharp/xlf/FSComp.txt.tr.xlf | 5 ----- src/fsharp/xlf/FSComp.txt.zh-Hans.xlf | 5 ----- src/fsharp/xlf/FSComp.txt.zh-Hant.xlf | 5 ----- .../DependencyManagerInteractiveTests.fs | 2 +- 17 files changed, 2 insertions(+), 72 deletions(-) diff --git a/src/fsharp/CompileOps.fs b/src/fsharp/CompileOps.fs index 3904c18d06d..0759d5899fa 100644 --- a/src/fsharp/CompileOps.fs +++ b/src/fsharp/CompileOps.fs @@ -5491,8 +5491,6 @@ module ScriptPreprocessClosure = if (result.StdOut.Length > 0 || result.StdError.Length > 0) then for line in Array.append result.StdOut result.StdError do errorR(Error(FSComp.SR.packageManagerError(line), m)) - else - warning(Error(FSComp.SR.packageManagerFailedNoOutput(), m)) // Resolution produced errors update packagerManagerLines entries to note these failure // failed resolutions will no longer be considered let tcConfigB = tcConfig.CloneOfOriginalBuilder diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 3bfebdb442a..7914b2e6919 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1546,5 +1546,4 @@ forFormatInvalidForInterpolated4,"Interpolated strings used as type IFormattable 3390,xmlDocInvalidParameterName,"This XML comment is invalid: unknown parameter '%s'" 3390,xmlDocDuplicateParameter,"This XML comment is invalid: multiple documentation entries for parameter '%s'" 3390,xmlDocUnresolvedCrossReference,"This XML comment is invalid: unresolved cross-reference '%s'" -3390,xmlDocMissingParameter,"This XML comment is incomplete: no documentation for parameter '%s'" -3393,packageManagerFailedNoOutput,"Package manager failed without output" \ No newline at end of file +3390,xmlDocMissingParameter,"This XML comment is incomplete: no documentation for parameter '%s'" \ No newline at end of file diff --git a/src/fsharp/fsi/fsi.fs b/src/fsharp/fsi/fsi.fs index 785f321b6af..40850bd7749 100644 --- a/src/fsharp/fsi/fsi.fs +++ b/src/fsharp/fsi/fsi.fs @@ -1500,8 +1500,6 @@ type internal FsiDynamicCompiler if (result.StdOut.Length > 0 || result.StdError.Length > 0) then for line in Array.append result.StdOut result.StdError do errorR(Error(FSComp.SR.packageManagerError(line), m)) - else - warning(Error(FSComp.SR.packageManagerFailedNoOutput(), m)) //Write outputs in F# Interactive and compiler tcConfigB.packageManagerLines <- PackageManagerLine.RemoveUnprocessedLines packageManagerKey tcConfigB.packageManagerLines istate // error already reported diff --git a/src/fsharp/xlf/FSComp.txt.cs.xlf b/src/fsharp/xlf/FSComp.txt.cs.xlf index e9acb86e59e..9839f7d0bca 100644 --- a/src/fsharp/xlf/FSComp.txt.cs.xlf +++ b/src/fsharp/xlf/FSComp.txt.cs.xlf @@ -247,11 +247,6 @@ Funkce správy balíčků vyžaduje jazykovou verzi 5.0, použijte /langversion:preview. - - Package manager failed without output - Package manager failed without output - - Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. diff --git a/src/fsharp/xlf/FSComp.txt.de.xlf b/src/fsharp/xlf/FSComp.txt.de.xlf index 3c0d46acc35..f0ddc681111 100644 --- a/src/fsharp/xlf/FSComp.txt.de.xlf +++ b/src/fsharp/xlf/FSComp.txt.de.xlf @@ -247,11 +247,6 @@ Für das Paketverwaltungsfeature ist Sprachversion 5.0 erforderlich. Verwenden Sie /langversion:preview. - - Package manager failed without output - Package manager failed without output - - Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. diff --git a/src/fsharp/xlf/FSComp.txt.es.xlf b/src/fsharp/xlf/FSComp.txt.es.xlf index 0031981ab89..24077dfabb0 100644 --- a/src/fsharp/xlf/FSComp.txt.es.xlf +++ b/src/fsharp/xlf/FSComp.txt.es.xlf @@ -247,11 +247,6 @@ La característica de administración de paquetes requiere la versión de lenguaje 5.0; use /langversion:preview - - Package manager failed without output - Package manager failed without output - - Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. diff --git a/src/fsharp/xlf/FSComp.txt.fr.xlf b/src/fsharp/xlf/FSComp.txt.fr.xlf index 6e88e4dc6d9..505de283f8c 100644 --- a/src/fsharp/xlf/FSComp.txt.fr.xlf +++ b/src/fsharp/xlf/FSComp.txt.fr.xlf @@ -247,11 +247,6 @@ La fonctionnalité de gestion des packages nécessite la version 5.0 du langage. Utilisez /langversion:preview - - Package manager failed without output - Package manager failed without output - - Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. diff --git a/src/fsharp/xlf/FSComp.txt.it.xlf b/src/fsharp/xlf/FSComp.txt.it.xlf index 99cbcf543c3..b6527118704 100644 --- a/src/fsharp/xlf/FSComp.txt.it.xlf +++ b/src/fsharp/xlf/FSComp.txt.it.xlf @@ -247,11 +247,6 @@ Con la funzionalità di gestione pacchetti è richiesta la versione 5.0 del linguaggio. Usare /langversion:preview - - Package manager failed without output - Package manager failed without output - - Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. diff --git a/src/fsharp/xlf/FSComp.txt.ja.xlf b/src/fsharp/xlf/FSComp.txt.ja.xlf index 4c29a908bd4..a361c41ff6b 100644 --- a/src/fsharp/xlf/FSComp.txt.ja.xlf +++ b/src/fsharp/xlf/FSComp.txt.ja.xlf @@ -3857,11 +3857,6 @@ {0} - - Package manager failed without output - Package manager failed without output - - Package manager key '{0}' was not registered in {1}. Currently registered: {2} Package manager key '{0}' was not registered in {1}. Currently registered: {2} diff --git a/src/fsharp/xlf/FSComp.txt.ko.xlf b/src/fsharp/xlf/FSComp.txt.ko.xlf index 8ed7956c52e..a6fcf98469d 100644 --- a/src/fsharp/xlf/FSComp.txt.ko.xlf +++ b/src/fsharp/xlf/FSComp.txt.ko.xlf @@ -247,11 +247,6 @@ 패키지 관리 기능을 사용하려면 언어 버전 5.0이 필요합니다. /langversion:preview를 사용하세요. - - Package manager failed without output - Package manager failed without output - - Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. diff --git a/src/fsharp/xlf/FSComp.txt.pl.xlf b/src/fsharp/xlf/FSComp.txt.pl.xlf index 583c9f600ac..3727ead1dac 100644 --- a/src/fsharp/xlf/FSComp.txt.pl.xlf +++ b/src/fsharp/xlf/FSComp.txt.pl.xlf @@ -247,11 +247,6 @@ Funkcja zarządzania pakietami wymaga języka w wersji 5.0, użyj parametru /langversion:preview - - Package manager failed without output - Package manager failed without output - - Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. diff --git a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf index a0de9958e4a..c6281378ea8 100644 --- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf +++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf @@ -247,11 +247,6 @@ O recurso de gerenciamento de pacotes requer a versão de idioma 5.0. Use /langversion:preview - - Package manager failed without output - Package manager failed without output - - Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. diff --git a/src/fsharp/xlf/FSComp.txt.ru.xlf b/src/fsharp/xlf/FSComp.txt.ru.xlf index ebcf5516d57..afe00bca155 100644 --- a/src/fsharp/xlf/FSComp.txt.ru.xlf +++ b/src/fsharp/xlf/FSComp.txt.ru.xlf @@ -247,11 +247,6 @@ Для функции управления пакетами требуется версия языка 5.0, используйте параметр /langversion:preview - - Package manager failed without output - Package manager failed without output - - Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. diff --git a/src/fsharp/xlf/FSComp.txt.tr.xlf b/src/fsharp/xlf/FSComp.txt.tr.xlf index b40d65f419f..bc142bfc6a0 100644 --- a/src/fsharp/xlf/FSComp.txt.tr.xlf +++ b/src/fsharp/xlf/FSComp.txt.tr.xlf @@ -247,11 +247,6 @@ Paket yönetimi özelliği dil sürümü 5.0 gerektiriyor, /langversion:preview kullanın - - Package manager failed without output - Package manager failed without output - - Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf index e73e1ce34ac..8df687974e5 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf @@ -247,11 +247,6 @@ 包管理功能需要语言版本 5.0,请使用 /langversion:preview - - Package manager failed without output - Package manager failed without output - - Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf index 5e7fdd53e0d..035bd7f69dc 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf @@ -247,11 +247,6 @@ 套件管理功能需要語言版本 5.0,請使用 /langversion:preview - - Package manager failed without output - Package manager failed without output - - Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected. diff --git a/tests/FSharp.Compiler.Private.Scripting.UnitTests/DependencyManagerInteractiveTests.fs b/tests/FSharp.Compiler.Private.Scripting.UnitTests/DependencyManagerInteractiveTests.fs index a62667f01b2..e58f46179d2 100644 --- a/tests/FSharp.Compiler.Private.Scripting.UnitTests/DependencyManagerInteractiveTests.fs +++ b/tests/FSharp.Compiler.Private.Scripting.UnitTests/DependencyManagerInteractiveTests.fs @@ -232,7 +232,7 @@ type DependencyManagerInteractiveTests() = /// Native dll resolution is not implemented on desktop #if NETCOREAPP - [] + [] member __.``Script using TorchSharp``() = let text = """ #r "nuget:RestoreSources=https://donsyme.pkgs.visualstudio.com/TorchSharp/_packaging/packages2/nuget/v3/index.json" From 1b7485ca8681cdaa1d0c8538d8d7686a83d2cabd Mon Sep 17 00:00:00 2001 From: Don Syme Date: Sun, 20 Sep 2020 13:34:00 +0100 Subject: [PATCH 11/12] fix tests --- .../FSharpScriptTests.fs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/FSharp.Compiler.Private.Scripting.UnitTests/FSharpScriptTests.fs b/tests/FSharp.Compiler.Private.Scripting.UnitTests/FSharpScriptTests.fs index 3ab48c5d46e..151f376ad53 100644 --- a/tests/FSharp.Compiler.Private.Scripting.UnitTests/FSharpScriptTests.fs +++ b/tests/FSharp.Compiler.Private.Scripting.UnitTests/FSharpScriptTests.fs @@ -249,21 +249,26 @@ printfn ""%A"" result if line.Contains("error NU1101:") && line.Contains("FSharp.Really.Not.A.Package") then found <- found + 1 outp.Add(line)) - let _result, _errors = script.Eval("""#r "nuget:FSharp.Really.Not.A.Package" """) - Assert.True( (found = 1), "Expected to see output contains 'error NU1101:' and 'FSharp.Really.Not.A.Package'") + let result, errors = script.Eval("""#r "nuget:FSharp.Really.Not.A.Package" """) + Assert.True( (found = 0), "Did not expect to see output contains 'error NU1101:' and 'FSharp.Really.Not.A.Package'") + Assert.True( errors |> Seq.exists (fun error -> error.Message.Contains("error NU1101:")), "Expect to error containing 'error NU1101:'") + Assert.True( errors |> Seq.exists (fun error -> error.Message.Contains("FSharp.Really.Not.A.Package")), "Expect to error containing 'FSharp.Really.Not.A.Package'") [] member __.``Eval script with invalid PackageName should fail immediately and resolve one time only``() = use output = new RedirectConsoleOutput() use script = new FSharpScript(additionalArgs=[|"/langversion:preview"|]) let mutable foundResolve = 0 - output.OutputProduced.Add (fun line -> if line.Contains("Microsoft (R) Build Engine version") then foundResolve <- foundResolve + 1) - let _result, _errors = + output.OutputProduced.Add (fun line -> if line.Contains("error NU1101:") then foundResolve <- foundResolve + 1) + let result, errors = script.Eval(""" #r "nuget:FSharp.Really.Not.A.Package" #r "nuget:FSharp.Really.Not.Another.Package" """) - Assert.True( (foundResolve = 1), (sprintf "Expected to see 'Microsoft (R) Build Engine version' only once actually resolved %d times" foundResolve)) + Assert.True( (foundResolve = 0), (sprintf "Did not expected to see 'error NU1101:' in output" )) + Assert.Equal(2, (errors |> Seq.filter (fun error -> error.Message.Contains("error NU1101:")) |> Seq.length)) + Assert.Equal(1, (errors |> Seq.filter (fun error -> error.Message.Contains("FSharp.Really.Not.A.Package")) |> Seq.length)) + Assert.Equal(1, (errors |> Seq.filter (fun error -> error.Message.Contains("FSharp.Really.Not.Another.Package")) |> Seq.length)) [] member __.``ML - use assembly with ref dependencies``() = From 7341d452605a1ac1c0b3fe223c1d374ac30e5dff Mon Sep 17 00:00:00 2001 From: Don Syme Date: Sun, 20 Sep 2020 15:28:24 +0100 Subject: [PATCH 12/12] fix tests --- .../DependencyProvider.fs | 2 +- .../DependencyManagerInteractiveTests.fs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs b/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs index f080981550c..522be2a40a5 100644 --- a/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs +++ b/src/fsharp/Microsoft.DotNet.DependencyManager/DependencyProvider.fs @@ -265,7 +265,7 @@ type DependencyProvider (assemblyProbingPaths: AssemblyResolutionProbe, nativePr // Note: creating a NativeDllResolveHandler currently installs process-wide handlers let dllResolveHandler = - match assemblyProbingPaths with + match nativeProbingRoots with | null -> { new IDisposable with member _.Dispose() = () } | _ -> new NativeDllResolveHandler(nativeProbingRoots) :> IDisposable diff --git a/tests/FSharp.Compiler.Private.Scripting.UnitTests/DependencyManagerInteractiveTests.fs b/tests/FSharp.Compiler.Private.Scripting.UnitTests/DependencyManagerInteractiveTests.fs index e58f46179d2..68628e106aa 100644 --- a/tests/FSharp.Compiler.Private.Scripting.UnitTests/DependencyManagerInteractiveTests.fs +++ b/tests/FSharp.Compiler.Private.Scripting.UnitTests/DependencyManagerInteractiveTests.fs @@ -54,10 +54,8 @@ type DependencyManagerInteractiveTests() = #r @"nuget:System.Collections.Immutable.DoesNotExist, version=1.5.0" 0""" use script = new scriptHost() - let opt = script.Eval(text) |> getValue - let value = opt.Value - Assert.Equal(typeof, value.ReflectionType) - Assert.Equal(0, value.ReflectionValue :?> int) + let opt, errors = script.Eval(text) + Assert.Equal(errors.Length, 1) (* []