提交 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 @@ ...@@ -8,11 +8,11 @@
using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
using Microsoft.CodeAnalysis.CSharp.Symbols.Retargeting;
using Roslyn.Utilities; using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp namespace Microsoft.CodeAnalysis.CSharp
{ {
using Symbols.Retargeting;
using MetadataOrDiagnostic = System.Object; using MetadataOrDiagnostic = System.Object;
public partial class CSharpCompilation public partial class CSharpCompilation
...@@ -307,7 +307,6 @@ private void InitializeAssemblyReuseData(AssemblySymbol assemblySymbol, Immutabl ...@@ -307,7 +307,6 @@ private void InitializeAssemblyReuseData(AssemblySymbol assemblySymbol, Immutabl
private bool CreateAndSetSourceAssemblyFullBind(CSharpCompilation compilation) private bool CreateAndSetSourceAssemblyFullBind(CSharpCompilation compilation)
{ {
var resolutionDiagnostics = DiagnosticBag.GetInstance(); var resolutionDiagnostics = DiagnosticBag.GetInstance();
var implicitlyResolvedReferences = ArrayBuilder<MetadataReference>.GetInstance();
try try
{ {
...@@ -327,29 +326,36 @@ private bool CreateAndSetSourceAssemblyFullBind(CSharpCompilation compilation) ...@@ -327,29 +326,36 @@ private bool CreateAndSetSourceAssemblyFullBind(CSharpCompilation compilation)
resolutionDiagnostics); resolutionDiagnostics);
var assemblyBeingBuiltData = new AssemblyDataForAssemblyBeingBuilt(new AssemblyIdentity(name: SimpleAssemblyName), referencedAssemblies, modules); 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) // Let's bind all the references and resolve missing one (if resolver is available)
bool hasCircularReference; bool hasCircularReference;
int corLibraryIndex; int corLibraryIndex;
ImmutableArray<MetadataReference> implicitlyResolvedReferences;
ImmutableArray<ResolvedReference> implicitlyResolvedReferenceMap;
ImmutableArray<AssemblyData> allAssemblyData;
BoundInputAssembly[] bindingResult = Bind( BoundInputAssembly[] bindingResult = Bind(
ref allAssemblyData, explicitAssemblyData,
compilation.Options.MetadataReferenceResolver, compilation.Options.MetadataReferenceResolver,
compilation.Options.MetadataImportOptions, compilation.Options.MetadataImportOptions,
implicitlyResolvedReferences, out allAssemblyData,
out implicitlyResolvedReferences,
out implicitlyResolvedReferenceMap,
resolutionDiagnostics, resolutionDiagnostics,
out hasCircularReference, out hasCircularReference,
out corLibraryIndex); out corLibraryIndex);
Debug.Assert(bindingResult.Length == allAssemblyData.Length); Debug.Assert(bindingResult.Length == allAssemblyData.Length);
references = references.AddRange(implicitlyResolvedReferences);
referenceMap = referenceMap.AddRange(implicitlyResolvedReferenceMap);
Dictionary<MetadataReference, int> referencedAssembliesMap, referencedModulesMap; Dictionary<MetadataReference, int> referencedAssembliesMap, referencedModulesMap;
ImmutableArray<ImmutableArray<string>> aliasesOfReferencedAssemblies; ImmutableArray<ImmutableArray<string>> aliasesOfReferencedAssemblies;
BuildReferencedAssembliesAndModulesMaps( BuildReferencedAssembliesAndModulesMaps(
references, references,
referenceMap, referenceMap,
implicitlyResolvedReferences,
referencedAssemblies.Length,
modules.Length, modules.Length,
out referencedAssembliesMap, out referencedAssembliesMap,
out referencedModulesMap, out referencedModulesMap,
...@@ -394,12 +400,15 @@ private bool CreateAndSetSourceAssemblyFullBind(CSharpCompilation compilation) ...@@ -394,12 +400,15 @@ private bool CreateAndSetSourceAssemblyFullBind(CSharpCompilation compilation)
// This should be done after we created/found all AssemblySymbols // This should be done after we created/found all AssemblySymbols
Dictionary<AssemblyIdentity, MissingAssemblySymbol> missingAssemblies = null; Dictionary<AssemblyIdentity, MissingAssemblySymbol> missingAssemblies = null;
// -1 for assembly being built:
int totalReferencedAssemblyCount = allAssemblyData.Length - 1;
// Setup bound references for newly created SourceAssemblySymbol // Setup bound references for newly created SourceAssemblySymbol
ImmutableArray<ModuleReferences<AssemblySymbol>> moduleReferences; ImmutableArray<ModuleReferences<AssemblySymbol>> moduleReferences;
SetupReferencesForSourceAssembly( SetupReferencesForSourceAssembly(
allAssemblyData,
assemblySymbol, assemblySymbol,
modules, modules,
totalReferencedAssemblyCount,
bindingResult, bindingResult,
ref missingAssemblies, ref missingAssemblies,
out moduleReferences); out moduleReferences);
...@@ -461,7 +470,6 @@ private bool CreateAndSetSourceAssemblyFullBind(CSharpCompilation compilation) ...@@ -461,7 +470,6 @@ private bool CreateAndSetSourceAssemblyFullBind(CSharpCompilation compilation)
finally finally
{ {
resolutionDiagnostics.Free(); resolutionDiagnostics.Free();
implicitlyResolvedReferences.Free();
} }
} }
...@@ -678,9 +686,9 @@ private static void UpdateSymbolCacheNoLock(List<int> newSymbols, ImmutableArray ...@@ -678,9 +686,9 @@ private static void UpdateSymbolCacheNoLock(List<int> newSymbols, ImmutableArray
} }
private static void SetupReferencesForSourceAssembly( private static void SetupReferencesForSourceAssembly(
ImmutableArray<AssemblyData> allAssemblyData,
SourceAssemblySymbol sourceAssembly, SourceAssemblySymbol sourceAssembly,
ImmutableArray<PEModule> modules, ImmutableArray<PEModule> modules,
int totalReferencedAssemblyCount,
BoundInputAssembly[] bindingResult, BoundInputAssembly[] bindingResult,
ref Dictionary<AssemblyIdentity, MissingAssemblySymbol> missingAssemblies, ref Dictionary<AssemblyIdentity, MissingAssemblySymbol> missingAssemblies,
out ImmutableArray<ModuleReferences<AssemblySymbol>> moduleReferences) out ImmutableArray<ModuleReferences<AssemblySymbol>> moduleReferences)
...@@ -693,8 +701,7 @@ private static void UpdateSymbolCacheNoLock(List<int> newSymbols, ImmutableArray ...@@ -693,8 +701,7 @@ private static void UpdateSymbolCacheNoLock(List<int> newSymbols, ImmutableArray
int refsUsed = 0; int refsUsed = 0;
for (int moduleIndex = 0; moduleIndex < moduleSymbols.Length; moduleIndex++) for (int moduleIndex = 0; moduleIndex < moduleSymbols.Length; moduleIndex++)
{ {
// -1 for assembly being built int refsCount = (moduleIndex == 0) ? totalReferencedAssemblyCount : modules[moduleIndex - 1].ReferencedAssemblies.Length;
int refsCount = (moduleIndex == 0) ? (allAssemblyData.Length - 1) : modules[moduleIndex - 1].ReferencedAssemblies.Length;
var identities = new AssemblyIdentity[refsCount]; var identities = new AssemblyIdentity[refsCount];
var symbols = new AssemblySymbol[refsCount]; var symbols = new AssemblySymbol[refsCount];
...@@ -731,7 +738,7 @@ private static void UpdateSymbolCacheNoLock(List<int> newSymbols, ImmutableArray ...@@ -731,7 +738,7 @@ private static void UpdateSymbolCacheNoLock(List<int> newSymbols, ImmutableArray
refsUsed += refsCount; refsUsed += refsCount;
} }
moduleReferences = moduleReferencesBuilder.AsImmutableOrEmpty(); moduleReferences = moduleReferencesBuilder.ToImmutableOrEmptyAndFree();
} }
private static AssemblySymbol GetAssemblyDefinitionSymbol( private static AssemblySymbol GetAssemblyDefinitionSymbol(
......
...@@ -2178,7 +2178,7 @@ public void AsymmetricUnification() ...@@ -2178,7 +2178,7 @@ public void AsymmetricUnification()
private class TestMissingMetadataReferenceResolver : MetadataReferenceResolver private class TestMissingMetadataReferenceResolver : MetadataReferenceResolver
{ {
private readonly Dictionary<string, MetadataReference> _map; private readonly Dictionary<string, MetadataReference> _map;
public readonly List<AssemblyIdentity> ResolvedIdentities = new List<AssemblyIdentity>(); public readonly List<AssemblyIdentity> ResolutionAttempts = new List<AssemblyIdentity>();
public TestMissingMetadataReferenceResolver(Dictionary<string, MetadataReference> map) public TestMissingMetadataReferenceResolver(Dictionary<string, MetadataReference> map)
{ {
...@@ -2187,7 +2187,7 @@ public TestMissingMetadataReferenceResolver(Dictionary<string, MetadataReference ...@@ -2187,7 +2187,7 @@ public TestMissingMetadataReferenceResolver(Dictionary<string, MetadataReference
public override PortableExecutableReference ResolveMissingAssembly(AssemblyIdentity identity) public override PortableExecutableReference ResolveMissingAssembly(AssemblyIdentity identity)
{ {
ResolvedIdentities.Add(identity); ResolutionAttempts.Add(identity);
MetadataReference reference; MetadataReference reference;
string nameAndVersion = identity.Name + (identity.Version != AssemblyIdentity.NullVersion ? $", {identity.Version}" : ""); string nameAndVersion = identity.Name + (identity.Version != AssemblyIdentity.NullVersion ? $", {identity.Version}" : "");
...@@ -2241,6 +2241,98 @@ public class C : A ...@@ -2241,6 +2241,98 @@ public class C : A
c.VerifyEmitDiagnostics(); c.VerifyEmitDiagnostics();
} }
[Fact]
public void MissingAssemblyResolution_AliasesMerge()
{
// c - a -> "b, V1" resolved to "b, V3" with alias X
// - d -> "b, V2" resolved to "b, V3" with alias Y
var b1Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public class B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference();
var b2Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""2.0.0.0"")] public class B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference();
var b3Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""3.0.0.0"")] public class B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference();
var aRef = CreateCompilationWithMscorlib("public class A : B { }", new[] { b1Ref }, assemblyName: "A").EmitToImageReference();
var dRef = CreateCompilationWithMscorlib("public class D : B { }", new[] { b2Ref }, assemblyName: "D").EmitToImageReference();
var b3RefX = b3Ref.WithAliases(ImmutableArray.Create("X"));
var b3RefY = b3Ref.WithAliases(ImmutableArray.Create("Y"));
var c = CreateCompilationWithMscorlib(@"
extern alias X;
extern alias Y;
public class C : A
{
X::B F() => new Y::B();
}
", new[] { aRef, dRef },
TestOptions.ReleaseDll.WithMetadataReferenceResolver(new TestMissingMetadataReferenceResolver(new Dictionary<string, MetadataReference>
{
{ "B, 1.0.0.0", b3RefX },
{ "B, 2.0.0.0", b3RefY },
})));
c.VerifyEmitDiagnostics(
// (5,18): warning CS1701: Assuming assembly reference
// 'B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' used by 'A' matches identity
// 'B, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' of 'B', you may need to supply runtime policy
Diagnostic(ErrorCode.WRN_UnifyReferenceMajMin, "A").WithArguments(
"B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", "A",
"B, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", "B"));
Assert.Equal("B", ((AssemblySymbol)c.GetAssemblyOrModuleSymbol(b3RefY)).Name);
Assert.Null(c.GetAssemblyOrModuleSymbol(b3RefX));
}
[Fact]
public void MissingAssemblyResolution_WeakIdentities1()
{
// c - a -> "b,v1,PKT=null"
// - d -> "b,v2,PKT=null"
var b1Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public interface B { }", assemblyName: "B").EmitToImageReference();
var b2Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""2.0.0.0"")] public interface B { }", assemblyName: "B").EmitToImageReference();
var b3Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""3.0.0.0"")] public interface B { }", assemblyName: "B").EmitToImageReference();
var b4Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""4.0.0.0"")] public interface B { }", assemblyName: "B").EmitToImageReference();
var aRef = CreateCompilationWithMscorlib(@"public interface A : B { }", new[] { b1Ref }, assemblyName: "A").EmitToImageReference();
var dRef = CreateCompilationWithMscorlib(@"public interface D : B { }", new[] { b2Ref }, assemblyName: "D").EmitToImageReference();
var c = CreateCompilationWithMscorlib(@"public interface C : A, D { }", new[] { aRef, dRef },
TestOptions.ReleaseDll.WithMetadataReferenceResolver(new TestMissingMetadataReferenceResolver(new Dictionary<string, MetadataReference>
{
{ "B, 1.0.0.0", b1Ref },
{ "B, 2.0.0.0", b2Ref },
})));
c.VerifyEmitDiagnostics(
// error CS1704: An assembly with the same simple name 'B' has already been imported. Try removing one of the references (e.g. 'B') or sign them to enable side-by-side.
Diagnostic(ErrorCode.ERR_DuplicateImportSimple).WithArguments("B", "B"));
}
[Fact]
public void MissingAssemblyResolution_WeakIdentities2()
{
// c - a -> "b,v1,PKT=null"
// - d -> "b,v2,PKT=null"
var b1Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public interface B { }", assemblyName: "B").EmitToImageReference();
var b2Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""2.0.0.0"")] public interface B { }", assemblyName: "B").EmitToImageReference();
var b3Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""3.0.0.0"")] public interface B { }", assemblyName: "B").EmitToImageReference();
var b4Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""4.0.0.0"")] public interface B { }", assemblyName: "B").EmitToImageReference();
var aRef = CreateCompilationWithMscorlib(@"public interface A : B { }", new[] { b1Ref }, assemblyName: "A").EmitToImageReference();
var dRef = CreateCompilationWithMscorlib(@"public interface D : B { }", new[] { b2Ref }, assemblyName: "D").EmitToImageReference();
var c = CreateCompilationWithMscorlib(@"public interface C : A, D { }", new[] { aRef, dRef },
TestOptions.ReleaseDll.WithMetadataReferenceResolver(new TestMissingMetadataReferenceResolver(new Dictionary<string, MetadataReference>
{
{ "B, 1.0.0.0", b3Ref },
{ "B, 2.0.0.0", b4Ref },
})));
c.VerifyEmitDiagnostics(
// error CS1704: An assembly with the same simple name 'B' has already been imported. Try removing one of the references (e.g. 'B') or sign them to enable side-by-side.
Diagnostic(ErrorCode.ERR_DuplicateImportSimple).WithArguments("B", "B"));
}
[Fact] [Fact]
public void MissingAssemblyResolution_None() public void MissingAssemblyResolution_None()
{ {
...@@ -2256,7 +2348,53 @@ public void MissingAssemblyResolution_None() ...@@ -2256,7 +2348,53 @@ public void MissingAssemblyResolution_None()
c.VerifyDiagnostics(); c.VerifyDiagnostics();
Assert.Equal(0, resolver.ResolvedIdentities.Count); Assert.Equal(0, resolver.ResolutionAttempts.Count);
}
[Fact]
public void MissingAssemblyResolution_ActualMissing()
{
// c - a -> d
var dRef = CreateCompilationWithMscorlib("public interface D { }", assemblyName: "D").EmitToImageReference();
var aRef = CreateCompilationWithMscorlib("public interface A : D { }", new[] { dRef }, assemblyName: "A").ToMetadataReference();
var resolver = new TestMissingMetadataReferenceResolver(new Dictionary<string, MetadataReference>());
var c = CreateCompilationWithMscorlib("public interface C : A { }", new[] { aRef },
TestOptions.ReleaseDll.WithMetadataReferenceResolver(resolver));
c.VerifyDiagnostics(
// (1,18): error CS0012: The type 'D' is defined in an assembly that is not referenced. You must add a reference to assembly 'D, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
Diagnostic(ErrorCode.ERR_NoTypeDef, "C").WithArguments("D", "D, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"));
Assert.Equal(1, resolver.ResolutionAttempts.Count);
}
/// <summary>
/// Ignore assemblies returned by the resolver that don't match the reference identity.
/// </summary>
[Fact]
public void MissingAssemblyResolution_MissingDueToResolutionMismatch()
{
// c - a -> b
var bRef = CreateCompilationWithMscorlib("public interface D { }", assemblyName: "B").EmitToImageReference();
var aRef = CreateCompilationWithMscorlib("public interface A : D { }", new[] { bRef }, assemblyName: "A").ToMetadataReference();
var eRef = CreateCompilationWithMscorlib("public interface E { }", assemblyName: "E").ToMetadataReference();
var resolver = new TestMissingMetadataReferenceResolver(new Dictionary<string, MetadataReference>
{
{ "B, 1.0.0.0", eRef },
});
var c = CreateCompilationWithMscorlib(@"public interface C : A { }", new[] { aRef },
TestOptions.ReleaseDll.WithMetadataReferenceResolver(resolver));
c.VerifyDiagnostics(
// (1,18): error CS0012: The type 'D' is defined in an assembly that is not referenced. You must add a reference to assembly 'B, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
Diagnostic(ErrorCode.ERR_NoTypeDef, "C").WithArguments("D", "B, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"));
Assert.Equal(1, resolver.ResolutionAttempts.Count);
} }
[Fact] [Fact]
...@@ -2279,7 +2417,7 @@ public void MissingAssemblyResolution_Multiple() ...@@ -2279,7 +2417,7 @@ public void MissingAssemblyResolution_Multiple()
c.VerifyEmitDiagnostics(); c.VerifyEmitDiagnostics();
Assert.Equal("D", ((AssemblySymbol)c.GetAssemblyOrModuleSymbol(dRef)).Name); Assert.Equal("D", ((AssemblySymbol)c.GetAssemblyOrModuleSymbol(dRef)).Name);
Assert.Equal(1, resolver.ResolvedIdentities.Count); Assert.Equal(1, resolver.ResolutionAttempts.Count);
} }
[Fact] [Fact]
...@@ -2312,8 +2450,11 @@ public void MissingAssemblyResolution_Modules() ...@@ -2312,8 +2450,11 @@ public void MissingAssemblyResolution_Modules()
Assert.Equal("D", ((AssemblySymbol)c.GetAssemblyOrModuleSymbol(dRef)).Name); Assert.Equal("D", ((AssemblySymbol)c.GetAssemblyOrModuleSymbol(dRef)).Name);
} }
/// <summary>
/// Don't try to resolve AssemblyRefs that already match explicitly specified definition.
/// </summary>
[Fact] [Fact]
public void MissingAssemblyResolution_BetterVersion_Higher_vs_Exact() public void MissingAssemblyResolution_BindingToForExplicitReference1()
{ {
// c - a -> "b,v1" // c - a -> "b,v1"
// - "b,v3" // - "b,v3"
...@@ -2324,160 +2465,244 @@ public void MissingAssemblyResolution_BetterVersion_Higher_vs_Exact() ...@@ -2324,160 +2465,244 @@ public void MissingAssemblyResolution_BetterVersion_Higher_vs_Exact()
var aRef = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public class A : B { }", new[] { b1Ref }, options: s_signedDll, assemblyName: "A").EmitToImageReference(); var aRef = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public class A : B { }", new[] { b1Ref }, options: s_signedDll, assemblyName: "A").EmitToImageReference();
var resolver = new TestMissingMetadataReferenceResolver(new Dictionary<string, MetadataReference>
{
// the compiler asked for v1, but we have v2
{ "B, 1.0.0.0", b2Ref }
});
var c = CreateCompilationWithMscorlib("public class C : A { }", new[] { aRef, b3Ref }, var c = CreateCompilationWithMscorlib("public class C : A { }", new[] { aRef, b3Ref },
s_signedDll.WithMetadataReferenceResolver(new TestMissingMetadataReferenceResolver(new Dictionary<string, MetadataReference> s_signedDll.WithMetadataReferenceResolver(resolver));
{
// the compiler asked for v1, but we have v2
{ "B, 1.0.0.0", b2Ref }
})));
c.VerifyEmitDiagnostics( c.VerifyEmitDiagnostics(
// (1,18): warning CS1701: Assuming assembly reference // (1,18): warning CS1701: Assuming assembly reference
// 'B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' used by 'A' matches identity // 'B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' used by 'A' matches identity
// 'B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' of 'B', you may need to supply runtime policy // 'B, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' of 'B', you may need to supply runtime policy
Diagnostic(ErrorCode.WRN_UnifyReferenceMajMin, "A").WithArguments( Diagnostic(ErrorCode.WRN_UnifyReferenceMajMin, "A").WithArguments(
"B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", "A", "B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", "A",
"B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", "B")); "B, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", "B"));
Assert.Equal(0, resolver.ResolutionAttempts.Count);
Assert.Equal( Assert.Equal(
"B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", "B, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2",
((AssemblySymbol)c.GetAssemblyOrModuleSymbol(b2Ref)).Identity.GetDisplayName()); ((AssemblySymbol)c.GetAssemblyOrModuleSymbol(b3Ref)).Identity.GetDisplayName());
Assert.Null((AssemblySymbol)c.GetAssemblyOrModuleSymbol(b2Ref));
} }
/// <summary>
/// Don't try to resolve AssemblyRefs that already match explicitly specified definition.
/// </summary>
[Fact] [Fact]
public void MissingAssemblyResolution_BetterVersion_Higher_vs_BetterHigher() public void MissingAssemblyResolution_BindingToExplicitReference_WorseVersion()
{ {
// c - a -> "b,v1" // c - a -> d -> "b,v2"
// - "b,v3" // e -> "b,v1"
// // - "b,v1"
var b1Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public class B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference(); var b1Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public interface B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference();
var b2Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""2.0.0.0"")] public class B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference(); var b2Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""2.0.0.0"")] public interface B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference();
var b3Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""3.0.0.0"")] public class B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference();
var aRef = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public class A : B { }", new[] { b1Ref }, options: s_signedDll, assemblyName: "A").EmitToImageReference(); var dRef = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public interface D : B { }", new[] { b2Ref }, options: s_signedDll, assemblyName: "D").EmitToImageReference();
var eRef = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public interface E : B { }", new[] { b1Ref }, options: s_signedDll, assemblyName: "E").EmitToImageReference();
var c = CreateCompilationWithMscorlib("public class C : A { }", new[] { aRef, b3Ref }, var resolverA = new TestMissingMetadataReferenceResolver(new Dictionary<string, MetadataReference>
s_signedDll.WithMetadataReferenceResolver(new TestMissingMetadataReferenceResolver(new Dictionary<string, MetadataReference> {
{ { "B, 2.0.0.0", b2Ref },
{ "B, 1.0.0.0", b2Ref } { "B, 1.0.0.0", b1Ref },
}))); });
var aRef = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public interface A : D, E { }", new[] { dRef, eRef },
s_signedDll.WithMetadataReferenceResolver(resolverA), assemblyName: "A").EmitToImageReference();
Assert.Equal(2, resolverA.ResolutionAttempts.Count);
var resolverC = new TestMissingMetadataReferenceResolver(new Dictionary<string, MetadataReference>
{
{ "D, 1.0.0.0", dRef },
{ "E, 1.0.0.0", eRef },
});
var c = CreateCompilationWithMscorlib("public class C : A { }", new[] { aRef, b1Ref },
s_signedDll.WithMetadataReferenceResolver(resolverC));
c.VerifyEmitDiagnostics( c.VerifyEmitDiagnostics(
// (1,18): warning CS1701: Assuming assembly reference // (1,14): error CS1705: Assembly
// 'B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' used by 'A' matches identity // 'A' with identity 'A, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' uses
// 'B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' of 'B', you may need to supply runtime policy // 'B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' which has a higher version than referenced assembly
Diagnostic(ErrorCode.WRN_UnifyReferenceMajMin, "A").WithArguments( // 'B' with identity 'B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2'
"B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", "A", Diagnostic(ErrorCode.ERR_AssemblyMatchBadVersion, "C").WithArguments(
"B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", "B")); "A", "A, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2",
"B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2",
"B", "B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2"),
// (1,14): error CS1705: Assembly
// 'D' with identity 'D, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' uses
// 'B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' which has a higher version than referenced assembly
// 'B' with identity 'B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2'
Diagnostic(ErrorCode.ERR_AssemblyMatchBadVersion, "C").WithArguments(
"D", "D, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2",
"B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2",
"B", "B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2"));
Assert.Equal(2, resolverC.ResolutionAttempts.Count);
} }
/// <summary>
/// Don't try to resolve AssemblyRefs that already match explicitly specified definition.
/// </summary>
[Fact] [Fact]
public void MissingAssemblyResolution_BetterVersion_Higher_vs_WorseHigher() public void MissingAssemblyResolution_BindingToExplicitReference_BetterVersion()
{ {
// c - a -> "b,v1" // c - a -> d -> "b,v2"
// - "b,v2" // e -> "b,v1"
// // - "b,v2"
var b1Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public class B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference(); var b1Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public interface B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference();
var b2Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""2.0.0.0"")] public class B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference(); var b2Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""2.0.0.0"")] public interface B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference();
var b3Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""3.0.0.0"")] public class B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference();
var aRef = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public class A : B { }", new[] { b1Ref }, options: s_signedDll, assemblyName: "A").EmitToImageReference(); var dRef = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public interface D : B { }", new[] { b2Ref }, options: s_signedDll, assemblyName: "D").EmitToImageReference();
var eRef = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public interface E : B { }", new[] { b1Ref }, options: s_signedDll, assemblyName: "E").EmitToImageReference();
var resolverA = new TestMissingMetadataReferenceResolver(new Dictionary<string, MetadataReference>
{
{ "B, 2.0.0.0", b2Ref },
{ "B, 1.0.0.0", b1Ref },
});
var aRef = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public interface A : D, E { }", new[] { dRef, eRef },
s_signedDll.WithMetadataReferenceResolver(resolverA), assemblyName: "A").EmitToImageReference();
Assert.Equal(2, resolverA.ResolutionAttempts.Count);
var resolverC = new TestMissingMetadataReferenceResolver(new Dictionary<string, MetadataReference>
{
{ "D, 1.0.0.0", dRef },
{ "E, 1.0.0.0", eRef },
});
var c = CreateCompilationWithMscorlib("public class C : A { }", new[] { aRef, b2Ref }, var c = CreateCompilationWithMscorlib("public class C : A { }", new[] { aRef, b2Ref },
s_signedDll.WithMetadataReferenceResolver(new TestMissingMetadataReferenceResolver(new Dictionary<string, MetadataReference> s_signedDll.WithMetadataReferenceResolver(resolverC));
{
{ "B, 1.0.0.0", b3Ref }
})));
c.VerifyEmitDiagnostics( c.VerifyEmitDiagnostics(
// (1,18): warning CS1701: Assuming assembly reference // (1,14): warning CS1701: Assuming assembly reference
// 'B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' used by 'A' matches identity // 'B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' used by
// 'B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' of 'B', you may need to supply runtime policy // 'A' matches identity 'B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' of 'B', you may need to supply runtime policy
Diagnostic(ErrorCode.WRN_UnifyReferenceMajMin, "A").WithArguments( Diagnostic(ErrorCode.WRN_UnifyReferenceMajMin, "C").WithArguments(
"B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", "A", "B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", "A",
"B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", "B"),
// (1,14): warning CS1701: Assuming assembly reference
// 'B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' used by 'E' matches identity
// 'B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' of 'B', you may need to supply runtime policy
Diagnostic(ErrorCode.WRN_UnifyReferenceMajMin, "C").WithArguments(
"B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", "E",
"B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", "B")); "B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", "B"));
Assert.Equal(2, resolverC.ResolutionAttempts.Count);
} }
[Fact] [Fact]
public void MissingAssemblyResolution_BetterVersion_Lower_vs_Exact1() public void MissingAssemblyResolution_BindingToImplicitReference1()
{ {
// c - a -> "b,v2" // c - a -> d -> "b,v2"
// - "b,v1" // e -> "b,v1"
// // "b,v1"
var b1Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public class B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference(); // "b,v2"
var b2Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""2.0.0.0"")] public class B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference(); var b1Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public interface B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference();
var b2Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""2.0.0.0"")] public interface B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference();
var aRef = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public class A : B { }", new[] { b2Ref }, options: s_signedDll, assemblyName: "A").EmitToImageReference(); var dRef = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public interface D : B { }", new[] { b2Ref }, options: s_signedDll, assemblyName: "D").EmitToImageReference();
var eRef = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public interface E : B { }", new[] { b1Ref }, options: s_signedDll, assemblyName: "E").EmitToImageReference();
var c = CreateCompilationWithMscorlib("public class C : A { }", new[] { aRef, b1Ref }, var aRef = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public interface A : D, E { }", new[] { dRef, eRef, b1Ref, b2Ref },
s_signedDll.WithMetadataReferenceResolver(new TestMissingMetadataReferenceResolver(new Dictionary<string, MetadataReference> s_signedDll, assemblyName: "A").EmitToImageReference();
{
{ "B, 2.0.0.0", b2Ref }
})));
c.VerifyEmitDiagnostics(); var resolverC = new TestMissingMetadataReferenceResolver(new Dictionary<string, MetadataReference>
{
{ "D, 1.0.0.0", dRef },
{ "E, 1.0.0.0", eRef },
{ "B, 1.0.0.0", b1Ref },
{ "B, 2.0.0.0", b2Ref },
});
Assert.Equal( var c = CreateCompilationWithMscorlib("public class C : A { }", new[] { aRef },
"B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", s_signedDll.WithMetadataReferenceResolver(resolverC));
((AssemblySymbol)c.GetAssemblyOrModuleSymbol(b2Ref)).Identity.GetDisplayName());
}
[Fact] c.VerifyEmitDiagnostics();
public void MissingAssemblyResolution_BetterVersion_Lower_vs_WorseLower()
{
// c - a -> "b,v3"
// - "b,v2"
//
var b1Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public class B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference();
var b2Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""2.0.0.0"")] public class B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference();
var b3Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""3.0.0.0"")] public class B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference();
var aRef = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public class A : B { }", new[] { b3Ref }, options: s_signedDll, assemblyName: "A").EmitToImageReference(); Assert.Equal(4, resolverC.ResolutionAttempts.Count);
var c = CreateCompilationWithMscorlib("public class C : A { }", new[] { aRef, b2Ref }, Assert.Equal(
s_signedDll.WithMetadataReferenceResolver(new TestMissingMetadataReferenceResolver(new Dictionary<string, MetadataReference> "B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2",
{ ((AssemblySymbol)c.GetAssemblyOrModuleSymbol(b1Ref)).Identity.GetDisplayName());
{ "B, 3.0.0.0", b1Ref }
})));
c.VerifyDiagnostics( Assert.Equal(
// (1,18): error CS1705: Assembly "B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2",
// 'A' with identity 'A, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' ((AssemblySymbol)c.GetAssemblyOrModuleSymbol(b2Ref)).Identity.GetDisplayName());
// uses 'B, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' which has a higher version than referenced assembly
// 'B' with identity 'B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2'
Diagnostic(ErrorCode.ERR_AssemblyMatchBadVersion, "A").WithArguments(
"A", "A, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2",
"B, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2",
"B", "B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2"));
} }
[Fact] [Fact]
public void MissingAssemblyResolution_BetterVersion_Lower_vs_BetterLower() public void MissingAssemblyResolution_BindingToImplicitReference2()
{ {
// c - a -> "b,v3" // c - a -> d -> "b,v2"
// - "b,v1" // e -> "b,v1"
// // "b,v1"
var b1Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public class B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference(); // "b,v2"
var b2Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""2.0.0.0"")] public class B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference(); var b1Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public interface B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference();
var b3Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""3.0.0.0"")] public class B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference(); var b2Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""2.0.0.0"")] public interface B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference();
var b3Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""3.0.0.0"")] public interface B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference();
var aRef = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public class A : B { }", new[] { b3Ref }, options: s_signedDll, assemblyName: "A").EmitToImageReference(); var b4Ref = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""4.0.0.0"")] public interface B { }", options: s_signedDll, assemblyName: "B").EmitToImageReference();
var dRef = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public interface D : B { }", new[] { b2Ref }, options: s_signedDll, assemblyName: "D").EmitToImageReference();
var eRef = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public interface E : B { }", new[] { b1Ref }, options: s_signedDll, assemblyName: "E").EmitToImageReference();
var aRef = CreateCompilationWithMscorlib(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public interface A : D, E { }", new[] { dRef, eRef, b1Ref, b2Ref },
s_signedDll, assemblyName: "A").EmitToImageReference();
var resolverC = new TestMissingMetadataReferenceResolver(new Dictionary<string, MetadataReference>
{
{ "D, 1.0.0.0", dRef },
{ "E, 1.0.0.0", eRef },
{ "B, 1.0.0.0", b3Ref },
{ "B, 2.0.0.0", b4Ref },
});
var c = CreateCompilationWithMscorlib("public class C : A { }", new[] { aRef, b1Ref }, var c = CreateCompilationWithMscorlib("public class C : A { }", new[] { aRef },
s_signedDll.WithMetadataReferenceResolver(new TestMissingMetadataReferenceResolver(new Dictionary<string, MetadataReference> s_signedDll.WithMetadataReferenceResolver(resolverC));
{
{ "B, 3.0.0.0", b2Ref }
})));
c.VerifyDiagnostics( c.VerifyEmitDiagnostics(
// (1,18): error CS1705: Assembly // (1,14): warning CS1701: Assuming assembly reference
// 'A' with identity 'A, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' // 'B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' used by 'A' matches identity
// uses 'B, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' which has a higher version than referenced assembly // 'B, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' of 'B', you may need to supply runtime policy
// 'B' with identity 'B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' Diagnostic(ErrorCode.WRN_UnifyReferenceMajMin, "C").WithArguments(
Diagnostic(ErrorCode.ERR_AssemblyMatchBadVersion, "A").WithArguments( "B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", "A",
"A", "A, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", "B, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", "B"),
"B, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2",
"B", "B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2")); // (1,14): warning CS1701: Assuming assembly reference
// 'B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' used by 'D' matches identity
// 'B, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' of 'B', you may need to supply runtime policy
Diagnostic(ErrorCode.WRN_UnifyReferenceMajMin, "C").WithArguments(
"B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", "D",
"B, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", "B"),
// (1,14): warning CS1701: Assuming assembly reference
// 'B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' used by 'E' matches identity
// 'B, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2' of 'B', you may need to supply runtime policy
Diagnostic(ErrorCode.WRN_UnifyReferenceMajMin, "C").WithArguments(
"B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", "E",
"B, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2", "B"));
Assert.Equal(4, resolverC.ResolutionAttempts.Count);
AssertEx.Equal(new[]
{
"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"A, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2",
"D, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2",
"B, Version=4.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2",
"E, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2",
"B, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2"
}, c.GetBoundReferenceManager().ReferencedAssemblies.Select(a => a.Identity.GetDisplayName()));
} }
} }
} }
...@@ -139,5 +139,10 @@ public static T Peek<T>(this ArrayBuilder<T> builder) ...@@ -139,5 +139,10 @@ public static T Peek<T>(this ArrayBuilder<T> builder)
{ {
return builder[builder.Count - 1]; 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 @@ ...@@ -4,6 +4,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Collections;
using Roslyn.Utilities; using Roslyn.Utilities;
...@@ -21,10 +22,9 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol> ...@@ -21,10 +22,9 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol>
/// build executable for the assembly being built. /// build executable for the assembly being built.
/// </summary> /// </summary>
/// ///
/// <param name="assemblies"> /// <param name="explicitAssemblies">
/// Input: An array of <see cref="AssemblyData"/> objects describing assemblies, for which this method should /// An array of <see cref="AssemblyData"/> objects describing assemblies, for which this method should
/// resolve references and find suitable AssemblySymbols. /// resolve references and find suitable AssemblySymbols. The first slot contains the assembly being built.
/// Output: Updated array with resolved implicitly referenced assemblies appended.
/// </param> /// </param>
/// <param name="resolverOpt"> /// <param name="resolverOpt">
/// Reference resolver used to look up missing assemblies. /// Reference resolver used to look up missing assemblies.
...@@ -32,8 +32,14 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol> ...@@ -32,8 +32,14 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol>
/// <param name="importOptions"> /// <param name="importOptions">
/// Import options applied to implicitly resolved references. /// Import options applied to implicitly resolved references.
/// </param> /// </param>
/// <param name="allAssemblies">
/// Updated array <paramref name="explicitAssemblies"/> with resolved implicitly referenced assemblies appended.
/// </param>
/// <param name="implicitlyResolvedReferences"> /// <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>
/// <param name="resolutionDiagnostics"> /// <param name="resolutionDiagnostics">
/// Any diagnostics reported while resolving missing assemblies. /// Any diagnostics reported while resolving missing assemblies.
...@@ -58,40 +64,51 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol> ...@@ -58,40 +64,51 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol>
/// against provided set of assembly definitions. Essentially, this is an array returned by /// against provided set of assembly definitions. Essentially, this is an array returned by
/// <see cref="AssemblyData.BindAssemblyReferences(ImmutableArray{AssemblyData}, AssemblyIdentityComparer)"/> method. /// <see cref="AssemblyData.BindAssemblyReferences(ImmutableArray{AssemblyData}, AssemblyIdentityComparer)"/> method.
/// </return> /// </return>
internal BoundInputAssembly[] Bind( protected BoundInputAssembly[] Bind(
ref ImmutableArray<AssemblyData> assemblies, ImmutableArray<AssemblyData> explicitAssemblies,
MetadataReferenceResolver resolverOpt, MetadataReferenceResolver resolverOpt,
MetadataImportOptions importOptions, MetadataImportOptions importOptions,
ArrayBuilder<MetadataReference> implicitlyResolvedReferences, out ImmutableArray<AssemblyData> allAssemblies,
out ImmutableArray<MetadataReference> implicitlyResolvedReferences,
out ImmutableArray<ResolvedReference> implicitlyResolvedReferenceMap,
DiagnosticBag resolutionDiagnostics, DiagnosticBag resolutionDiagnostics,
out bool hasCircularReference, out bool hasCircularReference,
out int corLibraryIndex) out int corLibraryIndex)
{ {
Debug.Assert(!assemblies.IsDefault); Debug.Assert(explicitAssemblies[0] is AssemblyDataForAssemblyBeingBuilt);
var referenceBindings = ArrayBuilder<AssemblyReferenceBinding[]>.GetInstance(); var referenceBindings = ArrayBuilder<AssemblyReferenceBinding[]>.GetInstance();
try try
{ {
// Based on assembly identity, for each assembly, // Based on assembly identity, for each assembly,
// bind its references against the other assemblies we have. // 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) 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 // For each assembly, locate AssemblySymbol with similar reference resolution
// What does similar mean? // What does similar mean?
// Similar means: // 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. // 2) The same assembly is used as the COR library.
var boundInputs = new BoundInputAssembly[referenceBindings.Count]; var boundInputs = new BoundInputAssembly[referenceBindings.Count];
...@@ -100,7 +117,7 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol> ...@@ -100,7 +117,7 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol>
boundInputs[i].ReferenceBinding = referenceBindings[i]; 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, // If any assembly from assemblies array refers back to assemblyBeingBuilt,
// we know that we cannot reuse symbols for any assemblies containing NoPia // we know that we cannot reuse symbols for any assemblies containing NoPia
...@@ -109,7 +126,7 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol> ...@@ -109,7 +126,7 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol>
if (!hasCircularReference) if (!hasCircularReference)
{ {
// Deal with assemblies containing NoPia local types. // Deal with assemblies containing NoPia local types.
if (ReuseAssemblySymbolsWithNoPiaLocalTypes(boundInputs, candidateInputAssemblySymbols, assemblies, corLibraryIndex)) if (ReuseAssemblySymbolsWithNoPiaLocalTypes(boundInputs, candidateInputAssemblySymbols, allAssemblies, corLibraryIndex))
{ {
return boundInputs; return boundInputs;
} }
...@@ -118,7 +135,7 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol> ...@@ -118,7 +135,7 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol>
// NoPia shortcut either didn't apply or failed, go through general process // NoPia shortcut either didn't apply or failed, go through general process
// of matching candidates. // of matching candidates.
ReuseAssemblySymbols(boundInputs, candidateInputAssemblySymbols, assemblies, corLibraryIndex); ReuseAssemblySymbols(boundInputs, candidateInputAssemblySymbols, allAssemblies, corLibraryIndex);
return boundInputs; return boundInputs;
} }
...@@ -130,21 +147,29 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol> ...@@ -130,21 +147,29 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol>
private void ResolveAndBindMissingAssemblies( private void ResolveAndBindMissingAssemblies(
ImmutableArray<AssemblyData> explicitAssemblies, ImmutableArray<AssemblyData> explicitAssemblies,
ArrayBuilder<AssemblyReferenceBinding[]> referenceBindings,
ArrayBuilder<MetadataReference> resolvedReferences,
MetadataReferenceResolver resolver, MetadataReferenceResolver resolver,
MetadataImportOptions importOptions, MetadataImportOptions importOptions,
DiagnosticBag resolutionDiagnostics, [In, Out] ArrayBuilder<AssemblyReferenceBinding[]> referenceBindings,
out ImmutableArray<AssemblyData> allAssemblies) 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(); var implicitAssemblies = ArrayBuilder<AssemblyData>.GetInstance();
// tracks identities we already asked the resolver to resolve: // 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 referenceBindingsToProcess = ArrayBuilder<AssemblyReferenceBinding[]>.GetInstance();
var metadataReferencesBuilder = ArrayBuilder<MetadataReference>.GetInstance();
Dictionary<string, List<ReferencedAssemblyIdentity>> lazyResolvedReferencesBySimpleName = null;
Dictionary<MetadataReference, ArrayBuilder<string>> lazyAliasMap = null;
try try
{ {
// collect all missing identities, resolve the assemblies and bind their references against explicit definitions: // collect all missing identities, resolve the assemblies and bind their references against explicit definitions:
...@@ -154,9 +179,13 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol> ...@@ -154,9 +179,13 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol>
{ {
foreach (var binding in referenceBindingsToProcess.Pop()) foreach (var binding in referenceBindingsToProcess.Pop())
{ {
// try resolve a reference if eitehr the binding failed or didn't find an exact match: // only attempt to resolve unbound references (regardless of version difference of the bound ones)
if (binding.IsBound && binding.VersionDifference == 0 || if (binding.IsBound)
resolvedMissingIdentities.Contains(binding.ReferenceIdentity)) {
continue;
}
if (!requestedIdentities.Add(binding.ReferenceIdentity))
{ {
continue; continue;
} }
...@@ -173,8 +202,19 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol> ...@@ -173,8 +202,19 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol>
continue; continue;
} }
resolvedReferences.Add(peReference); // The resolver may return different version than we asked for, so it may also happen that
resolvedMissingIdentities.Add(binding.ReferenceIdentity); // 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); implicitAssemblies.Add(data);
var referenceBinding = data.BindAssemblyReferences(explicitAssemblies, IdentityComparer); var referenceBinding = data.BindAssemblyReferences(explicitAssemblies, IdentityComparer);
...@@ -183,72 +223,102 @@ internal partial class CommonReferenceManager<TCompilation, TAssemblySymbol> ...@@ -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: // NB: includes the assembly being built:
int explicitAssemblyCount = explicitAssemblies.Length; int explicitAssemblyCount = explicitAssemblies.Length;
allAssemblies = explicitAssemblies.AddRange(implicitAssemblies); allAssemblies = explicitAssemblies.AddRange(implicitAssemblies);
// Rebind assembly referenced that were initially missing or were bound to a definitions with a different version for (int bindingsIndex = 0; bindingsIndex < referenceBindings.Count; bindingsIndex++)
// (with more assembly identities available we may have a better match now).
if (implicitAssemblies.Count > 0)
{ {
foreach (var referenceBinding in referenceBindings) var referenceBinding = referenceBindings[bindingsIndex];
for (int i = 0; i < referenceBinding.Length; i++)
{ {
for (int i = 0; i < referenceBinding.Length; i++) var binding = referenceBinding[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.
// We only need to resolve against implicitly resolved assemblies, if (binding.IsBound)
// since we already resolved against explicitly specified ones. {
var newBinding = ResolveReferencedAssembly( continue;
binding.ReferenceIdentity,
allAssemblies,
explicitAssemblyCount,
IdentityComparer);
if (IsBetterVersionMatch(binding.ReferenceIdentity, allAssemblies, binding, newBinding))
{
referenceBinding[i] = newBinding;
}
}
} }
}
UpdateBindingsOfAssemblyBeingBuilt(referenceBindings, explicitAssemblies, implicitAssemblies); // We only need to resolve against implicitly resolved assemblies,
// since we already resolved against explicitly specified ones.
referenceBinding[i] = ResolveReferencedAssembly(
binding.ReferenceIdentity,
allAssemblies,
explicitAssemblyCount,
IdentityComparer);
}
} }
UpdateBindingsOfAssemblyBeingBuilt(referenceBindings, explicitAssemblyCount, implicitAssemblies);
metadataReferences = metadataReferencesBuilder.ToImmutable();
resolvedReferences = ToResolvedAssemblyReferences(metadataReferences, lazyAliasMap, explicitAssemblyCount);
} }
finally finally
{ {
implicitAssemblies.Free(); implicitAssemblies.Free();
resolvedMissingIdentities.Free(); requestedIdentities.Free();
referenceBindingsToProcess.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: // 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): // 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: // add bindings for implicitly resolved assemblies:
for (int i = 0; i < implicitAssemblies.Count; i++) 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: // 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(); referenceBindings[0] = bindingsOfAssemblyBeingBuilt.ToArrayAndFree();
} }
internal AssemblyData ResolveMissingAssembly( internal AssemblyData ResolveMissingAssembly(
AssemblyIdentity identity, AssemblyIdentity referenceIdentity,
PortableExecutableReference peReference, PortableExecutableReference peReference,
MetadataImportOptions importOptions, MetadataImportOptions importOptions,
DiagnosticBag diagnostics) DiagnosticBag diagnostics)
...@@ -268,8 +338,16 @@ private static void UpdateBindingsOfAssemblyBeingBuilt(ArrayBuilder<AssemblyRefe ...@@ -268,8 +338,16 @@ private static void UpdateBindingsOfAssemblyBeingBuilt(ArrayBuilder<AssemblyRefe
return null; 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( return CreateAssemblyDataForFile(
assemblyMetadata.GetAssembly(), assembly,
assemblyMetadata.CachedSymbols, assemblyMetadata.CachedSymbols,
peReference.DocumentationProvider, peReference.DocumentationProvider,
SimpleAssemblyName, SimpleAssemblyName,
......
...@@ -106,7 +106,7 @@ public int Index ...@@ -106,7 +106,7 @@ public int Index
private string GetDebuggerDisplay() 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 ...@@ -344,7 +344,7 @@ public ReferencedAssemblyIdentity(AssemblyIdentity identity, MetadataReference m
: ((object)modulesBuilder == null ? 0 : modulesBuilder.Count); : ((object)modulesBuilder == null ? 0 : modulesBuilder.Count);
int reversedIndex = count - 1 - referenceMap[i].Index; 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 ...@@ -371,10 +371,10 @@ public ReferencedAssemblyIdentity(AssemblyIdentity identity, MetadataReference m
return ImmutableArray.CreateRange(referenceMap); 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; ArrayBuilder<string> aliases;
if (aliasMap != null && aliasMap.TryGetValue(reference, out aliases)) if (aliasMapOpt != null && aliasMapOpt.TryGetValue(reference, out aliases))
{ {
return aliases.ToImmutableAndFree(); return aliases.ToImmutableAndFree();
} }
...@@ -576,7 +576,7 @@ private static void AddModule(PEModule module, int referenceIndex, ResolvedRefer ...@@ -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. // 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 strong (have keys) and are either equal or FX unified
// - Both assembly names are weak (no keys) and have the same simple name. // - 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) ref Dictionary<string, List<ReferencedAssemblyIdentity>> referencesBySimpleName)
{ {
if (referencesBySimpleName == null) if (referencesBySimpleName == null)
...@@ -643,7 +643,7 @@ private static void AddModule(PEModule module, int referenceIndex, ResolvedRefer ...@@ -643,7 +643,7 @@ private static void AddModule(PEModule module, int referenceIndex, ResolvedRefer
// BREAKING CHANGE in VB: we report an error for both languages // 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. // 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 // If the versions match exactly we ignore duplicates w/o reporting errors while
// Dev12 C# reports: // Dev12 C# reports:
...@@ -664,7 +664,7 @@ private static void AddModule(PEModule module, int referenceIndex, ResolvedRefer ...@@ -664,7 +664,7 @@ private static void AddModule(PEModule module, int referenceIndex, ResolvedRefer
if (identity != equivalent.Identity) 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 ...@@ -840,6 +840,9 @@ private static PortableExecutableReference ResolveReferenceDirective(string refe
} }
continue; continue;
default:
throw ExceptionUtilities.Unreachable;
} }
} }
...@@ -909,28 +912,5 @@ private static PortableExecutableReference ResolveReferenceDirective(string refe ...@@ -909,28 +912,5 @@ private static PortableExecutableReference ResolveReferenceDirective(string refe
return new AssemblyReferenceBinding(reference); 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 ...@@ -383,16 +383,14 @@ internal bool IsBound
protected static void BuildReferencedAssembliesAndModulesMaps( protected static void BuildReferencedAssembliesAndModulesMaps(
ImmutableArray<MetadataReference> references, ImmutableArray<MetadataReference> references,
ImmutableArray<ResolvedReference> referenceMap, ImmutableArray<ResolvedReference> referenceMap,
IReadOnlyList<MetadataReference> implicitlyResolvedReferences,
int referencedAssemblyCount,
int referencedModuleCount, int referencedModuleCount,
out Dictionary<MetadataReference, int> referencedAssembliesMap, out Dictionary<MetadataReference, int> referencedAssembliesMap,
out Dictionary<MetadataReference, int> referencedModulesMap, out Dictionary<MetadataReference, int> referencedModulesMap,
out ImmutableArray<ImmutableArray<string>> aliasesOfReferencedAssemblies) 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); 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++) for (int i = 0; i < referenceMap.Length; i++)
{ {
...@@ -418,22 +416,6 @@ internal bool IsBound ...@@ -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(); aliasesOfReferencedAssemblies = aliasesOfReferencedAssembliesBuilder.ToImmutableAndFree();
} }
......
...@@ -256,7 +256,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ...@@ -256,7 +256,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Friend Function CreateAndSetSourceAssemblyFullBind(compilation As VisualBasicCompilation) As Boolean Friend Function CreateAndSetSourceAssemblyFullBind(compilation As VisualBasicCompilation) As Boolean
Dim resolutionDiagnostics = DiagnosticBag.GetInstance() Dim resolutionDiagnostics = DiagnosticBag.GetInstance()
Dim implicitlyResolvedReferences = ArrayBuilder(Of MetadataReference).GetInstance()
Try Try
Dim boundReferenceDirectiveMap As IDictionary(Of String, MetadataReference) = Nothing Dim boundReferenceDirectiveMap As IDictionary(Of String, MetadataReference) = Nothing
...@@ -275,21 +274,29 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ...@@ -275,21 +274,29 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
resolutionDiagnostics) resolutionDiagnostics)
Dim assemblyBeingBuiltData As New AssemblyDataForAssemblyBeingBuilt(New AssemblyIdentity(name:=SimpleAssemblyName), referencedAssemblies, modules) 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) ' Let's bind all the references and resolve missing one (if resolver is available)
Dim corLibraryIndex As Integer Dim corLibraryIndex As Integer
Dim hasCircularReference As Boolean 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.MetadataReferenceResolver,
compilation.Options.MetadataImportOptions, compilation.Options.MetadataImportOptions,
allAssemblyData,
implicitlyResolvedReferences, implicitlyResolvedReferences,
implicitlyResolvedReferenceMap,
resolutionDiagnostics, resolutionDiagnostics,
hasCircularReference, hasCircularReference,
corLibraryIndex) corLibraryIndex)
Debug.Assert(bindingResult.Length = allAssemblyData.Length) Debug.Assert(bindingResult.Length = allAssemblyData.Length)
referenceMap = referenceMap.AddRange(implicitlyResolvedReferenceMap)
Dim referencedAssembliesMap As Dictionary(Of MetadataReference, Integer) = Nothing Dim referencedAssembliesMap As Dictionary(Of MetadataReference, Integer) = Nothing
Dim referencedModulesMap As Dictionary(Of MetadataReference, Integer) = Nothing Dim referencedModulesMap As Dictionary(Of MetadataReference, Integer) = Nothing
Dim aliasesOfReferencedAssemblies As ImmutableArray(Of ImmutableArray(Of String)) = Nothing Dim aliasesOfReferencedAssemblies As ImmutableArray(Of ImmutableArray(Of String)) = Nothing
...@@ -297,8 +304,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ...@@ -297,8 +304,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
BuildReferencedAssembliesAndModulesMaps( BuildReferencedAssembliesAndModulesMaps(
references, references,
referenceMap, referenceMap,
implicitlyResolvedReferences,
referencedAssemblies.Length,
modules.Length, modules.Length,
referencedAssembliesMap, referencedAssembliesMap,
referencedModulesMap, referencedModulesMap,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册