diff --git a/src/Compiler/Driver/CompilerImports.fs b/src/Compiler/Driver/CompilerImports.fs index 4ab1ca3d7e..a9d1d0cba4 100644 --- a/src/Compiler/Driver/CompilerImports.fs +++ b/src/Compiler/Driver/CompilerImports.fs @@ -2247,110 +2247,99 @@ and [] TcImports phase2 // NOTE: When used in the Language Service this can cause the transitive checking of projects. Hence it must be cancellable. - member tcImports.TryRegisterAndPrepareToImportReferencedDll - (ctok, r: AssemblyResolution) - : Async<(_ * (unit -> AvailableImportedAssembly list)) option> = - async { - CheckDisposed() - let m = r.originalReference.Range - let fileName = r.resolvedPath + member tcImports.RegisterAndImportReferencedAssemblies(ctok, nms: AssemblyResolution list) = + let tryGetAssemblyData (r: AssemblyResolution) = + async { + CheckDisposed() + let m = r.originalReference.Range + let fileName = r.resolvedPath - let! contentsOpt = - async { - match r.ProjectReference with - | Some ilb -> return! ilb.EvaluateRawContents() - | None -> return ProjectAssemblyDataResult.Unavailable true - } + try - // If we have a project reference but did not get any valid contents, - // just return None and do not attempt to read elsewhere. - match contentsOpt with - | ProjectAssemblyDataResult.Unavailable false -> return None - | _ -> + let! contentsOpt = + async { + match r.ProjectReference with + | Some ilb -> return! ilb.EvaluateRawContents() + | None -> return ProjectAssemblyDataResult.Unavailable true + } - let assemblyData = + // If we have a project reference but did not get any valid contents, + // just return None and do not attempt to read elsewhere. match contentsOpt with - | ProjectAssemblyDataResult.Available ilb -> ilb - | ProjectAssemblyDataResult.Unavailable _ -> - let ilModule, ilAssemblyRefs = tcImports.OpenILBinaryModule(ctok, fileName, m) - RawFSharpAssemblyDataBackedByFileOnDisk(ilModule, ilAssemblyRefs) :> IRawFSharpAssemblyData + | ProjectAssemblyDataResult.Unavailable false -> return None + | _ -> + + match contentsOpt with + | ProjectAssemblyDataResult.Available ilb -> return Some(r, ilb) + | ProjectAssemblyDataResult.Unavailable _ -> + let ilModule, ilAssemblyRefs = tcImports.OpenILBinaryModule(ctok, fileName, m) + return Some(r, RawFSharpAssemblyDataBackedByFileOnDisk(ilModule, ilAssemblyRefs)) + + with e -> + errorR (Error(FSComp.SR.buildProblemReadingAssembly (fileName, e.Message), m)) + return None + } - let ilShortAssemName = assemblyData.ShortAssemblyName - let ilScopeRef = assemblyData.ILScopeRef + let registerDll (r: AssemblyResolution, assemblyData: IRawFSharpAssemblyData) = + let m = r.originalReference.Range + let fileName = r.resolvedPath + let ilShortAssemName = assemblyData.ShortAssemblyName + let ilScopeRef = assemblyData.ILScopeRef - if tcImports.IsAlreadyRegistered ilShortAssemName then - let dllinfo = tcImports.FindDllInfo(ctok, m, ilShortAssemName) + if tcImports.IsAlreadyRegistered ilShortAssemName then - let phase2 () = - [ tcImports.FindCcuInfo(ctok, m, ilShortAssemName, lookupOnly = true) ] + let phase2 () = + [ tcImports.FindCcuInfo(ctok, m, ilShortAssemName, lookupOnly = true) ] - return Some(dllinfo, phase2) - else - let dllinfo = - { - RawMetadata = assemblyData - FileName = fileName + async { return phase2 () } + else + let dllinfo = + { + RawMetadata = assemblyData + FileName = fileName #if !NO_TYPEPROVIDERS - ProviderGeneratedAssembly = None - IsProviderGenerated = false - ProviderGeneratedStaticLinkMap = None + ProviderGeneratedAssembly = None + IsProviderGenerated = false + ProviderGeneratedStaticLinkMap = None #endif - ILScopeRef = ilScopeRef - ILAssemblyRefs = assemblyData.ILAssemblyRefs - } + ILScopeRef = ilScopeRef + ILAssemblyRefs = assemblyData.ILAssemblyRefs + } - tcImports.RegisterDll dllinfo + tcImports.RegisterDll dllinfo - let phase2 = - if assemblyData.HasAnyFSharpSignatureDataAttribute then - if not assemblyData.HasMatchingFSharpSignatureDataAttribute then - errorR (Error(FSComp.SR.buildDifferentVersionMustRecompile fileName, m)) - tcImports.PrepareToImportReferencedILAssembly(ctok, m, fileName, dllinfo) - else - try - tcImports.PrepareToImportReferencedFSharpAssembly(ctok, m, fileName, dllinfo) - with e -> - error (Error(FSComp.SR.buildErrorOpeningBinaryFile (fileName, e.Message), m)) - else + let phase2 = + if assemblyData.HasAnyFSharpSignatureDataAttribute then + if not assemblyData.HasMatchingFSharpSignatureDataAttribute then + errorR (Error(FSComp.SR.buildDifferentVersionMustRecompile fileName, m)) tcImports.PrepareToImportReferencedILAssembly(ctok, m, fileName, dllinfo) + else + try + tcImports.PrepareToImportReferencedFSharpAssembly(ctok, m, fileName, dllinfo) + with e -> + error (Error(FSComp.SR.buildErrorOpeningBinaryFile (fileName, e.Message), m)) + else + tcImports.PrepareToImportReferencedILAssembly(ctok, m, fileName, dllinfo) - return Some(dllinfo, phase2) - } + async { return phase2 () } - // NOTE: When used in the Language Service this can cause the transitive checking of projects. Hence it must be cancellable. - member tcImports.RegisterAndImportReferencedAssemblies(ctok, nms: AssemblyResolution list) = async { CheckDisposed() - let tcConfig = tcConfigP.Get ctok + let! assemblyData = nms |> List.map tryGetAssemblyData |> MultipleDiagnosticsLoggers.Parallel - let runMethod = - match tcConfig.parallelReferenceResolution with - | ParallelReferenceResolution.On -> MultipleDiagnosticsLoggers.Parallel - | ParallelReferenceResolution.Off -> MultipleDiagnosticsLoggers.Sequential + // Preserve determinicstic order of references, because types from later assemblies may shadow earlier ones. + let phase2s = assemblyData |> Seq.choose id |> Seq.map registerDll |> List.ofSeq - let! results = - nms - |> List.map (fun nm -> - async { - try - use _ = new CompilationGlobalsScope() - return! tcImports.TryRegisterAndPrepareToImportReferencedDll(ctok, nm) - with e -> - errorR (Error(FSComp.SR.buildProblemReadingAssembly (nm.resolvedPath, e.Message), nm.originalReference.Range)) - return None - }) - |> runMethod - - let _dllinfos, phase2s = results |> Array.choose id |> List.ofArray |> List.unzip fixupOrphanCcus () - let ccuinfos = List.collect (fun phase2 -> phase2 ()) phase2s + + let! ccuinfos = phase2s |> MultipleDiagnosticsLoggers.Parallel if importsBase.IsSome then importsBase.Value.CcuTable.Values |> Seq.iter addConstraintSources ccuTable.Values |> Seq.iter addConstraintSources - return ccuinfos + return ccuinfos |> List.concat } /// Note that implicit loading is not used for compilations from MSBuild, which passes ``--noframework`` @@ -2376,7 +2365,7 @@ and [] TcImports ReportWarnings warns tcImports.RegisterAndImportReferencedAssemblies(ctok, res) - |> Async.RunImmediate + |> Async.RunSynchronously |> ignore true @@ -2684,7 +2673,7 @@ let RequireReferences (ctok, tcImports: TcImports, tcEnv, thisAssemblyName, reso let ccuinfos = tcImports.RegisterAndImportReferencedAssemblies(ctok, resolutions) - |> Async.RunImmediate + |> Async.RunSynchronously let asms = ccuinfos