/// <summary> /// For the given set of AssemblyData objects, do the following: /// 1) Resolve references from each assembly against other assemblies in the set. /// 2) Choose suitable AssemblySymbol instance for each AssemblyData object. /// /// The first element (index==0) of the assemblies array represents the assembly being built. /// One can think about the rest of the items in assemblies array as assembly references given to the compiler to /// /// build executable for the assembly being built. /// /// </summary> /// /// <param name="assemblies"> /// The set of AssemblyData objects describing assemblies, for which this method should /// resolve references and find suitable AssemblySymbols. This array is not modified by the /// method. /// </param> /// <param name="hasCircularReference"> /// True if the assembly being compiled is indirectly referenced thru some of its own references. /// </param> /// <param name="corLibraryIndex"> /// The definition index of the COR library. /// </param> /// <returns> /// An array of Binding structures describing the result. It has the same amount of items as /// the input assemblies array, Binding structure for each input AssemblyData object resides /// at the same position. /// /// Each Binding structure contains the following data: /// /// - Suitable AssemblySymbol instance for the corresponding assembly, /// null reference if none is available/found. Always null for the first element, which corresponds to the assembly being built. /// /// - Result of resolving assembly references of the corresponding assembly /// against provided set of assembly definitions. Essentially, this is an array returned by /// AssemblyData.BindAssemblyReferences method. /// </returns> internal BoundInputAssembly[] Bind( ImmutableArray <AssemblyData> assemblies, out bool hasCircularReference, out int corLibraryIndex) { Debug.Assert(!assemblies.IsDefault); int totalAssemblies = assemblies.Length; // This is the array where we store the result in. BoundInputAssembly[] boundInputs = new BoundInputAssembly[totalAssemblies]; // Based on assembly identity, for each assembly, // bind its references against the other assemblies we have. for (int i = 0; i < totalAssemblies; i++) { boundInputs[i].ReferenceBinding = assemblies[i].BindAssemblyReferences(assemblies, this.IdentityComparer); } // All assembly symbols should be uninitialized at this point: Debug.Assert(Array.TrueForAll(boundInputs, bi => bi.AssemblySymbol == null)); hasCircularReference = CheckCircularReference(boundInputs); corLibraryIndex = IndexOfCorLibrary(assemblies); // For each assembly, locate AssemblySymbol with similar reference resolution // What does similar mean? // Similar means: // 1) The same references are resolved against the assemblies that we are given. // 2) The same assembly is used as the COR library. TAssemblySymbol[] candidateInputAssemblySymbols = new TAssemblySymbol[totalAssemblies]; // If any assembly from assemblies array refers back to assemblyBeingBuilt, // we know that we cannot reuse symbols for any assemblies containing NoPia // local types. Because we cannot reuse symbols for assembly referring back // to assemblyBeingBuilt. if (!hasCircularReference) { // Deal with assemblies containing NoPia local types. if (ReuseAssemblySymbolsWithNoPiaLocalTypes(boundInputs, candidateInputAssemblySymbols, assemblies, corLibraryIndex)) { return(boundInputs); } } // NoPia shortcut either didn't apply or failed, go through general process // of matching candidates. ReuseAssemblySymbols(boundInputs, candidateInputAssemblySymbols, assemblies, corLibraryIndex); return(boundInputs); }
/// <summary> /// For the given set of AssemblyData objects, do the following: /// 1) Resolve references from each assembly against other assemblies in the set. /// 2) Choose suitable AssemblySymbol instance for each AssemblyData object. /// /// The first element (index==0) of the assemblies array represents the assembly being built. /// One can think about the rest of the items in assemblies array as assembly references given to the compiler to /// build executable for the assembly being built. /// </summary> /// <param name="compilation">Compilation.</param> /// <param name="explicitAssemblies"> /// An array of <see cref="AssemblyData"/> objects describing assemblies, for which this method should /// resolve references and find suitable AssemblySymbols. The first slot contains the assembly being built. /// </param> /// <param name="explicitModules"> /// An array of <see cref="PEModule"/> objects describing standalone modules referenced by the compilation. /// </param> /// <param name="explicitReferences"> /// An array of references passed to the compilation and resolved from #r directives. /// May contain references that were skipped during resolution (they don't have a corresponding explicit assmebly). /// </param> /// <param name="explicitReferenceMap"> /// Maps index to <paramref name="explicitReferences"/> to an index of a resolved assembly or module in <paramref name="explicitAssemblies"/> or modules. /// </param> /// <param name="resolverOpt"> /// Reference resolver used to look up missing assemblies. /// </param> /// <param name="supersedeLowerVersions"> /// Hide lower versions of dependencies that have multiple versions behind an alias. /// </param> /// <param name="assemblyReferencesBySimpleName"> /// Used to filter out assemblies that have the same strong or weak identity. /// Maps simple name to a list of identities. The highest version of each name is the first. /// </param> /// <param name="importOptions"> /// Import options applied to implicitly resolved references. /// </param> /// <param name="allAssemblies"> /// Updated array <paramref name="explicitAssemblies"/> with resolved implicitly referenced assemblies appended. /// </param> /// <param name="implicitlyResolvedReferences"> /// Implicitly resolved references. /// </param> /// <param name="implicitlyResolvedReferenceMap"> /// Maps indices of implicitly resolved references to the corresponding indices of resolved assemblies in <paramref name="allAssemblies"/> (explicit + implicit). /// </param> /// <param name="resolutionDiagnostics"> /// Any diagnostics reported while resolving missing assemblies. /// </param> /// <param name="hasCircularReference"> /// True if the assembly being compiled is indirectly referenced through some of its own references. /// </param> /// <param name="corLibraryIndex"> /// The definition index of the COR library. /// </param> /// <return> /// An array of <see cref="BoundInputAssembly"/> structures describing the result. It has the same amount of items as /// the input assemblies array, <see cref="BoundInputAssembly"/> for each input AssemblyData object resides /// at the same position. /// /// Each <see cref="BoundInputAssembly"/> contains the following data: /// /// - Suitable AssemblySymbol instance for the corresponding assembly, /// null reference if none is available/found. Always null for the first element, which corresponds to the assembly being built. /// /// - Result of resolving assembly references of the corresponding assembly /// against provided set of assembly definitions. Essentially, this is an array returned by /// <see cref="AssemblyData.BindAssemblyReferences(ImmutableArray{AssemblyData}, AssemblyIdentityComparer)"/> method. /// </return> protected BoundInputAssembly[] Bind( TCompilation compilation, ImmutableArray <AssemblyData> explicitAssemblies, ImmutableArray <PEModule> explicitModules, ImmutableArray <MetadataReference> explicitReferences, ImmutableArray <ResolvedReference> explicitReferenceMap, MetadataReferenceResolver resolverOpt, MetadataImportOptions importOptions, bool supersedeLowerVersions, [In, Out] Dictionary <string, List <ReferencedAssemblyIdentity> > assemblyReferencesBySimpleName, out ImmutableArray <AssemblyData> allAssemblies, out ImmutableArray <MetadataReference> implicitlyResolvedReferences, out ImmutableArray <ResolvedReference> implicitlyResolvedReferenceMap, [In, Out] DiagnosticBag resolutionDiagnostics, out bool hasCircularReference, out int corLibraryIndex) { Debug.Assert(explicitAssemblies[0] is AssemblyDataForAssemblyBeingBuilt); Debug.Assert(explicitReferences.Length == explicitReferenceMap.Length); var referenceBindings = ArrayBuilder <AssemblyReferenceBinding[]> .GetInstance(); try { // Based on assembly identity, for each assembly, // bind its references against the other assemblies we have. for (int i = 0; i < explicitAssemblies.Length; i++) { referenceBindings.Add(explicitAssemblies[i].BindAssemblyReferences(explicitAssemblies, IdentityComparer)); } if (resolverOpt?.ResolveMissingAssemblies == true) { ResolveAndBindMissingAssemblies( compilation, explicitAssemblies, explicitModules, explicitReferences, explicitReferenceMap, resolverOpt, importOptions, supersedeLowerVersions, referenceBindings, assemblyReferencesBySimpleName, out allAssemblies, out implicitlyResolvedReferences, out implicitlyResolvedReferenceMap, resolutionDiagnostics); } else { allAssemblies = explicitAssemblies; implicitlyResolvedReferences = ImmutableArray <MetadataReference> .Empty; implicitlyResolvedReferenceMap = ImmutableArray <ResolvedReference> .Empty; } // implicitly resolved missing assemblies were added to both referenceBindings and assemblies: Debug.Assert(referenceBindings.Count == allAssemblies.Length); hasCircularReference = CheckCircularReference(referenceBindings); corLibraryIndex = IndexOfCorLibrary(explicitAssemblies, assemblyReferencesBySimpleName, supersedeLowerVersions); // For each assembly, locate AssemblySymbol with similar reference resolution // What does similar mean? // Similar means: // 1) The same references are resolved against the assemblies that we are given // (or were found duiring implicit assembly resolution). // 2) The same assembly is used as the COR library. var boundInputs = new BoundInputAssembly[referenceBindings.Count]; for (int i = 0; i < referenceBindings.Count; i++) { boundInputs[i].ReferenceBinding = referenceBindings[i]; } var candidateInputAssemblySymbols = new TAssemblySymbol[allAssemblies.Length]; // If any assembly from assemblies array refers back to assemblyBeingBuilt, // we know that we cannot reuse symbols for any assemblies containing NoPia // local types. Because we cannot reuse symbols for assembly referring back // to assemblyBeingBuilt. if (!hasCircularReference) { // Deal with assemblies containing NoPia local types. if (ReuseAssemblySymbolsWithNoPiaLocalTypes(boundInputs, candidateInputAssemblySymbols, allAssemblies, corLibraryIndex)) { return(boundInputs); } } // NoPia shortcut either didn't apply or failed, go through general process // of matching candidates. ReuseAssemblySymbols(boundInputs, candidateInputAssemblySymbols, allAssemblies, corLibraryIndex); return(boundInputs); } finally { referenceBindings.Free(); } }