Skip to content

Commit f48c44e

Browse files
committed
parallel reference resolution with deterministic order
1 parent 2faf1ca commit f48c44e

File tree

1 file changed

+66
-77
lines changed

1 file changed

+66
-77
lines changed

src/Compiler/Driver/CompilerImports.fs

Lines changed: 66 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -2247,104 +2247,93 @@ and [<Sealed>] TcImports
22472247
phase2
22482248

22492249
// NOTE: When used in the Language Service this can cause the transitive checking of projects. Hence it must be cancellable.
2250-
member tcImports.TryRegisterAndPrepareToImportReferencedDll
2251-
(ctok, r: AssemblyResolution)
2252-
: Async<(_ * (unit -> AvailableImportedAssembly list)) option> =
2253-
async {
2254-
CheckDisposed()
2255-
let m = r.originalReference.Range
2256-
let fileName = r.resolvedPath
2250+
member tcImports.RegisterAndImportReferencedAssemblies(ctok, nms: AssemblyResolution list) =
2251+
let tryGetAssemblyData (r: AssemblyResolution) =
2252+
async {
2253+
CheckDisposed()
2254+
let m = r.originalReference.Range
2255+
let fileName = r.resolvedPath
22572256

2258-
let! contentsOpt =
2259-
async {
2260-
match r.ProjectReference with
2261-
| Some ilb -> return! ilb.EvaluateRawContents()
2262-
| None -> return ProjectAssemblyDataResult.Unavailable true
2263-
}
2257+
try
22642258

2265-
// If we have a project reference but did not get any valid contents,
2266-
// just return None and do not attempt to read elsewhere.
2267-
match contentsOpt with
2268-
| ProjectAssemblyDataResult.Unavailable false -> return None
2269-
| _ ->
2259+
let! contentsOpt =
2260+
async {
2261+
match r.ProjectReference with
2262+
| Some ilb -> return! ilb.EvaluateRawContents()
2263+
| None -> return ProjectAssemblyDataResult.Unavailable true
2264+
}
22702265

2271-
let assemblyData =
2266+
// If we have a project reference but did not get any valid contents,
2267+
// just return None and do not attempt to read elsewhere.
22722268
match contentsOpt with
2273-
| ProjectAssemblyDataResult.Available ilb -> ilb
2274-
| ProjectAssemblyDataResult.Unavailable _ ->
2275-
let ilModule, ilAssemblyRefs = tcImports.OpenILBinaryModule(ctok, fileName, m)
2276-
RawFSharpAssemblyDataBackedByFileOnDisk(ilModule, ilAssemblyRefs) :> IRawFSharpAssemblyData
2269+
| ProjectAssemblyDataResult.Unavailable false -> return None
2270+
| _ ->
2271+
2272+
match contentsOpt with
2273+
| ProjectAssemblyDataResult.Available ilb -> return Some(r, ilb)
2274+
| ProjectAssemblyDataResult.Unavailable _ ->
2275+
let ilModule, ilAssemblyRefs = tcImports.OpenILBinaryModule(ctok, fileName, m)
2276+
return Some(r, RawFSharpAssemblyDataBackedByFileOnDisk(ilModule, ilAssemblyRefs))
2277+
2278+
with e ->
2279+
errorR (Error(FSComp.SR.buildProblemReadingAssembly (fileName, e.Message), m))
2280+
return None
2281+
}
22772282

2278-
let ilShortAssemName = assemblyData.ShortAssemblyName
2279-
let ilScopeRef = assemblyData.ILScopeRef
2283+
let registerDll (r: AssemblyResolution, assemblyData: IRawFSharpAssemblyData) =
2284+
let m = r.originalReference.Range
2285+
let fileName = r.resolvedPath
2286+
let ilShortAssemName = assemblyData.ShortAssemblyName
2287+
let ilScopeRef = assemblyData.ILScopeRef
22802288

2281-
if tcImports.IsAlreadyRegistered ilShortAssemName then
2282-
let dllinfo = tcImports.FindDllInfo(ctok, m, ilShortAssemName)
2289+
if tcImports.IsAlreadyRegistered ilShortAssemName then
22832290

2284-
let phase2 () =
2285-
[ tcImports.FindCcuInfo(ctok, m, ilShortAssemName, lookupOnly = true) ]
2291+
let phase2 () =
2292+
[ tcImports.FindCcuInfo(ctok, m, ilShortAssemName, lookupOnly = true) ]
22862293

2287-
return Some(dllinfo, phase2)
2288-
else
2289-
let dllinfo =
2290-
{
2291-
RawMetadata = assemblyData
2292-
FileName = fileName
2294+
phase2
2295+
else
2296+
let dllinfo =
2297+
{
2298+
RawMetadata = assemblyData
2299+
FileName = fileName
22932300
#if !NO_TYPEPROVIDERS
2294-
ProviderGeneratedAssembly = None
2295-
IsProviderGenerated = false
2296-
ProviderGeneratedStaticLinkMap = None
2301+
ProviderGeneratedAssembly = None
2302+
IsProviderGenerated = false
2303+
ProviderGeneratedStaticLinkMap = None
22972304
#endif
2298-
ILScopeRef = ilScopeRef
2299-
ILAssemblyRefs = assemblyData.ILAssemblyRefs
2300-
}
2305+
ILScopeRef = ilScopeRef
2306+
ILAssemblyRefs = assemblyData.ILAssemblyRefs
2307+
}
23012308

2302-
tcImports.RegisterDll dllinfo
2309+
tcImports.RegisterDll dllinfo
23032310

2304-
let phase2 =
2305-
if assemblyData.HasAnyFSharpSignatureDataAttribute then
2306-
if not assemblyData.HasMatchingFSharpSignatureDataAttribute then
2307-
errorR (Error(FSComp.SR.buildDifferentVersionMustRecompile fileName, m))
2308-
tcImports.PrepareToImportReferencedILAssembly(ctok, m, fileName, dllinfo)
2309-
else
2310-
try
2311-
tcImports.PrepareToImportReferencedFSharpAssembly(ctok, m, fileName, dllinfo)
2312-
with e ->
2313-
error (Error(FSComp.SR.buildErrorOpeningBinaryFile (fileName, e.Message), m))
2314-
else
2311+
let phase2 =
2312+
if assemblyData.HasAnyFSharpSignatureDataAttribute then
2313+
if not assemblyData.HasMatchingFSharpSignatureDataAttribute then
2314+
errorR (Error(FSComp.SR.buildDifferentVersionMustRecompile fileName, m))
23152315
tcImports.PrepareToImportReferencedILAssembly(ctok, m, fileName, dllinfo)
2316+
else
2317+
try
2318+
tcImports.PrepareToImportReferencedFSharpAssembly(ctok, m, fileName, dllinfo)
2319+
with e ->
2320+
error (Error(FSComp.SR.buildErrorOpeningBinaryFile (fileName, e.Message), m))
2321+
else
2322+
tcImports.PrepareToImportReferencedILAssembly(ctok, m, fileName, dllinfo)
23162323

2317-
return Some(dllinfo, phase2)
2318-
}
2324+
phase2
23192325

2320-
// NOTE: When used in the Language Service this can cause the transitive checking of projects. Hence it must be cancellable.
2321-
member tcImports.RegisterAndImportReferencedAssemblies(ctok, nms: AssemblyResolution list) =
23222326
async {
23232327
CheckDisposed()
23242328

2325-
let tcConfig = tcConfigP.Get ctok
2329+
let! assemblyData = nms |> List.map tryGetAssemblyData |> MultipleDiagnosticsLoggers.Parallel
23262330

2327-
let runMethod =
2328-
match tcConfig.parallelReferenceResolution with
2329-
| ParallelReferenceResolution.On -> MultipleDiagnosticsLoggers.Parallel
2330-
| ParallelReferenceResolution.Off -> MultipleDiagnosticsLoggers.Sequential
2331+
// Preserve determinicstic order of references, because types from later assemblies may shadow earlier ones.
2332+
let phase2s = assemblyData |> Seq.choose id |> Seq.map registerDll |> List.ofSeq
23312333

2332-
let! results =
2333-
nms
2334-
|> List.map (fun nm ->
2335-
async {
2336-
try
2337-
use _ = new CompilationGlobalsScope()
2338-
return! tcImports.TryRegisterAndPrepareToImportReferencedDll(ctok, nm)
2339-
with e ->
2340-
errorR (Error(FSComp.SR.buildProblemReadingAssembly (nm.resolvedPath, e.Message), nm.originalReference.Range))
2341-
return None
2342-
})
2343-
|> runMethod
2344-
2345-
let _dllinfos, phase2s = results |> Array.choose id |> List.ofArray |> List.unzip
23462334
fixupOrphanCcus ()
2347-
let ccuinfos = List.collect (fun phase2 -> phase2 ()) phase2s
2335+
2336+
let ccuinfos = phase2s |> List.collect (fun phase2 -> phase2 ())
23482337

23492338
if importsBase.IsSome then
23502339
importsBase.Value.CcuTable.Values |> Seq.iter addConstraintSources

0 commit comments

Comments
 (0)