diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index 1c7e7bcd2ac3..5cd50aadff2e 100644 --- a/src/Compiler/Interactive/fsi.fs +++ b/src/Compiler/Interactive/fsi.fs @@ -4689,7 +4689,7 @@ type FsiEvaluationSession let errs = diagnosticsLogger.GetDiagnostics() let errorInfos = - DiagnosticHelpers.CreateDiagnostics(errorOptions, true, scriptFile, errs, true) + DiagnosticHelpers.CreateDiagnostics(errorOptions, true, scriptFile, errs, true, tcConfigB.flatErrors) let userRes = match res with diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs index 070185bdc166..381d7cfd255b 100644 --- a/src/Compiler/Service/FSharpCheckerResults.fs +++ b/src/Compiler/Service/FSharpCheckerResults.fs @@ -2207,7 +2207,8 @@ module internal ParseAndCheckFile = mainInputFileName, diagnosticsOptions: FSharpDiagnosticOptions, sourceText: ISourceText, - suggestNamesForErrors: bool + suggestNamesForErrors: bool, + flatErrors: bool ) = let mutable options = diagnosticsOptions let diagnosticsCollector = ResizeArray<_>() @@ -2218,7 +2219,7 @@ module internal ParseAndCheckFile = let collectOne severity diagnostic = for diagnostic in - DiagnosticHelpers.ReportDiagnostic(options, false, mainInputFileName, fileInfo, diagnostic, severity, suggestNamesForErrors) do + DiagnosticHelpers.ReportDiagnostic(options, false, mainInputFileName, fileInfo, diagnostic, severity, suggestNamesForErrors, flatErrors) do diagnosticsCollector.Add diagnostic if severity = FSharpDiagnosticSeverity.Error then @@ -2327,7 +2328,7 @@ module internal ParseAndCheckFile = usingLexbufForParsing (createLexbuf options.LangVersionText sourceText, fileName) (fun lexbuf -> let errHandler = - DiagnosticsHandler(false, fileName, options.DiagnosticOptions, sourceText, suggestNamesForErrors) + DiagnosticsHandler(false, fileName, options.DiagnosticOptions, sourceText, suggestNamesForErrors, false) let lexfun = createLexerFunction fileName options lexbuf errHandler @@ -2421,6 +2422,7 @@ module internal ParseAndCheckFile = options: FSharpParsingOptions, userOpName: string, suggestNamesForErrors: bool, + flatErrors: bool, identCapture: bool ) = Trace.TraceInformation("FCS: {0}.{1} ({2})", userOpName, "parseFile", fileName) @@ -2429,7 +2431,7 @@ module internal ParseAndCheckFile = Activity.start "ParseAndCheckFile.parseFile" [| Activity.Tags.fileName, fileName |] let errHandler = - DiagnosticsHandler(true, fileName, options.DiagnosticOptions, sourceText, suggestNamesForErrors) + DiagnosticsHandler(true, fileName, options.DiagnosticOptions, sourceText, suggestNamesForErrors, flatErrors) use _ = UseDiagnosticsLogger errHandler.DiagnosticsLogger @@ -2596,7 +2598,7 @@ module internal ParseAndCheckFile = // Initialize the error handler let errHandler = - DiagnosticsHandler(true, mainInputFileName, tcConfig.diagnosticsOptions, sourceText, suggestNamesForErrors) + DiagnosticsHandler(true, mainInputFileName, tcConfig.diagnosticsOptions, sourceText, suggestNamesForErrors, tcConfig.flatErrors) use _ = UseDiagnosticsLogger errHandler.DiagnosticsLogger @@ -3260,6 +3262,7 @@ type FsiInteractiveChecker(legacyReferenceResolver, tcConfig: TcConfig, tcGlobal parsingOptions, userOpName, suggestNamesForErrors, + tcConfig.flatErrors, tcConfig.captureIdentifiersWhenParsing ) diff --git a/src/Compiler/Service/FSharpCheckerResults.fsi b/src/Compiler/Service/FSharpCheckerResults.fsi index 6eb541982d0b..2283ffcdf495 100644 --- a/src/Compiler/Service/FSharpCheckerResults.fsi +++ b/src/Compiler/Service/FSharpCheckerResults.fsi @@ -537,6 +537,7 @@ module internal ParseAndCheckFile = options: FSharpParsingOptions * userOpName: string * suggestNamesForErrors: bool * + flatErrors: bool * identCapture: bool -> FSharpDiagnostic[] * ParsedInput * bool diff --git a/src/Compiler/Service/IncrementalBuild.fs b/src/Compiler/Service/IncrementalBuild.fs index dc27983338e4..5403a37b86bd 100644 --- a/src/Compiler/Service/IncrementalBuild.fs +++ b/src/Compiler/Service/IncrementalBuild.fs @@ -1599,16 +1599,18 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc } let diagnostics = - match builderOpt with - | Some builder -> - let diagnosticsOptions = builder.TcConfig.diagnosticsOptions - let diagnosticsLogger = CompilationDiagnosticLogger("IncrementalBuilderCreation", diagnosticsOptions) - delayedLogger.CommitDelayedDiagnostics diagnosticsLogger - diagnosticsLogger.GetDiagnostics() - | _ -> - Array.ofList delayedLogger.Diagnostics + let diagnostics, flatErrors = + match builderOpt with + | Some builder -> + let diagnosticsOptions = builder.TcConfig.diagnosticsOptions + let diagnosticsLogger = CompilationDiagnosticLogger("IncrementalBuilderCreation", diagnosticsOptions) + delayedLogger.CommitDelayedDiagnostics diagnosticsLogger + diagnosticsLogger.GetDiagnostics(), builder.TcConfig.flatErrors + | _ -> + Array.ofList delayedLogger.Diagnostics, false + diagnostics |> Array.map (fun (diagnostic, severity) -> - FSharpDiagnostic.CreateFromException(diagnostic, severity, range.Zero, suggestNamesForErrors)) + FSharpDiagnostic.CreateFromException(diagnostic, severity, range.Zero, suggestNamesForErrors, flatErrors)) return builderOpt, diagnostics } \ No newline at end of file diff --git a/src/Compiler/Service/ServiceAssemblyContent.fs b/src/Compiler/Service/ServiceAssemblyContent.fs index 0a89eb646d23..2b54ed7f229f 100644 --- a/src/Compiler/Service/ServiceAssemblyContent.fs +++ b/src/Compiler/Service/ServiceAssemblyContent.fs @@ -247,7 +247,7 @@ module AssemblyContent = // are not triggered (see "if not entity.IsProvided") and the other data accessed is immutable or computed safely // on-demand. However a more compete review may be warranted. - use _ignoreAllDiagnostics = new DiagnosticsScope() + use _ignoreAllDiagnostics = new DiagnosticsScope(false) signature.TryGetEntities() |> Seq.collect (traverseEntity contentType Parent.Empty) @@ -265,7 +265,7 @@ module AssemblyContent = // concurrently with other threads. On an initial review this is not a problem since type provider computations // are not triggered (see "if not entity.IsProvided") and the other data accessed is immutable or computed safely // on-demand. However a more compete review may be warranted. - use _ignoreAllDiagnostics = new DiagnosticsScope() + use _ignoreAllDiagnostics = new DiagnosticsScope(false) #if !NO_TYPEPROVIDERS match assemblies |> List.filter (fun x -> not x.IsProviderGenerated), fileName with diff --git a/src/Compiler/Service/ServiceParsedInputOps.fs b/src/Compiler/Service/ServiceParsedInputOps.fs index 91c48c42bcb3..a0f8a810ccb9 100644 --- a/src/Compiler/Service/ServiceParsedInputOps.fs +++ b/src/Compiler/Service/ServiceParsedInputOps.fs @@ -2012,7 +2012,7 @@ module ParsedInput = // We ignore all diagnostics during this operation // // Based on an initial review, no diagnostics should be generated. However the code should be checked more closely. - use _ignoreAllDiagnostics = new DiagnosticsScope() + use _ignoreAllDiagnostics = new DiagnosticsScope(false) let mutable result = None let mutable ns = None @@ -2175,7 +2175,7 @@ module ParsedInput = // We ignore all diagnostics during this operation // // Based on an initial review, no diagnostics should be generated. However the code should be checked more closely. - use _ignoreAllDiagnostics = new DiagnosticsScope() + use _ignoreAllDiagnostics = new DiagnosticsScope(false) match res with | None -> [||] diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs index 8b39b71e69a6..b7e18922cc42 100644 --- a/src/Compiler/Service/service.fs +++ b/src/Compiler/Service/service.fs @@ -99,14 +99,14 @@ module Helpers = | _ -> false module CompileHelpers = - let mkCompilationDiagnosticsHandlers () = + let mkCompilationDiagnosticsHandlers (flatErrors) = let diagnostics = ResizeArray<_>() let diagnosticsLogger = { new DiagnosticsLogger("CompileAPI") with member _.DiagnosticSink(diag, isError) = - diagnostics.Add(FSharpDiagnostic.CreateFromException(diag, isError, range0, true)) // Suggest names for errors + diagnostics.Add(FSharpDiagnostic.CreateFromException(diag, isError, range0, true, flatErrors)) // Suggest names for errors member _.ErrorCount = diagnostics @@ -137,7 +137,7 @@ module CompileHelpers = /// Compile using the given flags. Source files names are resolved via the FileSystem API. The output file must be given by a -o flag. let compileFromArgs (ctok, argv: string[], legacyReferenceResolver, tcImportsCapture, dynamicAssemblyCreator) = - let diagnostics, diagnosticsLogger, loggerProvider = mkCompilationDiagnosticsHandlers () + let diagnostics, diagnosticsLogger, loggerProvider = mkCompilationDiagnosticsHandlers (argv |> Array.contains "--flaterrors") let result = tryCompile diagnosticsLogger (fun exiter -> @@ -487,7 +487,7 @@ type BackgroundCompiler checkFileInProjectCache.Set(ltok, key, res) res) - member _.ParseFile(fileName: string, sourceText: ISourceText, options: FSharpParsingOptions, cache: bool, userOpName: string) = + member _.ParseFile(fileName: string, sourceText: ISourceText, options: FSharpParsingOptions, cache: bool, flatErrors: bool, userOpName: string) = async { use _ = Activity.start @@ -507,14 +507,14 @@ type BackgroundCompiler Interlocked.Increment(&actualParseFileCount) |> ignore let parseDiagnostics, parseTree, anyErrors = - ParseAndCheckFile.parseFile (sourceText, fileName, options, userOpName, suggestNamesForErrors, captureIdentifiersWhenParsing) + ParseAndCheckFile.parseFile (sourceText, fileName, options, userOpName, suggestNamesForErrors, flatErrors, captureIdentifiersWhenParsing) let res = FSharpParseFileResults(parseDiagnostics, parseTree, anyErrors, options.SourceFiles) parseCacheLock.AcquireLock(fun ltok -> parseFileCache.Set(ltok, (fileName, hash, options), res)) return res else let parseDiagnostics, parseTree, anyErrors = - ParseAndCheckFile.parseFile (sourceText, fileName, options, userOpName, false, captureIdentifiersWhenParsing) + ParseAndCheckFile.parseFile (sourceText, fileName, options, userOpName, false, flatErrors, captureIdentifiersWhenParsing) return FSharpParseFileResults(parseDiagnostics, parseTree, anyErrors, options.SourceFiles) } @@ -537,7 +537,7 @@ type BackgroundCompiler let parseTree, _, _, parseDiagnostics = builder.GetParseResultsForFile fileName let parseDiagnostics = - DiagnosticHelpers.CreateDiagnostics(builder.TcConfig.diagnosticsOptions, false, fileName, parseDiagnostics, suggestNamesForErrors) + DiagnosticHelpers.CreateDiagnostics(builder.TcConfig.diagnosticsOptions, false, fileName, parseDiagnostics, suggestNamesForErrors, builder.TcConfig.flatErrors) let diagnostics = [| yield! creationDiags; yield! parseDiagnostics |] @@ -767,6 +767,7 @@ type BackgroundCompiler parsingOptions, userOpName, suggestNamesForErrors, + builder.TcConfig.flatErrors, captureIdentifiersWhenParsing ) @@ -835,12 +836,12 @@ type BackgroundCompiler let diagnosticsOptions = builder.TcConfig.diagnosticsOptions let parseDiagnostics = - DiagnosticHelpers.CreateDiagnostics(diagnosticsOptions, false, fileName, parseDiagnostics, suggestNamesForErrors) + DiagnosticHelpers.CreateDiagnostics(diagnosticsOptions, false, fileName, parseDiagnostics, suggestNamesForErrors, builder.TcConfig.flatErrors) let parseDiagnostics = [| yield! creationDiags; yield! parseDiagnostics |] let tcDiagnostics = - DiagnosticHelpers.CreateDiagnostics(diagnosticsOptions, false, fileName, tcDiagnostics, suggestNamesForErrors) + DiagnosticHelpers.CreateDiagnostics(diagnosticsOptions, false, fileName, tcDiagnostics, suggestNamesForErrors, builder.TcConfig.flatErrors) let tcDiagnostics = [| yield! creationDiags; yield! tcDiagnostics |] @@ -994,7 +995,7 @@ type BackgroundCompiler let tcDependencyFiles = tcInfo.tcDependencyFiles let tcDiagnostics = - DiagnosticHelpers.CreateDiagnostics(diagnosticsOptions, true, fileName, tcDiagnostics, suggestNamesForErrors) + DiagnosticHelpers.CreateDiagnostics(diagnosticsOptions, true, fileName, tcDiagnostics, suggestNamesForErrors, builder.TcConfig.flatErrors) let diagnostics = [| yield! creationDiags; yield! tcDiagnostics |] @@ -1083,8 +1084,6 @@ type BackgroundCompiler [| Activity.Tags.fileName, fileName; Activity.Tags.userOpName, _userOpName |] cancellable { - use diagnostics = new DiagnosticsScope() - // Do we add a reference to FSharp.Compiler.Interactive.Settings by default? let useFsiAuxLib = defaultArg useFsiAuxLib true let useSdkRefs = defaultArg useSdkRefs true @@ -1102,6 +1101,8 @@ type BackgroundCompiler let otherFlags = defaultArg otherFlags extraFlags + use diagnostics = new DiagnosticsScope (otherFlags |> Array.contains "--flaterrors") + let useSimpleResolution = otherFlags |> Array.exists (fun x -> x = "--simpleresolution") let loadedTimeStamp = defaultArg loadedTimeStamp DateTime.MaxValue // Not 'now', we don't want to force reloading @@ -1159,7 +1160,7 @@ type BackgroundCompiler let diags = loadClosure.LoadClosureRootFileDiagnostics - |> List.map (fun (exn, isError) -> FSharpDiagnostic.CreateFromException(exn, isError, range.Zero, false)) + |> List.map (fun (exn, isError) -> FSharpDiagnostic.CreateFromException(exn, isError, range.Zero, false, options.OtherOptions |> Array.contains "--flaterrors")) return options, (diags @ diagnostics.Diagnostics) } @@ -1414,7 +1415,7 @@ type FSharpChecker member _.ParseFile(fileName, sourceText, options, ?cache, ?userOpName: string) = let cache = defaultArg cache true let userOpName = defaultArg userOpName "Unknown" - backgroundCompiler.ParseFile(fileName, sourceText, options, cache, userOpName) + backgroundCompiler.ParseFile(fileName, sourceText, options, cache, false, userOpName) member ic.ParseFileInProject(fileName, source: string, options, ?cache: bool, ?userOpName: string) = let parsingOptions, _ = ic.GetParsingOptionsFromProjectOptions(options) @@ -1650,7 +1651,7 @@ type FSharpChecker member _.GetParsingOptionsFromCommandLineArgs(sourceFiles, argv, ?isInteractive, ?isEditing) = let isEditing = defaultArg isEditing false let isInteractive = defaultArg isInteractive false - use errorScope = new DiagnosticsScope() + use errorScope = new DiagnosticsScope (argv |> List.contains "--flaterrors") let tcConfigB = TcConfigBuilder.CreateNew( diff --git a/src/Compiler/Symbols/FSharpDiagnostic.fs b/src/Compiler/Symbols/FSharpDiagnostic.fs index c4b57e84c9fd..f621860d6a1e 100644 --- a/src/Compiler/Symbols/FSharpDiagnostic.fs +++ b/src/Compiler/Symbols/FSharpDiagnostic.fs @@ -71,15 +71,15 @@ type FSharpDiagnostic(m: range, severity: FSharpDiagnosticSeverity, message: str sprintf "%s (%d,%d)-(%d,%d) %s %s %s" fileName s.Line (s.Column + 1) e.Line (e.Column + 1) subcategory severity message /// Decompose a warning or error into parts: position, severity, message, error number - static member CreateFromException(diagnostic: PhasedDiagnostic, severity, fallbackRange: range, suggestNames: bool) = + static member CreateFromException(diagnostic: PhasedDiagnostic, severity, fallbackRange: range, suggestNames: bool, flatErrors: bool) = let m = match diagnostic.Range with Some m -> m | None -> fallbackRange - let msg = diagnostic.FormatCore(false, suggestNames) + let msg = diagnostic.FormatCore(flatErrors, suggestNames) let errorNum = diagnostic.Number FSharpDiagnostic(m, severity, msg, diagnostic.Subcategory(), errorNum, "FS") /// Decompose a warning or error into parts: position, severity, message, error number - static member CreateFromExceptionAndAdjustEof(diagnostic, severity, fallbackRange: range, (linesCount: int, lastLength: int), suggestNames: bool) = - let diagnostic = FSharpDiagnostic.CreateFromException(diagnostic, severity, fallbackRange, suggestNames) + static member CreateFromExceptionAndAdjustEof(diagnostic, severity, fallbackRange: range, (linesCount: int, lastLength: int), suggestNames: bool, flatErrors: bool) = + let diagnostic = FSharpDiagnostic.CreateFromException(diagnostic, severity, fallbackRange, suggestNames, flatErrors) // Adjust to make sure that diagnostics reported at Eof are shown at the linesCount let startLine, startChanged = min (Line.toZ diagnostic.Range.StartLine, false) (linesCount, true) @@ -102,7 +102,7 @@ type FSharpDiagnostic(m: range, severity: FSharpDiagnosticSeverity, message: str /// Use to reset error and warning handlers [] -type DiagnosticsScope() = +type DiagnosticsScope(flatErrors: bool) = let mutable diags = [] let unwindBP = UseBuildPhase BuildPhase.TypeCheck let unwindEL = @@ -110,7 +110,7 @@ type DiagnosticsScope() = { new DiagnosticsLogger("DiagnosticsScope") with member _.DiagnosticSink(diagnostic, severity) = - let diagnostic = FSharpDiagnostic.CreateFromException(diagnostic, severity, range.Zero, false) + let diagnostic = FSharpDiagnostic.CreateFromException(diagnostic, severity, range.Zero, false, flatErrors) diags <- diagnostic :: diags member _.ErrorCount = diags.Length } @@ -139,7 +139,7 @@ type DiagnosticsScope() = /// autocomplete, then the error message is shown in replacement of the text (rather than crashing Visual /// Studio, or swallowing the exception completely) static member Protect<'a> (m: range) (f: unit->'a) (err: string->'a): 'a = - use diagnosticsScope = new DiagnosticsScope() + use diagnosticsScope = new DiagnosticsScope(false) let res = try Some (f()) @@ -184,7 +184,7 @@ type internal CompilationDiagnosticLogger (debugName: string, options: FSharpDia module DiagnosticHelpers = - let ReportDiagnostic (options: FSharpDiagnosticOptions, allErrors, mainInputFileName, fileInfo, diagnostic: PhasedDiagnostic, severity, suggestNames) = + let ReportDiagnostic (options: FSharpDiagnosticOptions, allErrors, mainInputFileName, fileInfo, diagnostic: PhasedDiagnostic, severity, suggestNames, flatErrors) = [ let severity = if diagnostic.ReportAsError (options, severity) then FSharpDiagnosticSeverity.Error @@ -198,12 +198,12 @@ module DiagnosticHelpers = // We use the first line of the file as a fallbackRange for reporting unexpected errors. // Not ideal, but it's hard to see what else to do. let fallbackRange = rangeN mainInputFileName 1 - let diagnostic = FSharpDiagnostic.CreateFromExceptionAndAdjustEof (diagnostic, severity, fallbackRange, fileInfo, suggestNames) + let diagnostic = FSharpDiagnostic.CreateFromExceptionAndAdjustEof (diagnostic, severity, fallbackRange, fileInfo, suggestNames, flatErrors) let fileName = diagnostic.Range.FileName if allErrors || fileName = mainInputFileName || fileName = TcGlobals.DummyFileNameForRangesWithoutASpecificLocation then yield diagnostic ] - let CreateDiagnostics (options, allErrors, mainInputFileName, diagnostics, suggestNames) = + let CreateDiagnostics (options, allErrors, mainInputFileName, diagnostics, suggestNames, flatErrors) = let fileInfo = (Int32.MaxValue, Int32.MaxValue) [| for diagnostic, severity in diagnostics do - yield! ReportDiagnostic (options, allErrors, mainInputFileName, fileInfo, diagnostic, severity, suggestNames) |] + yield! ReportDiagnostic (options, allErrors, mainInputFileName, fileInfo, diagnostic, severity, suggestNames, flatErrors) |] diff --git a/src/Compiler/Symbols/FSharpDiagnostic.fsi b/src/Compiler/Symbols/FSharpDiagnostic.fsi index 313c14240e46..e0cdd1161563 100644 --- a/src/Compiler/Symbols/FSharpDiagnostic.fsi +++ b/src/Compiler/Symbols/FSharpDiagnostic.fsi @@ -71,11 +71,12 @@ type public FSharpDiagnostic = severity: FSharpDiagnosticSeverity * range * lastPosInFile: (int * int) * - suggestNames: bool -> + suggestNames: bool * + flatErrors: bool -> FSharpDiagnostic static member internal CreateFromException: - diagnostic: PhasedDiagnostic * severity: FSharpDiagnosticSeverity * range * suggestNames: bool -> + diagnostic: PhasedDiagnostic * severity: FSharpDiagnosticSeverity * range * suggestNames: bool * flatErrors: bool -> FSharpDiagnostic /// Newlines are recognized and replaced with (ASCII 29, the 'group separator'), @@ -95,7 +96,7 @@ type internal DiagnosticsScope = interface IDisposable - new: unit -> DiagnosticsScope + new: bool -> DiagnosticsScope member Diagnostics: FSharpDiagnostic list @@ -122,7 +123,8 @@ module internal DiagnosticHelpers = fileInfo: (int * int) * diagnostic: PhasedDiagnostic * severity: FSharpDiagnosticSeverity * - suggestNames: bool -> + suggestNames: bool * + flatErrors: bool -> FSharpDiagnostic list val CreateDiagnostics: @@ -130,5 +132,6 @@ module internal DiagnosticHelpers = allErrors: bool * mainInputFileName: string * seq * - suggestNames: bool -> + suggestNames: bool * + flatErrors: bool -> FSharpDiagnostic[] diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/flaterrors.fs b/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/flaterrors.fs index 980b31ffeacc..bd917a838c24 100644 --- a/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/flaterrors.fs +++ b/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/flaterrors.fs @@ -59,11 +59,13 @@ module flaterrors = [] //Invalid case [] //Even more invalid case - [] // no + or - options + [] // no + allowed + [] // no - allowed [] - let ``E_MultiLine04_fs`` (options: string) = + let ``E_MultiLine04_fs`` (option: string) = Fs """List.rev {1..10} |> ignore""" - |> compile options + |> compile option |> shouldFail |> withDiagnostics [ + (Error 243, Line 0, Col 1, Line 0, Col 1, $"Unrecognized option: '{option}'. Use '--help' to learn about recognized command line options.") ]