Skip to content

Commit b3b5475

Browse files
committed
Fix 469 - meaningful errors from EvalScript etc
1 parent 6e86a6b commit b3b5475

File tree

10 files changed

+315
-137
lines changed

10 files changed

+315
-137
lines changed

src/fsharp/ErrorLogger.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ let rec findOriginalException err =
3838

3939

4040
/// Thrown when we stop processing the F# Interactive entry or #load.
41-
exception StopProcessing of string
41+
exception StopProcessing of exn option
4242

4343

4444
(* common error kinds *)

src/fsharp/fsc.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2099,7 +2099,7 @@ type InProcCompiler() =
20992099
let exitCode = ref 0
21002100
let exiter =
21012101
{ new Exiter with
2102-
member this.Exit n = exitCode := n; raise (StopProcessing "") }
2102+
member this.Exit n = exitCode := n; raise (StopProcessing None) }
21032103
try
21042104
typecheckAndCompile(argv, false, true, exiter, loggerProvider, None, None)
21052105
with

src/fsharp/fsi/fsi.fs

Lines changed: 152 additions & 103 deletions
Large diffs are not rendered by default.

src/fsharp/fsi/fsi.fsi

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
module Microsoft.FSharp.Compiler.Interactive.Shell
1414

1515
open System.IO
16+
open Microsoft.FSharp.Compiler
1617
open Microsoft.FSharp.Compiler.SourceCodeServices
1718

1819
[<Class>]
@@ -146,6 +147,15 @@ type FsiEvaluationSession =
146147
/// by input from 'stdin'.
147148
member EvalInteraction : code: string -> unit
148149

150+
/// Execute the code as if it had been entered as one or more interactions, with an
151+
/// implicit termination at the end of the input. Stop on first error, discarding the rest
152+
/// of the input. Errors and warnings are collected apart from any exception arising from execution
153+
/// which is returned via a Choice. Execution is performed on the 'Run()' thread.
154+
///
155+
/// Due to a current limitation, it is not fully thread-safe to run this operation concurrently with evaluation triggered
156+
/// by input from 'stdin'.
157+
member EvalInteractionNonThrowing : code: string -> Choice<unit, exn> * FSharpErrorInfo[]
158+
149159
/// Execute the given script. Stop on first error, discarding the rest
150160
/// of the script. Errors are sent to the output writer, a 'true' return value indicates there
151161
/// were no errors overall. Execution is performed on the 'Run()' thread.
@@ -154,16 +164,33 @@ type FsiEvaluationSession =
154164
/// by input from 'stdin'.
155165
member EvalScript : filePath: string -> unit
156166

167+
/// Execute the given script. Stop on first error, discarding the rest
168+
/// of the script. Errors and warnings are collected apart from any exception arising from execution
169+
/// which is returned via a Choice. Execution is performed on the 'Run()' thread.
170+
///
171+
/// Due to a current limitation, it is not fully thread-safe to run this operation concurrently with evaluation triggered
172+
/// by input from 'stdin'.
173+
member EvalScriptNonThrowing : filePath: string -> Choice<unit, exn> * FSharpErrorInfo[]
174+
157175
/// Execute the code as if it had been entered as one or more interactions, with an
158176
/// implicit termination at the end of the input. Stop on first error, discarding the rest
159-
/// of the input. Errors are sent to the output writer, a 'true' return value indicates there
160-
/// were no errors overall. Parsing is performed on the current thread, and execution is performed
177+
/// of the input. Errors are sent to the output writer. Parsing is performed on the current thread, and execution is performed
161178
/// sycnhronously on the 'main' thread.
162179
///
163180
/// Due to a current limitation, it is not fully thread-safe to run this operation concurrently with evaluation triggered
164181
/// by input from 'stdin'.
165182
member EvalExpression : code: string -> FsiValue option
166183

184+
/// Execute the code as if it had been entered as one or more interactions, with an
185+
/// implicit termination at the end of the input. Stop on first error, discarding the rest
186+
/// of the input. Errors and warnings are collected apart from any exception arising from execution
187+
/// which is returned via a Choice. Parsing is performed on the current thread, and execution is performed
188+
/// sycnhronously on the 'main' thread.
189+
///
190+
/// Due to a current limitation, it is not fully thread-safe to run this operation concurrently with evaluation triggered
191+
/// by input from 'stdin'.
192+
member EvalExpressionNonThrowing : code: string -> Choice<FsiValue option, exn> * FSharpErrorInfo[]
193+
167194
/// Raised when an interaction is successfully typechecked and executed, resulting in an update to the
168195
/// type checking state.
169196
///

src/fsharp/vs/IncrementalBuild.fs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,7 +1084,7 @@ type FrameworkImportsCache(keepStrongly) =
10841084

10851085

10861086
/// An error logger that capture errors, filtering them according to warning levels etc.
1087-
type CompilationErrorLogger (debugName:string, tcConfig:TcConfig) =
1087+
type internal CompilationErrorLogger (debugName:string, tcConfig:TcConfig) =
10881088
inherit ErrorLogger("CompilationErrorLogger("+debugName+")")
10891089

10901090
let warningsSeenInScope = new ResizeArray<_>()
@@ -1192,7 +1192,7 @@ type IncrementalBuilder(frameworkTcImportsCache: FrameworkImportsCache, tcConfig
11921192
// This operation is done when constructing the builder itself, rather than as an incremental task.
11931193
let nonFrameworkAssemblyInputs =
11941194
// Note we are not calling errorLogger.GetErrors() anywhere for this task.
1195-
// REVIEW: Consider if this is ok. I believe so, because this is a background build and we aren'T currently reporting errors from the background build.
1195+
// This is ok because not much can actually go wrong here.
11961196
let errorLogger = CompilationErrorLogger("nonFrameworkAssemblyInputs", tcConfig)
11971197
// Return the disposable object that cleans up
11981198
use _holder = new CompilationGlobalsScope(errorLogger,BuildPhase.Parameter, projectDirectory)
@@ -1207,12 +1207,11 @@ type IncrementalBuilder(frameworkTcImportsCache: FrameworkImportsCache, tcConfig
12071207
DateTime.Now
12081208
with e ->
12091209
// Note we are not calling errorLogger.GetErrors() anywhere for this task. This warning will not be reported...
1210-
// REVIEW: Consider if this is ok. I believe so, because this is a background build and we aren't currently reporting errors from the background build.
12111210
errorLogger.Warning(e)
12121211
DateTime.Now
12131212
yield (Choice1Of2 r.resolvedPath,originalTimeStamp)
12141213
for pr in projectReferences do
1215-
yield Choice2Of2 pr, defaultArg (pr.GetLogicalTimeStamp()) DateTime.Now]
1214+
yield Choice2Of2 pr, defaultArg (pr.GetLogicalTimeStamp()) DateTime.Now]
12161215

12171216
// The IncrementalBuilder needs to hold up to one item that needs to be disposed, which is the tcImports for the incremental
12181217
// build.
@@ -1725,7 +1724,7 @@ type IncrementalBuilder(frameworkTcImportsCache: FrameworkImportsCache, tcConfig
17251724
else MSBuildResolver.CompileTimeLike
17261725

17271726
tcConfigB.conditionalCompilationDefines <-
1728-
let define = if useScriptResolutionRules then "INTERACTIVE" else "COMPILED"
1727+
let define = if useScriptResolutionRules then "INTERACTIVE" else "MPILED"
17291728
define::tcConfigB.conditionalCompilationDefines
17301729

17311730
tcConfigB.projectReferences <- projectReferences

src/fsharp/vs/IncrementalBuild.fsi

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,16 @@ type internal FrameworkImportsCache =
5252
member Clear: unit -> unit
5353
member Downsize: unit -> unit
5454
55+
/// An error logger that capture errors, filtering them according to warning levels etc.
56+
type internal CompilationErrorLogger =
57+
inherit ErrorLogger
58+
59+
/// Create the error logger
60+
new : debugName:string * tcConfig:TcConfig -> CompilationErrorLogger
61+
62+
/// Get the captured errors
63+
member GetErrors : unit -> (PhasedError * FSharpErrorSeverity) list
64+
5565
/// Represents the state in the incremental graph assocaited with checking a file
5666
type internal PartialCheckResults =
5767
{ TcState : TcState

src/fsharp/vs/SimpleServices.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ namespace Microsoft.FSharp.Compiler.SimpleSourceCodeServices
136136
let tryCompile errorLogger f =
137137
use unwindParsePhase = PushThreadBuildPhaseUntilUnwind (BuildPhase.Parse)
138138
use unwindEL_2 = PushErrorLoggerPhaseUntilUnwind (fun _ -> errorLogger)
139-
let exiter = { new Exiter with member x.Exit n = raise (StopProcessing "") }
139+
let exiter = { new Exiter with member x.Exit n = raise (StopProcessing None) }
140140
try
141141
f exiter
142142
0

src/fsharp/vs/service.fs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1527,7 +1527,8 @@ module internal Parser =
15271527
for e in relatedErrors do
15281528
yield! oneError true e ]
15291529

1530-
let CreateErrorInfos (tcConfig:TcConfig, allErrors, mainInputFileName, fileInfo, errors) =
1530+
let CreateErrorInfos (tcConfig:TcConfig, allErrors, mainInputFileName, errors) =
1531+
let fileInfo = (Int32.MaxValue, Int32.MaxValue)
15311532
[| for (exn,warn) in errors do
15321533
yield! ReportError (tcConfig, allErrors, mainInputFileName, fileInfo, (exn, warn)) |]
15331534

@@ -2392,8 +2393,7 @@ type BackgroundCompiler(projectCacheSize, keepAssemblyContents, keepAllBackgroun
23922393
| Some builder ->
23932394
let inputOpt,_,_,parseErrors = builder.GetParseResultsForFile filename
23942395
let dependencyFiles = builder.Dependencies
2395-
let fileInfo = (Int32.MaxValue, Int32.MaxValue)
2396-
let errors = [| yield! creationErrors; yield! Parser.CreateErrorInfos (builder.TcConfig, false, filename, fileInfo, parseErrors) |]
2396+
let errors = [| yield! creationErrors; yield! Parser.CreateErrorInfos (builder.TcConfig, false, filename, parseErrors) |]
23972397
FSharpParseFileResults(errors = errors, input = inputOpt, parseHadErrors = false, dependencyFiles = dependencyFiles)
23982398
)
23992399

@@ -2508,9 +2508,8 @@ type BackgroundCompiler(projectCacheSize, keepAssemblyContents, keepAllBackgroun
25082508
| Some builder ->
25092509
let (inputOpt, _, _, untypedErrors) = builder.GetParseResultsForFile filename
25102510
let tcProj = builder.GetCheckResultsAfterFileInProject filename
2511-
let fileInfo = (Int32.MaxValue, Int32.MaxValue)
2512-
let untypedErrors = [| yield! creationErrors; yield! Parser.CreateErrorInfos (builder.TcConfig, false, filename, fileInfo, untypedErrors) |]
2513-
let tcErrors = [| yield! creationErrors; yield! Parser.CreateErrorInfos (builder.TcConfig, false, filename, fileInfo, tcProj.Errors) |]
2511+
let untypedErrors = [| yield! creationErrors; yield! Parser.CreateErrorInfos (builder.TcConfig, false, filename, untypedErrors) |]
2512+
let tcErrors = [| yield! creationErrors; yield! Parser.CreateErrorInfos (builder.TcConfig, false, filename, tcProj.Errors) |]
25142513
let parseResults = FSharpParseFileResults(errors = untypedErrors, input = inputOpt, parseHadErrors = false, dependencyFiles = builder.Dependencies)
25152514
let loadClosure = scriptClosureCache.TryGet options
25162515
let scope =
@@ -2539,8 +2538,7 @@ type BackgroundCompiler(projectCacheSize, keepAssemblyContents, keepAllBackgroun
25392538
FSharpCheckProjectResults (keepAssemblyContents, Array.ofList creationErrors, None, reactorOps)
25402539
| Some builder ->
25412540
let (tcProj, ilAssemRef, tcAssemblyDataOpt, tcAssemblyExprOpt) = builder.GetCheckResultsAndImplementationsForProject()
2542-
let fileInfo = (Int32.MaxValue, Int32.MaxValue)
2543-
let errors = [| yield! creationErrors; yield! Parser.CreateErrorInfos (tcProj.TcConfig, true, Microsoft.FSharp.Compiler.TcGlobals.DummyFileNameForRangesWithoutASpecificLocation, fileInfo, tcProj.Errors) |]
2541+
let errors = [| yield! creationErrors; yield! Parser.CreateErrorInfos (tcProj.TcConfig, true, Microsoft.FSharp.Compiler.TcGlobals.DummyFileNameForRangesWithoutASpecificLocation, tcProj.Errors) |]
25442542
FSharpCheckProjectResults (keepAssemblyContents, errors, Some(tcProj.TcGlobals, tcProj.TcImports, tcProj.TcState.Ccu, tcProj.TcState.PartialAssemblySignature, tcProj.TcSymbolUses, tcProj.TopAttribs, tcAssemblyDataOpt, ilAssemRef, tcProj.TcEnvAtEnd.AccessRights, tcAssemblyExprOpt), reactorOps)
25452543

25462544
/// Get the timestamp that would be on the output if fully built immediately
@@ -3238,6 +3236,9 @@ type FSharpChecker(projectCacheSize, keepAssemblyContents, keepAllBackgroundReso
32383236
type FsiInteractiveChecker(reactorOps: IReactorOperations, tcConfig, tcGlobals, tcImports, tcState, loadClosure) =
32393237
let keepAssemblyContents = false
32403238

3239+
static member CreateErrorInfos (tcConfig, allErrors, mainInputFileName, errors) =
3240+
Parser.CreateErrorInfos(tcConfig, allErrors, mainInputFileName, errors)
3241+
32413242
member __.ParseAndCheckInteraction (source) =
32423243

32433244
let mainInputFileName = "stdin.fsx"

src/fsharp/vs/service.fsi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,7 @@ type FSharpChecker =
722722
type internal FsiInteractiveChecker =
723723
internal new : ops: IReactorOperations * tcConfig: TcConfig * tcGlobals: TcGlobals * tcImports: TcImports * tcState: TcState * loadClosure: LoadClosure option -> FsiInteractiveChecker
724724
member internal ParseAndCheckInteraction : source:string -> FSharpParseFileResults * FSharpCheckFileResults * FSharpCheckProjectResults
725+
static member internal CreateErrorInfos : tcConfig: TcConfig * allErrors:bool * mainInputFileName : string * seq<ErrorLogger.PhasedError * FSharpErrorSeverity> -> FSharpErrorInfo[]
725726

726727
/// Information about the compilation environment
727728
type [<Class>] CompilerEnvironment =

0 commit comments

Comments
 (0)