提交 e4a7cca2 编写于 作者: T Tomas Matousek

Avoid rebinding references bound to explicitly specified definitions, even if...

Avoid rebinding references bound to explicitly specified definitions, even if a better version is available after resolution
上级 bb38549f
......@@ -8,11 +8,11 @@
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
using Microsoft.CodeAnalysis.CSharp.Symbols.Retargeting;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
using Symbols.Retargeting;
using MetadataOrDiagnostic = System.Object;
public partial class CSharpCompilation
......@@ -307,7 +307,6 @@ private void InitializeAssemblyReuseData(AssemblySymbol assemblySymbol, Immutabl
private bool CreateAndSetSourceAssemblyFullBind(CSharpCompilation compilation)
{
var resolutionDiagnostics = DiagnosticBag.GetInstance();
var implicitlyResolvedReferences = ArrayBuilder<MetadataReference>.GetInstance();
try
{
......@@ -327,29 +326,36 @@ private bool CreateAndSetSourceAssemblyFullBind(CSharpCompilation compilation)
resolutionDiagnostics);
var assemblyBeingBuiltData = new AssemblyDataForAssemblyBeingBuilt(new AssemblyIdentity(name: SimpleAssemblyName), referencedAssemblies, modules);
var allAssemblyData = referencedAssemblies.Insert(0, assemblyBeingBuiltData);
var explicitAssemblyData = referencedAssemblies.Insert(0, assemblyBeingBuiltData);
// Let's bind all the references and resolve missing one (if resolver is available)
bool hasCircularReference;
int corLibraryIndex;
ImmutableArray<MetadataReference> implicitlyResolvedReferences;
ImmutableArray<ResolvedReference> implicitlyResolvedReferenceMap;
ImmutableArray<AssemblyData> allAssemblyData;
BoundInputAssembly[] bindingResult = Bind(
ref allAssemblyData,
explicitAssemblyData,
compilation.Options.MetadataReferenceResolver,
compilation.Options.MetadataImportOptions,
implicitlyResolvedReferences,
out allAssemblyData,
out implicitlyResolvedReferences,
out implicitlyResolvedReferenceMap,
resolutionDiagnostics,
out hasCircularReference,
out corLibraryIndex);
Debug.Assert(bindingResult.Length == allAssemblyData.Length);
references = references.AddRange(implicitlyResolvedReferences);
referenceMap = referenceMap.AddRange(implicitlyResolvedReferenceMap);
Dictionary<MetadataReference, int> referencedAssembliesMap, referencedModulesMap;
ImmutableArray<ImmutableArray<string>> aliasesOfReferencedAssemblies;
BuildReferencedAssembliesAndModulesMaps(
references,
referenceMap,
implicitlyResolvedReferences,
referencedAssemblies.Length,
modules.Length,
out referencedAssembliesMap,
out referencedModulesMap,
......@@ -394,12 +400,15 @@ private bool CreateAndSetSourceAssemblyFullBind(CSharpCompilation compilation)
// This should be done after we created/found all AssemblySymbols
Dictionary<AssemblyIdentity, MissingAssemblySymbol> missingAssemblies = null;
// -1 for assembly being built:
int totalReferencedAssemblyCount = allAssemblyData.Length - 1;
// Setup bound references for newly created SourceAssemblySymbol
ImmutableArray<ModuleReferences<AssemblySymbol>> moduleReferences;
SetupReferencesForSourceAssembly(
allAssemblyData,
assemblySymbol,
modules,
totalReferencedAssemblyCount,
bindingResult,
ref missingAssemblies,
out moduleReferences);
......@@ -461,7 +470,6 @@ private bool CreateAndSetSourceAssemblyFullBind(CSharpCompilation compilation)
finally
{
resolutionDiagnostics.Free();
implicitlyResolvedReferences.Free();
}
}
......@@ -678,9 +686,9 @@ private static void UpdateSymbolCacheNoLock(List<int> newSymbols, ImmutableArray
}
private static void SetupReferencesForSourceAssembly(
ImmutableArray<AssemblyData> allAssemblyData,
SourceAssemblySymbol sourceAssembly,
ImmutableArray<PEModule> modules,
int totalReferencedAssemblyCount,
BoundInputAssembly[] bindingResult,
ref Dictionary<AssemblyIdentity, MissingAssemblySymbol> missingAssemblies,
out ImmutableArray<ModuleReferences<AssemblySymbol>> moduleReferences)
......@@ -693,8 +701,7 @@ private static void UpdateSymbolCacheNoLock(List<int> newSymbols, ImmutableArray
int refsUsed = 0;
for (int moduleIndex = 0; moduleIndex < moduleSymbols.Length; moduleIndex++)
{
// -1 for assembly being built
int refsCount = (moduleIndex == 0) ? (allAssemblyData.Length - 1) : modules[moduleIndex - 1].ReferencedAssemblies.Length;
int refsCount = (moduleIndex == 0) ? totalReferencedAssemblyCount : modules[moduleIndex - 1].ReferencedAssemblies.Length;
var identities = new AssemblyIdentity[refsCount];
var symbols = new AssemblySymbol[refsCount];
......@@ -731,7 +738,7 @@ private static void UpdateSymbolCacheNoLock(List<int> newSymbols, ImmutableArray
refsUsed += refsCount;
}
moduleReferences = moduleReferencesBuilder.AsImmutableOrEmpty();
moduleReferences = moduleReferencesBuilder.ToImmutableOrEmptyAndFree();
}
private static AssemblySymbol GetAssemblyDefinitionSymbol(
......
......@@ -139,5 +139,10 @@ public static T Peek<T>(this ArrayBuilder<T> builder)
{
return builder[builder.Count - 1];
}
public static ImmutableArray<T> ToImmutableOrEmptyAndFree<T>(this ArrayBuilder<T> builderOpt)
{
return builderOpt?.ToImmutableAndFree() ?? ImmutableArray<T>.Empty;
}
}
}
......@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.CodeAnalysis.Collections;
using Roslyn.Utilities;
......@@ -21,10 +22,9 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol>
/// build executable for the assembly being built.
/// </summary>
///
/// <param name="assemblies">
/// Input: An array of <see cref="AssemblyData"/> objects describing assemblies, for which this method should
/// resolve references and find suitable AssemblySymbols.
/// Output: Updated array with resolved implicitly referenced assemblies appended.
/// <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="resolverOpt">
/// Reference resolver used to look up missing assemblies.
......@@ -32,8 +32,14 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol>
/// <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, corresponding to <see cref="AssemblyData"/> appended to the <paramref name="assemblies"/> array.
/// Implicitly resolved references.
/// </param>
/// <param name="implicitlyResolvedReferenceMap">
/// Maps index to all references (explicit + implicit) to an index of a resolved assembly in all assemblies (explicit + implicit).
/// </param>
/// <param name="resolutionDiagnostics">
/// Any diagnostics reported while resolving missing assemblies.
......@@ -58,40 +64,51 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol>
/// against provided set of assembly definitions. Essentially, this is an array returned by
/// <see cref="AssemblyData.BindAssemblyReferences(ImmutableArray{AssemblyData}, AssemblyIdentityComparer)"/> method.
/// </return>
internal BoundInputAssembly[] Bind(
ref ImmutableArray<AssemblyData> assemblies,
protected BoundInputAssembly[] Bind(
ImmutableArray<AssemblyData> explicitAssemblies,
MetadataReferenceResolver resolverOpt,
MetadataImportOptions importOptions,
ArrayBuilder<MetadataReference> implicitlyResolvedReferences,
out ImmutableArray<AssemblyData> allAssemblies,
out ImmutableArray<MetadataReference> implicitlyResolvedReferences,
out ImmutableArray<ResolvedReference> implicitlyResolvedReferenceMap,
DiagnosticBag resolutionDiagnostics,
out bool hasCircularReference,
out int corLibraryIndex)
{
Debug.Assert(!assemblies.IsDefault);
Debug.Assert(explicitAssemblies[0] is AssemblyDataForAssemblyBeingBuilt);
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 < assemblies.Length; i++)
for (int i = 0; i < explicitAssemblies.Length; i++)
{
referenceBindings.Add(assemblies[i].BindAssemblyReferences(assemblies, IdentityComparer));
referenceBindings.Add(explicitAssemblies[i].BindAssemblyReferences(explicitAssemblies, IdentityComparer));
}
if (resolverOpt?.ResolveMissingAssemblies == true)
{
ResolveAndBindMissingAssemblies(assemblies, referenceBindings, implicitlyResolvedReferences, resolverOpt, importOptions, resolutionDiagnostics, out assemblies);
ResolveAndBindMissingAssemblies(explicitAssemblies, resolverOpt, importOptions, referenceBindings, out allAssemblies, out implicitlyResolvedReferences, out implicitlyResolvedReferenceMap, resolutionDiagnostics);
}
else
{
allAssemblies = explicitAssemblies;
implicitlyResolvedReferences = ImmutableArray<MetadataReference>.Empty;
implicitlyResolvedReferenceMap = ImmutableArray<ResolvedReference>.Empty;
}
hasCircularReference = CheckCircularReference(referenceBindings);
// implicitly resolved missing assemblies were added to both referenceBindings and assemblies:
Debug.Assert(referenceBindings.Count == allAssemblies.Length);
corLibraryIndex = IndexOfCorLibrary(assemblies);
hasCircularReference = CheckCircularReference(referenceBindings);
corLibraryIndex = IndexOfCorLibrary(allAssemblies);
// 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.
// 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];
......@@ -100,7 +117,7 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol>
boundInputs[i].ReferenceBinding = referenceBindings[i];
}
var candidateInputAssemblySymbols = new TAssemblySymbol[assemblies.Length];
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
......@@ -109,7 +126,7 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol>
if (!hasCircularReference)
{
// Deal with assemblies containing NoPia local types.
if (ReuseAssemblySymbolsWithNoPiaLocalTypes(boundInputs, candidateInputAssemblySymbols, assemblies, corLibraryIndex))
if (ReuseAssemblySymbolsWithNoPiaLocalTypes(boundInputs, candidateInputAssemblySymbols, allAssemblies, corLibraryIndex))
{
return boundInputs;
}
......@@ -118,7 +135,7 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol>
// NoPia shortcut either didn't apply or failed, go through general process
// of matching candidates.
ReuseAssemblySymbols(boundInputs, candidateInputAssemblySymbols, assemblies, corLibraryIndex);
ReuseAssemblySymbols(boundInputs, candidateInputAssemblySymbols, allAssemblies, corLibraryIndex);
return boundInputs;
}
......@@ -130,21 +147,29 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol>
private void ResolveAndBindMissingAssemblies(
ImmutableArray<AssemblyData> explicitAssemblies,
ArrayBuilder<AssemblyReferenceBinding[]> referenceBindings,
ArrayBuilder<MetadataReference> resolvedReferences,
MetadataReferenceResolver resolver,
MetadataImportOptions importOptions,
DiagnosticBag resolutionDiagnostics,
out ImmutableArray<AssemblyData> allAssemblies)
[In, Out] ArrayBuilder<AssemblyReferenceBinding[]> referenceBindings,
out ImmutableArray<AssemblyData> allAssemblies,
out ImmutableArray<MetadataReference> metadataReferences,
out ImmutableArray<ResolvedReference> resolvedReferences,
DiagnosticBag resolutionDiagnostics)
{
Debug.Assert(explicitAssemblies[0] is AssemblyDataForAssemblyBeingBuilt);
var implicitAssemblies = ArrayBuilder<AssemblyData>.GetInstance();
// tracks identities we already asked the resolver to resolve:
var resolvedMissingIdentities = PooledHashSet<AssemblyIdentity>.GetInstance();
var requestedIdentities = PooledHashSet<AssemblyIdentity>.GetInstance();
// reference bindings of implicit assemblies, use to calculate a fixed point:
// reference bindings of implicit assemblies, used to calculate a fixed point:
var referenceBindingsToProcess = ArrayBuilder<AssemblyReferenceBinding[]>.GetInstance();
var metadataReferencesBuilder = ArrayBuilder<MetadataReference>.GetInstance();
Dictionary<string, List<ReferencedAssemblyIdentity>> lazyResolvedReferencesBySimpleName = null;
Dictionary<MetadataReference, ArrayBuilder<string>> lazyAliasMap = null;
try
{
// collect all missing identities, resolve the assemblies and bind their references against explicit definitions:
......@@ -154,9 +179,13 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol>
{
foreach (var binding in referenceBindingsToProcess.Pop())
{
// try resolve a reference if eitehr the binding failed or didn't find an exact match:
if (binding.IsBound && binding.VersionDifference == 0 ||
resolvedMissingIdentities.Contains(binding.ReferenceIdentity))
// only attempt to resolve unbound references (regardless of version difference of the bound ones)
if (binding.IsBound)
{
continue;
}
if (!requestedIdentities.Add(binding.ReferenceIdentity))
{
continue;
}
......@@ -173,8 +202,19 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol>
continue;
}
resolvedReferences.Add(peReference);
resolvedMissingIdentities.Add(binding.ReferenceIdentity);
// The resolver may return different version than we asked for, so it may also happen that
// it returns the same identity for two different input identities (e.g. if a higher version
// of an assembly is available than what the assemblies reference: "A, v1" -> "A, v3" and "A, v2" -> "A, v3").
// If such case occurs merge the properties (aliases) of the resulting references in the same way we do
var existingReference = TryAddAssembly(data.Identity, peReference, resolutionDiagnostics, Location.None, ref lazyResolvedReferencesBySimpleName);
if (existingReference != null)
{
MergeReferenceProperties(existingReference, peReference, resolutionDiagnostics, ref lazyAliasMap);
continue;
}
metadataReferencesBuilder.Add(peReference);
implicitAssemblies.Add(data);
var referenceBinding = data.BindAssemblyReferences(explicitAssemblies, IdentityComparer);
......@@ -183,72 +223,102 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol>
}
}
if (implicitAssemblies.Count == 0)
{
Debug.Assert(lazyAliasMap == null);
Debug.Assert(lazyResolvedReferencesBySimpleName == null);
resolvedReferences = ImmutableArray<ResolvedReference>.Empty;
metadataReferences = ImmutableArray<MetadataReference>.Empty;
allAssemblies = explicitAssemblies;
return;
}
// Rebind assembly references that were initially missing. All bindings established above
// are against explicitly specified references.
// NB: includes the assembly being built:
int explicitAssemblyCount = explicitAssemblies.Length;
allAssemblies = explicitAssemblies.AddRange(implicitAssemblies);
// Rebind assembly referenced that were initially missing or were bound to a definitions with a different version
// (with more assembly identities available we may have a better match now).
if (implicitAssemblies.Count > 0)
{
foreach (var referenceBinding in referenceBindings)
for (int bindingsIndex = 0; bindingsIndex < referenceBindings.Count; bindingsIndex++)
{
var referenceBinding = referenceBindings[bindingsIndex];
for (int i = 0; i < referenceBinding.Length; i++)
{
var binding = referenceBinding[i];
if (!binding.IsBound || binding.VersionDifference != 0)
// We don't rebind references bound to a non-matching version of a reference that was explicitly
// specified, even if we have a better version now.
if (binding.IsBound)
{
continue;
}
// We only need to resolve against implicitly resolved assemblies,
// since we already resolved against explicitly specified ones.
var newBinding = ResolveReferencedAssembly(
referenceBinding[i] = ResolveReferencedAssembly(
binding.ReferenceIdentity,
allAssemblies,
explicitAssemblyCount,
IdentityComparer);
if (IsBetterVersionMatch(binding.ReferenceIdentity, allAssemblies, binding, newBinding))
{
referenceBinding[i] = newBinding;
}
}
}
}
UpdateBindingsOfAssemblyBeingBuilt(referenceBindings, explicitAssemblies, implicitAssemblies);
}
UpdateBindingsOfAssemblyBeingBuilt(referenceBindings, explicitAssemblyCount, implicitAssemblies);
metadataReferences = metadataReferencesBuilder.ToImmutable();
resolvedReferences = ToResolvedAssemblyReferences(metadataReferences, lazyAliasMap, explicitAssemblyCount);
}
finally
{
implicitAssemblies.Free();
resolvedMissingIdentities.Free();
requestedIdentities.Free();
referenceBindingsToProcess.Free();
metadataReferencesBuilder.Free();
}
}
private static void UpdateBindingsOfAssemblyBeingBuilt(ArrayBuilder<AssemblyReferenceBinding[]> referenceBindings, ImmutableArray<AssemblyData> explicitAssemblies, ArrayBuilder<AssemblyData> implicitAssemblies)
private static ImmutableArray<ResolvedReference> ToResolvedAssemblyReferences(
ImmutableArray<MetadataReference> references,
Dictionary<MetadataReference, ArrayBuilder<string>> aliasMapOpt,
int explicitAssemblyCount)
{
var result = ArrayBuilder<ResolvedReference>.GetInstance(references.Length);
for (int i = 0; i < references.Length; i++)
{
// -1 for assembly being built
result.Add(new ResolvedReference(explicitAssemblyCount - 1 + i, MetadataImageKind.Assembly, GetAndFreeAliases(references[i], aliasMapOpt)));
}
return result.ToImmutableAndFree();
}
private static void UpdateBindingsOfAssemblyBeingBuilt(ArrayBuilder<AssemblyReferenceBinding[]> referenceBindings, int explicitAssemblyCount, ArrayBuilder<AssemblyData> implicitAssemblies)
{
var referenceBindingsOfAssemblyBeingBuilt = referenceBindings[0];
// add implicitly resolved assemblies to the bindings of the assembly being built:
var bindingsOfAssemblyBeingBuilt = ArrayBuilder<AssemblyReferenceBinding>.GetInstance(referenceBindings[0].Length + implicitAssemblies.Count);
var bindingsOfAssemblyBeingBuilt = ArrayBuilder<AssemblyReferenceBinding>.GetInstance(referenceBindingsOfAssemblyBeingBuilt.Length + implicitAssemblies.Count);
// add bindings for explicitly specified assemblies (-1 for the assembly being built):
bindingsOfAssemblyBeingBuilt.AddRange(referenceBindings[0], explicitAssemblies.Length - 1);
bindingsOfAssemblyBeingBuilt.AddRange(referenceBindingsOfAssemblyBeingBuilt, explicitAssemblyCount - 1);
// add bindings for implicitly resolved assemblies:
for (int i = 0; i < implicitAssemblies.Count; i++)
{
bindingsOfAssemblyBeingBuilt.Add(new AssemblyReferenceBinding(implicitAssemblies[i].Identity, explicitAssemblies.Length + i));
bindingsOfAssemblyBeingBuilt.Add(new AssemblyReferenceBinding(implicitAssemblies[i].Identity, explicitAssemblyCount + i));
}
// add bindings for assemblies referenced by modules added to the compilation:
bindingsOfAssemblyBeingBuilt.AddRange(referenceBindings[0], explicitAssemblies.Length - 1, referenceBindings[0].Length - explicitAssemblies.Length + 1);
bindingsOfAssemblyBeingBuilt.AddRange(referenceBindingsOfAssemblyBeingBuilt, explicitAssemblyCount - 1, referenceBindingsOfAssemblyBeingBuilt.Length - explicitAssemblyCount + 1);
referenceBindings[0] = bindingsOfAssemblyBeingBuilt.ToArrayAndFree();
}
internal AssemblyData ResolveMissingAssembly(
AssemblyIdentity identity,
AssemblyIdentity referenceIdentity,
PortableExecutableReference peReference,
MetadataImportOptions importOptions,
DiagnosticBag diagnostics)
......@@ -268,8 +338,16 @@ private static void UpdateBindingsOfAssemblyBeingBuilt(ArrayBuilder<AssemblyRefe
return null;
}
var assembly = assemblyMetadata.GetAssembly();
// Allow reference and definition identities to differ in version, but not other properties:
if (IdentityComparer.Compare(referenceIdentity, assembly.Identity) == AssemblyIdentityComparer.ComparisonResult.NotEquivalent)
{
return null;
}
return CreateAssemblyDataForFile(
assemblyMetadata.GetAssembly(),
assembly,
assemblyMetadata.CachedSymbols,
peReference.DocumentationProvider,
SimpleAssemblyName,
......
......@@ -106,7 +106,7 @@ public int Index
private string GetDebuggerDisplay()
{
return IsSkipped ? "<skipped>" : (_kind == MetadataImageKind.Assembly ? "A[" : "M[") + Index + "]: aliases=" + _aliases.ToString();
return IsSkipped ? "<skipped>" : $"{(_kind == MetadataImageKind.Assembly ? "A" : "M")}[{Index}]: aliases='{string.Join("','", _aliases)}'";
}
}
......@@ -344,7 +344,7 @@ public ReferencedAssemblyIdentity(AssemblyIdentity identity, MetadataReference m
: ((object)modulesBuilder == null ? 0 : modulesBuilder.Count);
int reversedIndex = count - 1 - referenceMap[i].Index;
referenceMap[i] = new ResolvedReference(reversedIndex, referenceMap[i].Kind, GetAliases(references[i], aliasMap));
referenceMap[i] = new ResolvedReference(reversedIndex, referenceMap[i].Kind, GetAndFreeAliases(references[i], aliasMap));
}
}
......@@ -371,10 +371,10 @@ public ReferencedAssemblyIdentity(AssemblyIdentity identity, MetadataReference m
return ImmutableArray.CreateRange(referenceMap);
}
private static ImmutableArray<string> GetAliases(MetadataReference reference, Dictionary<MetadataReference, ArrayBuilder<string>> aliasMap)
private static ImmutableArray<string> GetAndFreeAliases(MetadataReference reference, Dictionary<MetadataReference, ArrayBuilder<string>> aliasMapOpt)
{
ArrayBuilder<string> aliases;
if (aliasMap != null && aliasMap.TryGetValue(reference, out aliases))
if (aliasMapOpt != null && aliasMapOpt.TryGetValue(reference, out aliases))
{
return aliases.ToImmutableAndFree();
}
......@@ -576,7 +576,7 @@ private static void AddModule(PEModule module, int referenceIndex, ResolvedRefer
// Returns null if an assembly of an equivalent identity has not been added previously, otherwise returns the reference that added it.
// - Both assembly names are strong (have keys) and are either equal or FX unified
// - Both assembly names are weak (no keys) and have the same simple name.
private MetadataReference TryAddAssembly(AssemblyIdentity identity, MetadataReference boundReference, DiagnosticBag diagnostics, Location location,
private MetadataReference TryAddAssembly(AssemblyIdentity identity, MetadataReference boundReference, DiagnosticBag diagnosticsOpt, Location location,
ref Dictionary<string, List<ReferencedAssemblyIdentity>> referencesBySimpleName)
{
if (referencesBySimpleName == null)
......@@ -643,7 +643,7 @@ private static void AddModule(PEModule module, int referenceIndex, ResolvedRefer
// BREAKING CHANGE in VB: we report an error for both languages
// Multiple assemblies with equivalent identity have been imported: '{0}' and '{1}'. Remove one of the duplicate references.
MessageProvider.ReportDuplicateMetadataReferenceStrong(diagnostics, location, boundReference, identity, equivalent.MetadataReference, equivalent.Identity);
MessageProvider.ReportDuplicateMetadataReferenceStrong(diagnosticsOpt, location, boundReference, identity, equivalent.MetadataReference, equivalent.Identity);
}
// If the versions match exactly we ignore duplicates w/o reporting errors while
// Dev12 C# reports:
......@@ -664,7 +664,7 @@ private static void AddModule(PEModule module, int referenceIndex, ResolvedRefer
if (identity != equivalent.Identity)
{
MessageProvider.ReportDuplicateMetadataReferenceWeak(diagnostics, location, boundReference, identity, equivalent.MetadataReference, equivalent.Identity);
MessageProvider.ReportDuplicateMetadataReferenceWeak(diagnosticsOpt, location, boundReference, identity, equivalent.MetadataReference, equivalent.Identity);
}
}
......@@ -840,6 +840,9 @@ private static PortableExecutableReference ResolveReferenceDirective(string refe
}
continue;
default:
throw ExceptionUtilities.Unreachable;
}
}
......@@ -909,28 +912,5 @@ private static PortableExecutableReference ResolveReferenceDirective(string refe
return new AssemblyReferenceBinding(reference);
}
private static bool IsBetterVersionMatch(AssemblyIdentity reference, ImmutableArray<AssemblyData> definitions, AssemblyReferenceBinding previousBinding, AssemblyReferenceBinding newBinding)
{
Debug.Assert(newBinding.IsBound);
// Previous binding failed or new binding is an exact match
if (!previousBinding.IsBound || newBinding.VersionDifference == 0)
{
return true;
}
if (previousBinding.VersionDifference != newBinding.VersionDifference)
{
// lesser than reference version is worst than higher than reference version
return previousBinding.VersionDifference < 0;
}
var previousVersion = definitions[previousBinding.DefinitionIndex].Identity.Version;
var newVersion = definitions[newBinding.DefinitionIndex].Identity.Version;
// closer version is better:
return (newBinding.VersionDifference > 0) ? newVersion < previousVersion : newVersion > previousVersion;
}
}
}
......@@ -383,16 +383,14 @@ internal bool IsBound
protected static void BuildReferencedAssembliesAndModulesMaps(
ImmutableArray<MetadataReference> references,
ImmutableArray<ResolvedReference> referenceMap,
IReadOnlyList<MetadataReference> implicitlyResolvedReferences,
int referencedAssemblyCount,
int referencedModuleCount,
out Dictionary<MetadataReference, int> referencedAssembliesMap,
out Dictionary<MetadataReference, int> referencedModulesMap,
out ImmutableArray<ImmutableArray<string>> aliasesOfReferencedAssemblies)
{
referencedAssembliesMap = new Dictionary<MetadataReference, int>(referenceMap.Length + implicitlyResolvedReferences.Count);
referencedAssembliesMap = new Dictionary<MetadataReference, int>(referenceMap.Length);
referencedModulesMap = new Dictionary<MetadataReference, int>(referencedModuleCount);
var aliasesOfReferencedAssembliesBuilder = ArrayBuilder<ImmutableArray<string>>.GetInstance(referencedAssemblyCount);
var aliasesOfReferencedAssembliesBuilder = ArrayBuilder<ImmutableArray<string>>.GetInstance(referenceMap.Length - referencedModuleCount);
for (int i = 0; i < referenceMap.Length; i++)
{
......@@ -418,22 +416,6 @@ internal bool IsBound
}
}
for (int i = 0; i < implicitlyResolvedReferences.Count; i++)
{
var assemblyIndex = referencedAssemblyCount + i;
Debug.Assert(aliasesOfReferencedAssembliesBuilder.Count == assemblyIndex);
referencedAssembliesMap.Add(implicitlyResolvedReferences[i], assemblyIndex);
// Use aliases specified on the reference returned by the missing assembly resolver.
// Unlike explicitly given references, we don't apply de-duplication logic on references
// returned by the resolver. This is because we already have an assembly identity
// (rather than an opaque reference string or a preexisting metadata reference)
// and we don't ask the resolver to resolve an identity that matches identities
// we have already resolved. Hence there are no opportunities for reference duplication.
aliasesOfReferencedAssembliesBuilder.Add(implicitlyResolvedReferences[i].Properties.Aliases);
}
aliasesOfReferencedAssemblies = aliasesOfReferencedAssembliesBuilder.ToImmutableAndFree();
}
......
......@@ -256,7 +256,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Friend Function CreateAndSetSourceAssemblyFullBind(compilation As VisualBasicCompilation) As Boolean
Dim resolutionDiagnostics = DiagnosticBag.GetInstance()
Dim implicitlyResolvedReferences = ArrayBuilder(Of MetadataReference).GetInstance()
Try
Dim boundReferenceDirectiveMap As IDictionary(Of String, MetadataReference) = Nothing
......@@ -275,21 +274,29 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
resolutionDiagnostics)
Dim assemblyBeingBuiltData As New AssemblyDataForAssemblyBeingBuilt(New AssemblyIdentity(name:=SimpleAssemblyName), referencedAssemblies, modules)
Dim allAssemblyData = referencedAssemblies.Insert(0, assemblyBeingBuiltData)
Dim explicitAssemblyData = referencedAssemblies.Insert(0, assemblyBeingBuiltData)
' Let's bind all the references and resolve missing one (if resolver is available)
Dim corLibraryIndex As Integer
Dim hasCircularReference As Boolean
Dim bindingResult() As BoundInputAssembly = Bind(allAssemblyData,
Dim implicitlyResolvedReferences As ImmutableArray(Of MetadataReference) = Nothing
Dim implicitlyResolvedReferenceMap As ImmutableArray(Of ResolvedReference) = Nothing
Dim allAssemblyData As ImmutableArray(Of AssemblyData) = Nothing
Dim bindingResult() As BoundInputAssembly = Bind(explicitAssemblyData,
compilation.Options.MetadataReferenceResolver,
compilation.Options.MetadataImportOptions,
allAssemblyData,
implicitlyResolvedReferences,
implicitlyResolvedReferenceMap,
resolutionDiagnostics,
hasCircularReference,
corLibraryIndex)
Debug.Assert(bindingResult.Length = allAssemblyData.Length)
referenceMap = referenceMap.AddRange(implicitlyResolvedReferenceMap)
Dim referencedAssembliesMap As Dictionary(Of MetadataReference, Integer) = Nothing
Dim referencedModulesMap As Dictionary(Of MetadataReference, Integer) = Nothing
Dim aliasesOfReferencedAssemblies As ImmutableArray(Of ImmutableArray(Of String)) = Nothing
......@@ -297,8 +304,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
BuildReferencedAssembliesAndModulesMaps(
references,
referenceMap,
implicitlyResolvedReferences,
referencedAssemblies.Length,
modules.Length,
referencedAssembliesMap,
referencedModulesMap,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册