@@ -15,6 +15,7 @@ open Microsoft.FSharp.Control
1515open System
1616open System.Text
1717open System.Threading
18+ open System.Collections .Concurrent
1819open System.Collections .Generic
1920
2021open Microsoft.FSharp .Compiler
@@ -50,16 +51,17 @@ open Microsoft.FSharp.Compiler.TypeChecker
5051// InteractiveChecker
5152//-------------------------------------------------------------------------
5253
53- type InteractiveChecker internal ( tcConfig , tcGlobals , tcImports , tcState , ctok , reactorOps ) =
54+ type InteractiveChecker internal ( tcConfig , tcGlobals , tcImports , tcInitialState , ctok , reactorOps , moduleNamesDict ) =
55+ let userOpName = " Unknown"
5456
55- static member Create ( references : string [], readAllBytes : string -> byte []) =
57+ static member Create ( references : string [], readAllBytes : string -> byte [], defines : string [] ) =
5658
5759 let GetSignatureData (( filename : string ), ilScopeRef , ( ilModule : ILModuleDef option ), ( bytes : byte [])) =
5860 TastPickle.unpickleObjWithDanglingCcus filename ilScopeRef ilModule TastPickle.unpickleCcuInfo bytes
5961 let GetOptimizationData (( filename : string ), ilScopeRef , ( ilModule : ILModuleDef option ), ( bytes : byte [])) =
6062 TastPickle.unpickleObjWithDanglingCcus filename ilScopeRef ilModule Optimizer.u_ CcuOptimizationInfo bytes
6163
62- let tcConfig = TcConfig ( optimize = true )
64+ let tcConfig = TcConfig ( optimize = true , defines = Array.toList defines )
6365 let tcImports = TcImports ()
6466 let ilGlobals = IL.EcmaMscorlibILGlobals
6567
@@ -142,7 +144,9 @@ type InteractiveChecker internal (tcConfig, tcGlobals, tcImports, tcState, ctok,
142144 let fileName = ilModule.Name
143145 let ilScopeRef = ILScopeRef.Assembly ( mkSimpleAssRef ccuName)
144146 let invalidateCcu = new Event<_>()
145- let ccu = Import.ImportILAssembly( tcImports.GetImportMap, m, auxModuleLoader, ilScopeRef, tcConfig.implicitIncludeDir, Some fileName, ilModule, invalidateCcu.Publish)
147+ let ccu = Import.ImportILAssembly(
148+ tcImports.GetImportMap, m, auxModuleLoader, ilScopeRef,
149+ tcConfig.implicitIncludeDir, Some fileName, ilModule, invalidateCcu.Publish)
146150 let ccuInfo = mkCcuInfo ilGlobals ilScopeRef ilModule ccu
147151 ccuInfo, None
148152
@@ -220,7 +224,10 @@ type InteractiveChecker internal (tcConfig, tcGlobals, tcImports, tcState, ctok,
220224
221225 // search over all imported CCUs for each cached type
222226 let ccuHasType ( ccu : CcuThunk ) ( nsname : string list ) ( tname : string ) =
223- match ( Some ccu.Contents, nsname) ||> List.fold ( fun entityOpt n -> match entityOpt with None -> None | Some entity -> entity.ModuleOrNamespaceType.AllEntitiesByCompiledAndLogicalMangledNames.TryFind n) with
227+ match ( Some ccu.Contents, nsname) ||> List.fold ( fun entityOpt n ->
228+ match entityOpt with
229+ | None -> None
230+ | Some entity -> entity.ModuleOrNamespaceType.AllEntitiesByCompiledAndLogicalMangledNames.TryFind n) with
224231 | Some ns ->
225232 match Map.tryFind tname ns.ModuleOrNamespaceType.TypesByMangledName with
226233 | Some _ -> true
@@ -256,8 +263,8 @@ type InteractiveChecker internal (tcConfig, tcGlobals, tcImports, tcState, ctok,
256263
257264 let assemblyName = " Project"
258265 let ccus = ccuInfos |> List.map ( fun x -> x.FSharpViewOfMetadata, x.AssemblyAutoOpenAttributes, x.AssemblyInternalsVisibleToAttributes)
259- let tcEnv = CreateInitialTcEnv ( tcGlobals, amap, rng, assemblyName, ccus)
260- let tcState = GetInitialTcState ( rangeStartup, assemblyName, tcConfig, tcGlobals, tcImports, niceNameGen, tcEnv )
266+ let tcInitialEnv = CreateInitialTcEnv ( tcGlobals, amap, rng, assemblyName, ccus)
267+ let tcInitialState = GetInitialTcState ( rangeStartup, assemblyName, tcConfig, tcGlobals, tcImports, niceNameGen, tcInitialEnv )
261268 let ctok = CompilationThreadToken()
262269
263270 let reactorOps =
@@ -266,44 +273,118 @@ type InteractiveChecker internal (tcConfig, tcGlobals, tcImports, tcState, ctok,
266273 async.Return ( Cancellable.runWithoutCancellation ( op ctok))
267274 member __.EnqueueOp ( userOpName , opName , opArg , op ) = ( op ctok) }
268275
269- InteractiveChecker ( tcConfig, tcGlobals, tcImports, tcState, ctok, reactorOps)
276+ // for de-duplicating module names
277+ let moduleNamesDict = ConcurrentDictionary< string, Set< string>>()
278+
279+ InteractiveChecker ( tcConfig, tcGlobals, tcImports, tcInitialState, ctok, reactorOps, moduleNamesDict)
270280
271- member x.ParseScript ( mainInputFileName , source ) =
272- let userOpName = " Unknown"
273- let filename = mainInputFileName
274- // Note: projectSourceFiles is only used to compute isLastCompiland, and is ignored if Build.IsScript(mainInputFileName) is true (which it is in this case).
275- let parsingOptions = FSharpParsingOptions.FromTcConfig( tcConfig, [| filename |], false )
276- let parseErrors , inputOpt , anyErrors = Parser.parseFile ( source, filename, parsingOptions, userOpName)
281+ member private x.MakeProjectResults ( projectFileName : string , parseResults : FSharpParseFileResults [], tcState : TcState , errors : FSharpErrorInfo [],
282+ symbolUses : TcSymbolUses list , topAttrsOpt : TopAttribs option , tcImplFilesOpt : TypedImplFile list option ) =
283+ let assemblyRef = mkSimpleAssRef " stdin"
284+ let assemblyDataOpt = None
285+ let access = tcState.TcEnvFromImpls.AccessRights
286+ let dependencyFiles = parseResults |> Seq.map ( fun x -> x.DependencyFiles) |> Array.concat
287+ let details = ( tcGlobals, tcImports, tcState.Ccu, tcState.CcuSig, symbolUses, topAttrsOpt, assemblyDataOpt, assemblyRef, access, tcImplFilesOpt, dependencyFiles)
288+ FSharpCheckProjectResults ( projectFileName, Some tcConfig, true , errors, Some details)
289+
290+ member private x.ParseScript ( filename : string , source : string ) =
291+ let parsingOptions = FSharpParsingOptions.FromTcConfig( tcConfig, [| filename |], true )
292+ let parseErrors , parseTreeOpt , anyErrors = Parser.parseFile ( source, filename, parsingOptions, userOpName)
293+ let parseTreeOpt = parseTreeOpt |> Option.map ( DeduplicateParsedInputModuleName moduleNamesDict)
277294 let dependencyFiles = [||] // interactions have no dependencies
278- let parseResults = FSharpParseFileResults( parseErrors, inputOpt, parseHadErrors = anyErrors, dependencyFiles = dependencyFiles)
279- parseResults
295+ FSharpParseFileResults ( parseErrors, parseTreeOpt, anyErrors, dependencyFiles)
280296
281- member x.ParseAndCheckScript ( mainInputFileName , source ) =
282- let parseResults = x.ParseScript ( mainInputFileName , source)
297+ member x.ParseAndCheckScript ( projectFileName , filename : string , source : string ) =
298+ let parseResults = x.ParseScript ( filename , source)
283299 let loadClosure = None
284300 let backgroundErrors = [||]
285- let tcResults =
286- Parser.CheckOneFile( parseResults,
287- source,
288- mainInputFileName,
289- " project" ,
290- tcConfig,
291- tcGlobals,
292- tcImports,
293- tcState,
294- loadClosure,
295- backgroundErrors,
296- reactorOps,
297- ( fun () -> true ),
298- None,
299- " " )
300-
301- match tcResults with
301+ let checkAlive = fun () -> true
302+ let textSnapshotInfo = None
303+ let tcState = tcInitialState
304+ let tcResults = Parser.CheckOneFile(
305+ parseResults, source, filename, projectFileName, tcConfig, tcGlobals, tcImports, tcState,
306+ loadClosure, backgroundErrors, reactorOps, checkAlive, textSnapshotInfo, userOpName)
307+ match tcResults with
302308 | tcErrors, Parser.TypeCheckAborted.No scope ->
303- let errors = [| yield ! parseResults.Errors; yield ! tcErrors |]
304- let tcImplFiles = match scope.ImplementationFile with Some x -> Some [ x] | None -> None
305- let typeCheckResults = FSharpCheckFileResults ( mainInputFileName, errors, Some scope, parseResults.DependencyFiles, None, reactorOps, true )
306- let projectResults = FSharpCheckProjectResults ( mainInputFileName, Some tcConfig, true , errors, Some( tcGlobals, tcImports, scope.ThisCcu, scope.CcuSigForFile, [ scope.ScopeSymbolUses], None, None, mkSimpleAssRef " stdin" , tcState.TcEnvFromImpls.AccessRights, tcImplFiles, parseResults.DependencyFiles))
309+ let errors = Array.append parseResults.Errors tcErrors
310+ let tcImplFilesOpt = match scope.ImplementationFile with Some x -> Some [ x] | None -> None
311+ let typeCheckResults = FSharpCheckFileResults ( filename, errors, Some scope, parseResults.DependencyFiles, None, reactorOps, true )
312+ let symbolUses = [ scope.ScopeSymbolUses]
313+ let projectResults = x.MakeProjectResults ( projectFileName, [| parseResults|], tcState, errors, symbolUses, None, tcImplFilesOpt)
307314 parseResults, typeCheckResults, projectResults
308- | _ ->
315+ | _ ->
309316 failwith " unexpected aborted"
317+
318+ member x.ParseAndCheckProject ( projectFileName , fileNames : string [], sources : string []) =
319+ use errorScope = new ErrorScope()
320+ let sink = TcResultsSinkImpl( tcGlobals)
321+
322+ let typeCheckOneInput ( ctok , checkForErrors , tcConfig , tcImports , tcGlobals , prefixPathOpt ) tcSink tcState input =
323+ //// 'use' ensures that the warning handler is restored at the end
324+ //use unwindEL = PushErrorLoggerPhaseUntilUnwind(fun oldLogger ->
325+ // GetErrorLoggerFilteringByScopedPragmas(false, GetScopedPragmasForInput(input), oldLogger) )
326+ //use unwindBP = PushThreadBuildPhaseUntilUnwind BuildPhase.TypeCheck
327+ TypeCheckOneInputEventually ( checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt, tcSink, tcState, input)
328+ |> Eventually.force ctok
329+
330+ let makeTcResult ( tcState : TcState ) ( parseRes : FSharpParseFileResults , ( tcEnvAtEnd : TcEnv , _topAttrs , implFile , ccuSigForFile )) =
331+ let filename = parseRes.FileName
332+ let loadClosure = None
333+ let checkAlive = fun () -> true
334+ let textSnapshotInfo = None
335+ let tcErrors = errorScope.Diagnostics |> List.filter ( fun e -> e.FileName = filename) |> List.toArray
336+ let errors = Array.append parseRes.Errors tcErrors
337+ let scope = TypeCheckInfo( tcConfig, tcGlobals, ccuSigForFile, tcState.Ccu, tcImports, tcEnvAtEnd.AccessRights,
338+ projectFileName, filename, sink.GetResolutions(), sink.GetSymbolUses(), tcEnvAtEnd.NameEnv,
339+ loadClosure, reactorOps, checkAlive, textSnapshotInfo, implFile, sink.GetOpenDeclarations())
340+ FSharpCheckFileResults ( filename, errors, Some scope, parseRes.DependencyFiles, None, reactorOps, true )
341+
342+ // parse files
343+ let parseScript ( filename , source ) = x.ParseScript( filename, source)
344+ let parseResults = Array.zip fileNames sources |> Array.map parseScript
345+ let parseHadErrors = parseResults |> Array.exists ( fun p -> p.ParseHadErrors)
346+ let inputs = parseResults |> Array.choose ( fun p -> p.ParseTree) |> Array.toList
347+
348+ // type check files
349+ let checkForErrors () = parseHadErrors
350+ let prefixPathOpt = None
351+ let tcSink = TcResultsSink.WithSink sink
352+ let tcOneInput = typeCheckOneInput ( ctok, checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt) tcSink
353+ let tcResults , tcState = ( tcInitialState, inputs) ||> List.mapFold tcOneInput
354+ let ( _tcEnvAtEnd , topAttrs , implFiles , _ccuSigsForFiles ), tcState = TypeCheckMultipleInputsFinish( tcResults, tcState)
355+ let tcState , tcImplFiles = TypeCheckClosedInputSetFinish ( implFiles, tcState)
356+
357+ let typeCheckResults = tcResults |> List.toArray |> Array.zip parseResults |> Array.map ( makeTcResult tcState)
358+
359+ // make project results
360+ let parseErrors = parseResults |> Array.collect ( fun p -> p.Errors)
361+ let tcErrors = errorScope.Diagnostics |> List.toArray
362+ let errors = Array.append parseErrors tcErrors
363+ let symbolUses = [ sink.GetSymbolUses()]
364+ let projectResults = x.MakeProjectResults ( projectFileName, parseResults, tcState, errors, symbolUses, Some topAttrs, Some tcImplFiles)
365+
366+ parseResults, typeCheckResults, projectResults
367+
368+ member x.ParseAndCheckProject_simple ( projectFileName , fileNames : string [], sources : string []) =
369+ use errorScope = new ErrorScope()
370+
371+ // parse files
372+ let parseScript ( filename , source ) = x.ParseScript( filename, source)
373+ let parseResults = Array.zip fileNames sources |> Array.map parseScript
374+ let parseHadErrors = parseResults |> Array.exists ( fun p -> p.ParseHadErrors)
375+ let inputs = parseResults |> Array.choose ( fun p -> p.ParseTree) |> Array.toList
376+
377+ // type check files
378+ let checkForErrors () = parseHadErrors
379+ let prefixPathOpt = None
380+ let tcState , topAttrs , tcImplFiles , _tcEnvAtEnd =
381+ TypeCheckClosedInputSet ( ctok, checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt, tcInitialState, inputs)
382+
383+ // make project results
384+ let parseErrors = parseResults |> Array.collect ( fun p -> p.Errors)
385+ let tcErrors = errorScope.Diagnostics |> List.toArray
386+ let errors = Array.append parseErrors tcErrors
387+ let symbolUses = [] //todo:
388+ let projectResults = x.MakeProjectResults ( projectFileName, parseResults, tcState, errors, symbolUses, Some topAttrs, Some tcImplFiles)
389+
390+ projectResults
0 commit comments