diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index 5239c3f322a55971e371b9a72f7a2feed55a76eb..d982de2fe6c479eccd68a214e106fd6e223eaf68 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -8999,7 +8999,7 @@ internal class CSharpResources { } /// - /// Looks up a localized string similar to Type '{0}' is forwarded to multiple assemblies: '{1}' and '{2}'. + /// Looks up a localized string similar to Module '{0}' in assembly '{1}' is forwarding the type '{2}' to multiple assemblies: '{3}' and '{4}'.. /// internal static string ERR_TypeForwardedToMultipleAssemblies { get { diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 4e649deaa2495ff8956285d64c461a2ebebc470f..483d5e4d443141ea85a9825b38444d09b51a3ecb 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -5009,6 +5009,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Attributes are not allowed on local function parameters or type parameters - Type '{0}' is forwarded to multiple assemblies: '{1}' and '{2}' + Module '{0}' in assembly '{1}' is forwarding the type '{2}' to multiple assemblies: '{3}' and '{4}'. \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/Symbols/AssemblySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AssemblySymbol.cs index bd29e48ab7eb078719bcaa303527ac92aad8a477..88d1858d1769e77b99d250e8037766333f692fe0 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AssemblySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AssemblySymbol.cs @@ -370,6 +370,12 @@ internal ErrorTypeSymbol CreateCycleInTypeForwarderErrorTypeSymbol(ref MetadataT return new MissingMetadataTypeSymbol.TopLevelWithCustomErrorInfo(this.Modules[0], ref emittedName, diagnosticInfo); } + internal ErrorTypeSymbol CreateMultipleForwardingErrorTypeSymbol(ref MetadataTypeName emittedName, ModuleSymbol forwardingModule, AssemblySymbol destination1, AssemblySymbol destination2) + { + var diagnosticInfo = new CSDiagnosticInfo(ErrorCode.ERR_TypeForwardedToMultipleAssemblies, forwardingModule, this, emittedName.FullName, destination1, destination2); + return new MissingMetadataTypeSymbol.TopLevelWithCustomErrorInfo(forwardingModule, ref emittedName, diagnosticInfo); + } + /// /// Lookup declaration for predefined CorLib type in this Assembly. /// diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEAssemblySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEAssemblySymbol.cs index 88832a79669546a3904f0a3f5834f35fc8de0087..661b6ed9b8806393afd5fc0d29afeab196525613 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEAssemblySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEAssemblySymbol.cs @@ -157,13 +157,8 @@ internal override NamedTypeSymbol TryLookupForwardedMetadataTypeWithCycleDetecti { if ((object)secondSymbol != null) { - var forwardingErrorInfo = new DiagnosticInfo( - MessageProvider.Instance, - (int)ErrorCode.ERR_TypeForwardedToMultipleAssemblies, - emittedName.FullName, - firstSymbol.Name, - secondSymbol.Name); - return new MissingMetadataTypeSymbol.TopLevelWithCustomErrorInfo(PrimaryModule, ref emittedName, forwardingErrorInfo); + // Report the main module as that is the only one checked. clr does not honor type forwarders in non-primary modules. + return CreateMultipleForwardingErrorTypeSymbol(ref emittedName, this.PrimaryModule, firstSymbol, secondSymbol); } // Don't bother to check the forwarded-to assembly if we've already seen it. diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEModuleSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEModuleSymbol.cs index a2ec27722fe1b3c46c2c25c4016f7269a094a192..c55e723db6a8f12e08425445b86ca2a71b8d006e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEModuleSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEModuleSymbol.cs @@ -653,9 +653,19 @@ internal NamedTypeSymbol LookupTopLevelMetadataType(ref MetadataTypeName emitted string matchedName; (int firstIndex, int secondIndex) = this.Module.GetAssemblyRefsForForwardedType(fullName.FullName, ignoreCase: false, matchedName: out matchedName); - var firstSymbol = firstIndex < 0 ? null : GetReferencedAssemblySymbol(firstIndex); - var secondSymbol = secondIndex < 0 ? null : GetReferencedAssemblySymbol(secondIndex); + if (firstIndex < 0) + { + return (null, null); + } + + AssemblySymbol firstSymbol = GetReferencedAssemblySymbol(firstIndex); + if (secondIndex < 0) + { + return (firstSymbol, null); + } + + AssemblySymbol secondSymbol = GetReferencedAssemblySymbol(secondIndex); return (firstSymbol, secondSymbol); } @@ -663,13 +673,9 @@ internal IEnumerable GetForwardedTypes() { foreach (KeyValuePair forwarder in Module.GetForwardedTypes()) { - if (forwarder.Value.FirstIndex < 0) - { - continue; - } - var name = MetadataTypeName.FromFullName(forwarder.Key); + Debug.Assert(forwarder.Value.FirstIndex >= 0, "First index should never be negative"); AssemblySymbol firstSymbol = this.GetReferencedAssemblySymbol(forwarder.Value.FirstIndex); Debug.Assert((object)firstSymbol != null, "Invalid indexes (out of bound) are discarded during reading metadata in PEModule.EnsureForwardTypeToAssemblyMap()"); @@ -678,8 +684,7 @@ internal IEnumerable GetForwardedTypes() var secondSymbol = this.GetReferencedAssemblySymbol(forwarder.Value.SecondIndex); Debug.Assert((object)secondSymbol != null, "Invalid indexes (out of bound) are discarded during reading metadata in PEModule.EnsureForwardTypeToAssemblyMap()"); - var forwardingErrorInfo = new DiagnosticInfo(MessageProvider.Instance, (int)ErrorCode.ERR_TypeForwardedToMultipleAssemblies, forwarder.Key, firstSymbol.Name, secondSymbol.Name); - yield return new MissingMetadataTypeSymbol.TopLevelWithCustomErrorInfo(this, ref name, forwardingErrorInfo); + yield return ContainingAssembly.CreateMultipleForwardingErrorTypeSymbol(ref name, this, firstSymbol, secondSymbol); } else { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs index ca7dc03c93f7398bd792ae6b47b3f5b51a53a90e..4cc0f8a9bea23d9ba604684ef5570a6b11c75dfa 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs @@ -2589,13 +2589,7 @@ internal override NamedTypeSymbol TryLookupForwardedMetadataTypeWithCycleDetecti { if ((object)secondSymbol != null) { - var forwardingErrorInfo = new DiagnosticInfo( - MessageProvider.Instance, - (int)ErrorCode.ERR_TypeForwardedToMultipleAssemblies, - emittedName.FullName, - firstSymbol.Name, - secondSymbol.Name); - return new MissingMetadataTypeSymbol.TopLevelWithCustomErrorInfo(SourceModule, ref emittedName, forwardingErrorInfo); + return CreateMultipleForwardingErrorTypeSymbol(ref emittedName, peModuleSymbol, firstSymbol, secondSymbol); } // Don't bother to check the forwarded-to assembly if we've already seen it. diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs index a6cfd9473e0bfc4bff5edff5fe72df05100de3ed..ece16dd97c7cef8b587e63b836bfb7d51a386bdc 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs @@ -19508,6 +19508,7 @@ .assembly Forwarder { .ver 1:0:0:0 } +.module ForwarderModule.dll .class extern forwarder Destination.TestClass { .assembly extern Destination1 @@ -19519,9 +19520,9 @@ .assembly Forwarder var compilation = CreateCompilationWithCustomILSource(userCode, forwardingIL, appendDefaultHeader: false); compilation.VerifyDiagnostics( - // (8,29): error CS8206: Type 'Destination.TestClass' is forwarded to multiple assemblies: 'Destination1' and 'Destination2' + // (8,29): error CS8206: Module 'ForwarderModule.dll' in assembly 'Forwarder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is forwarding the type 'Destination.TestClass' to multiple assemblies: 'Destination1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' and 'Destination2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. // new Destination.TestClass(); - Diagnostic(ErrorCode.ERR_TypeForwardedToMultipleAssemblies, "TestClass").WithArguments("Destination.TestClass", "Destination1", "Destination2").WithLocation(8, 29), + Diagnostic(ErrorCode.ERR_TypeForwardedToMultipleAssemblies, "TestClass").WithArguments("ForwarderModule.dll", "Forwarder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "Destination.TestClass", "Destination1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "Destination2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(8, 29), // (8,29): error CS0234: The type or namespace name 'TestClass' does not exist in the namespace 'Destination' (are you missing an assembly reference?) // new Destination.TestClass(); Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "TestClass").WithArguments("TestClass", "Destination").WithLocation(8, 29)); @@ -19542,9 +19543,8 @@ public static void Main() } }"; var forwardingIL = @" -.assembly Forwarder -{ -} +.assembly Forwarder { } +.module ForwarderModule.dll .assembly extern Destination1 { } .assembly extern Destination2 { } .assembly extern Destination3 { } @@ -19573,9 +19573,9 @@ .assembly Forwarder var compilation = CreateCompilationWithCustomILSource(userCode, forwardingIL, appendDefaultHeader: false); compilation.VerifyDiagnostics( - // (8,29): error CS8206: Type 'Destination.TestClass' is forwarded to multiple assemblies: 'Destination1' and 'Destination2' + // (8,29): error CS8206: Module 'ForwarderModule.dll' in assembly 'Forwarder, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is forwarding the type 'Destination.TestClass' to multiple assemblies: 'Destination1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' and 'Destination2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // new Destination.TestClass(); - Diagnostic(ErrorCode.ERR_TypeForwardedToMultipleAssemblies, "TestClass").WithArguments("Destination.TestClass", "Destination1", "Destination2").WithLocation(8, 29), + Diagnostic(ErrorCode.ERR_TypeForwardedToMultipleAssemblies, "TestClass").WithArguments("ForwarderModule.dll", "Forwarder, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "Destination.TestClass", "Destination1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "Destination2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(8, 29), // (8,29): error CS0234: The type or namespace name 'TestClass' does not exist in the namespace 'Destination' (are you missing an assembly reference?) // new Destination.TestClass(); Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "TestClass").WithArguments("TestClass", "Destination").WithLocation(8, 29)); @@ -19631,6 +19631,7 @@ .assembly C { .ver 0:0:0:0 } +.module CModule.dll .assembly extern D1 { } .assembly extern D2 { } .class extern forwarder C.ClassC @@ -19645,9 +19646,9 @@ .assembly C var referenceC2 = CompileIL(codeC2, appendDefaultHeader: false); CreateCompilationWithMscorlib(codeA, references: new MetadataReference[] { referenceB, referenceC2 }, assemblyName: "A").VerifyDiagnostics( - // (10,13): error CS8206: Type 'C.ClassC' is forwarded to multiple assemblies: 'D1' and 'D2' + // (10,13): error CS8206: Module 'CModule.dll' in assembly 'C, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is forwarding the type 'C.ClassC' to multiple assemblies: 'D1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' and 'D2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // ClassB.MethodB(null); - Diagnostic(ErrorCode.ERR_TypeForwardedToMultipleAssemblies, "ClassB.MethodB").WithArguments("C.ClassC", "D1", "D2").WithLocation(10, 13)); + Diagnostic(ErrorCode.ERR_TypeForwardedToMultipleAssemblies, "ClassB.MethodB").WithArguments("CModule.dll", "C, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "C.ClassC", "D1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "D2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")); } [Fact, WorkItem(16484, "https://github.com/dotnet/roslyn/issues/16484")] @@ -19718,9 +19719,10 @@ .assembly C } [Fact, WorkItem(16484, "https://github.com/dotnet/roslyn/issues/16484")] - public void AddingReferenceToModuleWithMultipleForwardersToDifferentAssembliesShouldErrorOut() + public void CompilingModuleWithMultipleForwardersToDifferentAssembliesShouldErrorOut() { var ilSource = @" +.module ForwarderModule.dll .assembly extern D1 { } .assembly extern D2 { } .class extern forwarder Testspace.TestType @@ -19732,19 +19734,14 @@ public void AddingReferenceToModuleWithMultipleForwardersToDifferentAssembliesSh .assembly extern D2 }"; - ImmutableArray ilBytes; - ImmutableArray pdbBytes; - EmitILToArray(ilSource, appendDefaultHeader: false, includePdb: false, assemblyBytes: out ilBytes, pdbBytes: out pdbBytes); - - var ilModule = ModuleMetadata.CreateFromImage(ilBytes).GetReference(); - - CreateCompilationWithMscorlib(string.Empty, references: new MetadataReference[] { ilModule }).VerifyDiagnostics( - // error CS8206: Type 'Testspace.TestType' is forwarded to multiple assemblies: 'D1' and 'D2' - Diagnostic(ErrorCode.ERR_TypeForwardedToMultipleAssemblies).WithArguments("Testspace.TestType", "D1", "D2").WithLocation(1, 1)); + var ilModule = GetILModuleReference(ilSource, appendDefaultHeader: false); + CreateCompilationWithMscorlib(string.Empty, references: new MetadataReference[] { ilModule }, assemblyName: "Forwarder").VerifyDiagnostics( + // error CS8206: Module 'ForwarderModule.dll' in assembly 'Forwarder, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is forwarding the type 'Testspace.TestType' to multiple assemblies: 'D1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' and 'D2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + Diagnostic(ErrorCode.ERR_TypeForwardedToMultipleAssemblies).WithArguments("ForwarderModule.dll", "Forwarder, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "Testspace.TestType", "D1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "D2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 1)); } [Fact, WorkItem(16484, "https://github.com/dotnet/roslyn/issues/16484")] - public void AddingReferenceToModuleWithMultipleForwardersToTheSameAssemblyShouldNotProduceMultipleForwardingErrors() + public void CompilingModuleWithMultipleForwardersToTheSameAssemblyShouldNotProduceMultipleForwardingErrors() { var ilSource = @" .assembly extern D1 { } @@ -19757,12 +19754,7 @@ public void AddingReferenceToModuleWithMultipleForwardersToTheSameAssemblyShould .assembly extern D1 }"; - ImmutableArray ilBytes; - ImmutableArray pdbBytes; - EmitILToArray(ilSource, appendDefaultHeader: false, includePdb: false, assemblyBytes: out ilBytes, pdbBytes: out pdbBytes); - - var ilModule = ModuleMetadata.CreateFromImage(ilBytes).GetReference(); - + var ilModule = GetILModuleReference(ilSource, appendDefaultHeader: false); CreateCompilationWithMscorlib(string.Empty, references: new MetadataReference[] { ilModule }).VerifyDiagnostics( // error CS0012: The type 'TestType' is defined in an assembly that is not referenced. You must add a reference to assembly 'D1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. Diagnostic(ErrorCode.ERR_NoTypeDef).WithArguments("Testspace.TestType", "D1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 1)); diff --git a/src/Compilers/Core/Portable/MetadataReader/PEModule.cs b/src/Compilers/Core/Portable/MetadataReader/PEModule.cs index 1cc6c4ce22aed4b6743a434e4f8548c03c1b741e..d3335b8bd4b16e5bf98e4470f4c3599386b498c6 100644 --- a/src/Compilers/Core/Portable/MetadataReader/PEModule.cs +++ b/src/Compilers/Core/Portable/MetadataReader/PEModule.cs @@ -2901,7 +2901,7 @@ private void EnsureForwardTypeToAssemblyMap() continue; } - if (referencedAssemblyIndex >= this.ReferencedAssemblies.Length) + if (referencedAssemblyIndex < 0 || referencedAssemblyIndex >= this.ReferencedAssemblies.Length) { continue; } @@ -2921,6 +2921,8 @@ private void EnsureForwardTypeToAssemblyMap() if (typesToAssemblyIndexMap.TryGetValue(name, out indices)) { + Debug.Assert(indices.FirstIndex >= 0, "Not allowed to store a negative (non-existent) index in typesToAssemblyIndexMap"); + // Store it only if it was not a duplicate if (indices.FirstIndex != referencedAssemblyIndex && indices.SecondIndex < 0) { diff --git a/src/Compilers/VisualBasic/Portable/Binding/Binder_Symbols.vb b/src/Compilers/VisualBasic/Portable/Binding/Binder_Symbols.vb index 5dc8623c78f28cf82dc60bcae151709c6f5d929d..5bda397b04ce56de1f6a1d6c5c84d3dc48866cb9 100644 --- a/src/Compilers/VisualBasic/Portable/Binding/Binder_Symbols.vb +++ b/src/Compilers/VisualBasic/Portable/Binding/Binder_Symbols.vb @@ -511,9 +511,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Next If forwardedType IsNot Nothing Then - If Not reportedAnError And forwardedType.IsErrorType Then + If Not reportedAnError AndAlso forwardedType.IsErrorType Then Dim errorInfo = DirectCast(forwardedType, ErrorTypeSymbol).ErrorInfo - + If errorInfo.Code = ERRID.ERR_TypeFwdCycle2 Then Debug.Assert(forwardedType.ContainingAssembly IsNot Nothing, "How did we find a cycle if there is no forwarding?") Binder.ReportDiagnostic(diagBag, typeSyntax, ERRID.ERR_TypeFwdCycle2, fullName, forwardedType.ContainingAssembly) diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AssemblySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AssemblySymbol.vb index a66ac607e0930d49c11aa5200d3ae10398a8d51f..4e6b582d0230e48a59003c5158c9be991c554345 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AssemblySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AssemblySymbol.vb @@ -301,6 +301,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return New MissingMetadataTypeSymbol.TopLevelWithCustomErrorInfo(Me.Modules(0), emittedName, diagInfo) End Function + Friend Function CreateMultipleForwardingErrorTypeSymbol(ByRef emittedName As MetadataTypeName, forwardingModule As ModuleSymbol, destination1 As AssemblySymbol, destination2 As AssemblySymbol) As ErrorTypeSymbol + Dim diagnosticInfo = New DiagnosticInfo(MessageProvider.Instance, ERRID.ERR_TypeForwardedToMultipleAssemblies, forwardingModule, Me, emittedName.FullName, destination1, destination2) + Return New MissingMetadataTypeSymbol.TopLevelWithCustomErrorInfo(forwardingModule, emittedName, diagnosticInfo) + End Function + ''' ''' Lookup declaration for predefined CorLib type in this Assembly. Only valid if this ''' assembly is the Cor Library diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEAssemblySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEAssemblySymbol.vb index 541c9b97c711931881cb57c421588f52cae2bf4c..b3bf7c94372365432a67dd49bfb57572ab4d5db3 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEAssemblySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEAssemblySymbol.vb @@ -166,17 +166,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Dim matchedName As String = Nothing Dim forwardedToAssemblies = LookupAssembliesForForwardedMetadataType(emittedName, ignoreCase, matchedName) - If DirectCast(forwardedToAssemblies.FirstSymbol, Object) IsNot Nothing - If DirectCast(forwardedToAssemblies.SecondSymbol, Object) IsNot Nothing - Dim forwardingErrorInfo = New DiagnosticInfo( - MessageProvider.Instance, - ERRID.ERR_TypeForwardedToMultipleAssemblies, - emittedName.FullName, - forwardedToAssemblies.FirstSymbol.Name, - forwardedToAssemblies.SecondSymbol.Name) - Return new MissingMetadataTypeSymbol.TopLevelWithCustomErrorInfo(PrimaryModule, emittedName, forwardingErrorInfo) + If forwardedToAssemblies.FirstSymbol IsNot Nothing Then + If forwardedToAssemblies.SecondSymbol IsNot Nothing Then + ' Report the main module as that Is the only one checked. clr does Not honor type forwarders in non-primary modules. + Return CreateMultipleForwardingErrorTypeSymbol(emittedName, PrimaryModule, forwardedToAssemblies.FirstSymbol, forwardedToAssemblies.SecondSymbol) End If - + ' Don't bother to check the forwarded-to assembly if we've already seen it. If visitedAssemblies IsNot Nothing AndAlso visitedAssemblies.Contains(forwardedToAssemblies.FirstSymbol) Then Return CreateCycleInTypeForwarderErrorTypeSymbol(emittedName) diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEModuleSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEModuleSymbol.vb index 61b303e5b19e0b2180c4690ecaeaf08de40c2021..8fde0cfa7d82f933c3648165d7137fbc68469c10 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEModuleSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEModuleSymbol.vb @@ -434,30 +434,34 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE ''' Friend Function GetAssembliesForForwardedType(ByRef fullName As MetadataTypeName, ignoreCase As Boolean, ByRef matchedName As String) As (FirstSymbol As AssemblySymbol, SecondSymbol As AssemblySymbol) Dim indices = Me.Module.GetAssemblyRefsForForwardedType(fullName.FullName, ignoreCase, matchedName) - - Dim firstSymbol = If(indices.FirstIndex < 0, Nothing, GetReferencedAssemblySymbol(indices.FirstIndex)) - Dim secondSymbol = If(indices.SecondIndex < 0, Nothing, GetReferencedAssemblySymbol(indices.SecondIndex)) - return (firstSymbol, secondSymbol) + If indices.FirstIndex < 0 Then + Return (Nothing, Nothing) + End If + + Dim firstSymbol = GetReferencedAssemblySymbol(indices.FirstIndex) + + If indices.SecondIndex < 0 Then + Return (firstSymbol, Nothing) + End If + + Dim secondSymbol = GetReferencedAssemblySymbol(indices.SecondIndex) + Return (firstSymbol, secondSymbol) End Function Friend Iterator Function GetForwardedTypes() As IEnumerable(Of NamedTypeSymbol) For Each forwarder As KeyValuePair(Of String, (FirstIndex As Integer, SecondIndex As Integer)) In Me.Module.GetForwardedTypes() - If forwarder.Value.FirstIndex < 0 Then - Continue For - End If - Dim name = MetadataTypeName.FromFullName(forwarder.Key) + Debug.Assert(forwarder.Value.FirstIndex >= 0, "First index should never be negative") Dim firstSymbol = GetReferencedAssemblySymbol(forwarder.Value.FirstIndex) - Debug.Assert(DirectCast(firstSymbol, Object) IsNot Nothing, "Invalid indexes (out of bound) are discarded during reading metadata in PEModule.EnsureForwardTypeToAssemblyMap()") + Debug.Assert(firstSymbol IsNot Nothing, "Invalid indexes (out of bound) are discarded during reading metadata in PEModule.EnsureForwardTypeToAssemblyMap()") If forwarder.Value.SecondIndex >= 0 Then Dim secondSymbol = GetReferencedAssemblySymbol(forwarder.Value.SecondIndex) - Debug.Assert(DirectCast(secondSymbol, Object) IsNot Nothing, "Invalid indexes (out of bound) are discarded during reading metadata in PEModule.EnsureForwardTypeToAssemblyMap()") + Debug.Assert(secondSymbol IsNot Nothing, "Invalid indexes (out of bound) are discarded during reading metadata in PEModule.EnsureForwardTypeToAssemblyMap()") - Dim forwardingErrorInfo = New DiagnosticInfo(MessageProvider.Instance, ERRID.ERR_TypeForwardedToMultipleAssemblies, forwarder.Key, firstSymbol.Name, secondSymbol.Name) - Yield New MissingMetadataTypeSymbol.TopLevelWithCustomErrorInfo(Me, name, forwardingErrorInfo) + Yield ContainingAssembly.CreateMultipleForwardingErrorTypeSymbol(name, Me, firstSymbol, secondSymbol) Else Yield firstSymbol.LookupTopLevelMetadataType(name, digThroughForwardedTypes:= true) End If diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb index 5da4b34a181f7c54e466fb6a2c64001ef3c70f30..0c84acfd3c7b17dd654b7a24cbab41ff9be8f5eb 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb @@ -1695,10 +1695,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Dim peModuleSymbol = DirectCast(_modules(i), PEModuleSymbol) Dim forwardedToAssemblies = peModuleSymbol.GetAssembliesForForwardedType(emittedName, ignoreCase, matchedName) - If DirectCast(forwardedToAssemblies.FirstSymbol, Object) IsNot Nothing Then - If DirectCast(forwardedToAssemblies.SecondSymbol, Object) IsNot Nothing Then - Dim forwardingErrorInfo = New DiagnosticInfo(MessageProvider.Instance, ERRID.ERR_TypeForwardedToMultipleAssemblies, emittedName.FullName, forwardedToAssemblies.FirstSymbol.Name, forwardedToAssemblies.SecondSymbol.Name) - Return New MissingMetadataTypeSymbol.TopLevelWithCustomErrorInfo(SourceModule, emittedName, forwardingErrorInfo) + If forwardedToAssemblies.FirstSymbol IsNot Nothing Then + If forwardedToAssemblies.SecondSymbol IsNot Nothing Then + Return CreateMultipleForwardingErrorTypeSymbol(emittedName, peModuleSymbol, forwardedToAssemblies.FirstSymbol, forwardedToAssemblies.SecondSymbol) End If ' Don't bother to check the forwarded-to assembly if we've already seen it. diff --git a/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb b/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb index 8e87be3612007f447e7c1ad7b4a103c8f93d7291..95e05ace3b068d3e09dbbf8443607ba6ed2a13bc 100644 --- a/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb +++ b/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb @@ -10686,7 +10686,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Property ''' - ''' Looks up a localized string similar to Type '{0}' is forwarded to multiple assemblies: '{1}' and '{2}'. + ''' Looks up a localized string similar to Module '{0}' in assembly '{1}' is forwarding the type '{2}' to multiple assemblies: '{3}' and '{4}'.. ''' Friend ReadOnly Property ERR_TypeForwardedToMultipleAssemblies() As String Get diff --git a/src/Compilers/VisualBasic/Portable/VBResources.resx b/src/Compilers/VisualBasic/Portable/VBResources.resx index eec85b18d6fe87a371d9c1574687c527c335028e..feba468a29079e3c69387911bba0965ed31206ad 100644 --- a/src/Compilers/VisualBasic/Portable/VBResources.resx +++ b/src/Compilers/VisualBasic/Portable/VBResources.resx @@ -5462,6 +5462,6 @@ Invalid assembly name: {0} - Type '{0}' is forwarded to multiple assemblies: '{1}' and '{2}' + Module '{0}' in assembly '{1}' is forwarding the type '{2}' to multiple assemblies: '{3}' and '{4}'. - + \ No newline at end of file diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/SymbolErrorTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/SymbolErrorTests.vb index 52c08f01bd927d0fbf47890bf0e4b24778a5b543..44b48af0a5b1b20c87cda019802a0835a3400b34 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/SymbolErrorTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/SymbolErrorTests.vb @@ -23844,6 +23844,7 @@ End Namespace { .ver 1:0:0:0 } +.module ForwarderModule.dll .class extern forwarder Destination.TestClass { .assembly extern Destination1 @@ -23853,12 +23854,12 @@ End Namespace .assembly extern Destination2 }" Dim compilation = CreateCompilationWithCustomILSource(userCode, forwardingIL, appendDefaultHeader:= False) - + CompilationUtils.AssertTheseDiagnostics(compilation, ) @@ -23885,6 +23886,7 @@ End Namespace .assembly Forwarder { } +.module ForwarderModule.dll .assembly extern Destination1 { } .assembly extern Destination2 { } .assembly extern Destination3 { } @@ -23912,12 +23914,12 @@ End Namespace }" Dim compilation = CreateCompilationWithCustomILSource(userCode, forwardingIL, appendDefaultHeader:= False) - + CompilationUtils.AssertTheseDiagnostics(compilation, ) @@ -23984,6 +23986,7 @@ End Namespace" { .ver 0:0:0:0 } +.module CModule.dll .assembly extern D1 { } .assembly extern D2 { } .class extern forwarder C.ClassC @@ -24004,7 +24007,7 @@ End Namespace" assemblyName:= "A") CompilationUtils.AssertTheseDiagnostics(compilation, ) @@ -24092,8 +24095,9 @@ BC30652: Reference required to assembly 'D, Version=0.0.0.0, Culture=neutral, Pu - Public Sub AddingReferenceToModuleWithMultipleForwardersToDifferentAssembliesShouldErrorOut() + Public Sub CompilingModuleWithMultipleForwardersToDifferentAssembliesShouldErrorOut() Dim ilSource = " +.module ForwarderModule.dll .assembly extern D1 { } .assembly extern D2 { } .class extern forwarder Testspace.TestType @@ -24105,22 +24109,21 @@ BC30652: Reference required to assembly 'D, Version=0.0.0.0, Culture=neutral, Pu .assembly extern D2 }" - Dim ilBytes As ImmutableArray(Of Byte) = Nothing - Dim pdbBytes As ImmutableArray(Of Byte) = Nothing - EmitILToArray(ilSource, appendDefaultHeader:=False, includePdb:=False, assemblyBytes:=ilBytes, pdbBytes:=pdbBytes) - - Dim ilModule = ModuleMetadata.CreateFromImage(ilBytes).GetReference() - - Dim compilation = CreateCompilationWithMscorlib(String.Empty, references:={ilModule}, options:=New VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary)) + Dim ilModule = GetILModuleReference(ilSource, appendDefaultHeader:=False) + Dim compilation = CreateCompilationWithMscorlib( + source:=String.Empty, + references:={ilModule}, + options:=New VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary), + assemblyName:="Forwarder") CompilationUtils.AssertTheseDiagnostics(compilation, ) End Sub - - Public Sub AddingReferenceToModuleWithMultipleForwardersToTheSameAssemblyShouldNotProduceMultipleForwardingErrors() + + Public Sub CompilingModuleWithMultipleForwardersToTheSameAssemblyShouldNotProduceMultipleForwardingErrors() Dim ilSource = " .assembly extern D1 { } .class extern forwarder Testspace.TestType @@ -24132,12 +24135,7 @@ BC37208: Type 'Testspace.TestType' is forwarded to multiple assemblies: 'D1' and .assembly extern D1 }" - Dim ilBytes As ImmutableArray(Of Byte) = Nothing - Dim pdbBytes As ImmutableArray(Of Byte) = Nothing - EmitILToArray(ilSource, appendDefaultHeader:=False, includePdb:=False, assemblyBytes:=ilBytes, pdbBytes:=pdbBytes) - - Dim ilModule = ModuleMetadata.CreateFromImage(ilBytes).GetReference() - + Dim ilModule = GetILModuleReference(ilSource, appendDefaultHeader:=False) Dim compilation = CreateCompilationWithMscorlib(String.Empty, references:={ilModule}, options:=New VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary)) CompilationUtils.AssertTheseDiagnostics(compilation, assemblyBytes; + ImmutableArray pdbBytes; + EmitILToArray(ilSource, appendDefaultHeader, includePdb: false, assemblyBytes: out assemblyBytes, pdbBytes: out pdbBytes); + return ModuleMetadata.CreateFromImage(assemblyBytes).GetReference(); + } + #endregion #region Compilation Creation Helpers