提交 df12a7f3 编写于 作者: J Julien Couvreur

Fix GetHashCode on annotated type arguments

Conflicts:
	src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs
上级 eec064e0
......@@ -1180,6 +1180,16 @@ internal static bool IsPrimitiveRecursiveStruct(this TypeSymbol t)
/// </summary>
internal static int ComputeHashCode(this NamedTypeSymbol type)
{
Debug.Assert(!type.Equals(type.OriginalDefinition, TypeCompareKind.AllIgnoreOptions) || wasConstructedForAnnotations(type));
if (wasConstructedForAnnotations(type))
{
// A type that uses its own type parameters as type arguments was constructed only for the purpose of adding annotations.
// In that case we'll use the hash from the definition.
return type.OriginalDefinition.GetHashCode();
}
int code = type.OriginalDefinition.GetHashCode();
code = Hash.Combine(type.ContainingType, code);
......@@ -1209,6 +1219,28 @@ internal static int ComputeHashCode(this NamedTypeSymbol type)
code++;
}
return code;
static bool wasConstructedForAnnotations(NamedTypeSymbol type)
{
do
{
var typeArguments = type.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics;
var typeParameters = type.OriginalDefinition.TypeParameters;
for (int i = 0; i < typeArguments.Length; i++)
{
if (!typeParameters[i].Equals(typeArguments[i].Type.OriginalDefinition))
{
return false;
}
}
type = type.ContainingType;
}
while (type is object && !type.IsDefinition);
return true;
}
}
/// <summary>
......
......@@ -85180,6 +85180,335 @@ static void Main()
CompileAndVerify(source, targetFramework: TargetFramework.StandardAndCSharp, options: WithNonNullTypesTrue());
}
[Fact]
[WorkItem(30673, "https://github.com/dotnet/roslyn/issues/30673")]
public void TypeSymbolGetHashCode_Annotated()
{
var text = @"
class C<T> where T : class
{
C<T?> M() => throw null!;
}
";
var comp = CreateNullableCompilation(text);
var type = comp.GetMember<NamedTypeSymbol>("C");
Assert.Equal("C<T>", type.ToTestDisplayString(includeNonNullable: true));
Assert.True(type.IsDefinition);
var type2 = comp.GetMember<MethodSymbol>("C.M").ReturnType;
Assert.Equal("C<T?>", type2.ToTestDisplayString(includeNonNullable: true));
Assert.False(type2.IsDefinition);
AssertHashCodesMatch(type, type2);
}
[Fact]
[WorkItem(30673, "https://github.com/dotnet/roslyn/issues/30673")]
public void TypeSymbolGetHashCode_NotAnnotated()
{
var text = @"
class C<T> where T : class
{
C<T> M() => throw null!;
}
";
var comp = CreateNullableCompilation(text);
var type = comp.GetMember<NamedTypeSymbol>("C");
Assert.Equal("C<T>", type.ToTestDisplayString(includeNonNullable: true));
Assert.True(type.IsDefinition);
var type2 = comp.GetMember<MethodSymbol>("C.M").ReturnType;
Assert.Equal("C<T!>", type2.ToTestDisplayString(includeNonNullable: true));
Assert.False(type2.IsDefinition);
AssertHashCodesMatch(type, type2);
}
[Fact]
[WorkItem(30673, "https://github.com/dotnet/roslyn/issues/30673")]
public void TypeSymbolGetHashCode_ContainingType()
{
var text = @"
class C<T> where T : class
{
interface I { }
}
";
var comp = CreateNullableCompilation(text);
var iDefinition = comp.GetMember<NamedTypeSymbol>("C.I");
Assert.Equal("C<T>.I", iDefinition.ToTestDisplayString(includeNonNullable: true));
Assert.True(iDefinition.IsDefinition);
var cDefinition = iDefinition.ContainingType;
Assert.Equal("C<T>", cDefinition.ToTestDisplayString(includeNonNullable: true));
Assert.True(cDefinition.IsDefinition);
var c2 = cDefinition.Construct(ImmutableArray.Create(TypeWithAnnotations.Create(cDefinition.TypeParameters.Single(), NullableAnnotation.NotAnnotated)));
Assert.Equal("C<T!>", c2.ToTestDisplayString(includeNonNullable: true));
Assert.False(c2.IsDefinition);
AssertHashCodesMatch(cDefinition, c2);
var i2 = c2.GetTypeMember("I");
Assert.Equal("C<T!>.I", i2.ToTestDisplayString(includeNonNullable: true));
Assert.False(i2.IsDefinition);
AssertHashCodesMatch(iDefinition, i2);
var c3 = cDefinition.Construct(ImmutableArray.Create(TypeWithAnnotations.Create(cDefinition.TypeParameters.Single(), NullableAnnotation.Annotated)));
Assert.Equal("C<T?>", c3.ToTestDisplayString(includeNonNullable: true));
Assert.False(c3.IsDefinition);
AssertHashCodesMatch(cDefinition, c3);
var i3 = c3.GetTypeMember("I");
Assert.Equal("C<T?>.I", i3.ToTestDisplayString(includeNonNullable: true));
Assert.False(i3.IsDefinition);
AssertHashCodesMatch(iDefinition, i3);
}
[Fact]
[WorkItem(30673, "https://github.com/dotnet/roslyn/issues/30673")]
public void TypeSymbolGetHashCode_ContainingType_GenericNestedType()
{
var text = @"
class C<T> where T : class
{
interface I<U> where U : class { }
}
";
var comp = CreateNullableCompilation(text);
var iDefinition = comp.GetMember<NamedTypeSymbol>("C.I");
Assert.Equal("C<T>.I<U>", iDefinition.ToTestDisplayString(includeNonNullable: true));
Assert.True(iDefinition.IsDefinition);
// Construct from iDefinition with annotated U from iDefinition
var i1 = iDefinition.Construct(ImmutableArray.Create(TypeWithAnnotations.Create(iDefinition.TypeParameters.Single(), NullableAnnotation.Annotated)));
Assert.Equal("C<T>.I<U?>", i1.ToTestDisplayString(includeNonNullable: true));
AssertHashCodesMatch(iDefinition, i1);
var cDefinition = iDefinition.ContainingType;
Assert.Equal("C<T>", cDefinition.ToTestDisplayString(includeNonNullable: true));
Assert.True(cDefinition.IsDefinition);
// Construct from cDefinition with unannotated T from cDefinition
var c2 = cDefinition.Construct(ImmutableArray.Create(TypeWithAnnotations.Create(cDefinition.TypeParameters.Single(), NullableAnnotation.NotAnnotated)));
var i2 = c2.GetTypeMember("I");
Assert.Equal("C<T!>.I<U>", i2.ToTestDisplayString(includeNonNullable: true));
Assert.Same(i2.OriginalDefinition, iDefinition);
AssertHashCodesMatch(i2, iDefinition);
// Construct from i2 with U from iDefinition
var i2a = i2.Construct(iDefinition.TypeParameters.Single());
Assert.Equal("C<T!>.I<U>", i2a.ToTestDisplayString(includeNonNullable: true));
AssertHashCodesMatch(iDefinition, i2a);
// Construct from i2 with annotated U from iDefinition
var i2b = i2.Construct(ImmutableArray.Create(TypeWithAnnotations.Create(iDefinition.TypeParameters.Single(), NullableAnnotation.Annotated)));
Assert.Equal("C<T!>.I<U?>", i2b.ToTestDisplayString(includeNonNullable: true));
AssertHashCodesMatch(iDefinition, i2b);
// Construct from i2 with U from i2
var i2c = i2.Construct(ImmutableArray.Create(TypeWithAnnotations.Create(i2.TypeParameters.Single(), NullableAnnotation.Annotated)));
Assert.Equal("C<T!>.I<U?>", i2c.ToTestDisplayString(includeNonNullable: true));
AssertHashCodesMatch(iDefinition, i2c);
var c3 = cDefinition.Construct(ImmutableArray.Create(TypeWithAnnotations.Create(cDefinition.TypeParameters.Single(), NullableAnnotation.Annotated)));
var i3 = c3.GetTypeMember("I");
Assert.Equal("C<T?>.I<U>", i3.ToTestDisplayString(includeNonNullable: true));
AssertHashCodesMatch(iDefinition, i3);
var i3b = i3.Construct(ImmutableArray.Create(TypeWithAnnotations.Create(i3.TypeParameters.Single(), NullableAnnotation.Annotated)));
Assert.Equal("C<T?>.I<U?>", i3b.ToTestDisplayString(includeNonNullable: true));
AssertHashCodesMatch(iDefinition, i3b);
// Construct from cDefinition with modified T from cDefinition
var modifiers = ImmutableArray.Create(CSharpCustomModifier.CreateOptional(comp.GetSpecialType(SpecialType.System_Object)));
var c4 = cDefinition.Construct(ImmutableArray.Create(TypeWithAnnotations.Create(cDefinition.TypeParameters.Single(), customModifiers: modifiers)));
Assert.Equal("C<T modopt(System.Object)>", c4.ToTestDisplayString());
Assert.False(c4.IsDefinition);
AssertHashCodesMatch(cDefinition, c4);
var i4 = c4.GetTypeMember("I");
Assert.Equal("C<T modopt(System.Object)>.I<U>", i4.ToTestDisplayString());
Assert.Same(i4.OriginalDefinition, iDefinition);
Assert.False(iDefinition.Equals(i4, TypeCompareKind.ConsiderEverything));
Assert.False(iDefinition.Equals(i4, TypeCompareKind.CLRSignatureCompareOptions));
Assert.True(iDefinition.Equals(i4, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds));
Assert.Equal(iDefinition.GetHashCode(), i4.GetHashCode());
}
private static void AssertHashCodesMatch(TypeSymbol c, TypeSymbol c2)
{
Assert.False(c.Equals(c2));
Assert.True(c.Equals(c2, TypeCompareKind.AllIgnoreOptions));
Assert.Equal(c2.GetHashCode(), c.GetHashCode());
}
[Fact]
[WorkItem(35619, "https://github.com/dotnet/roslyn/issues/35619")]
public void ExplicitInterface_UsingOuterDefinition_Simple()
{
var text = @"
class Outer<T>
{
protected internal interface Interface
{
void Method();
}
internal class C : Outer<T>.Interface
{
void Interface.Method()
{
}
}
}
";
var comp = CreateNullableCompilation(text);
comp.VerifyDiagnostics(
// (10,14): warning CS8643: Nullability of reference types in explicit interface specifier doesn't match interface implemented by the type.
// void Interface.Method()
Diagnostic(ErrorCode.WRN_NullabilityMismatchInExplicitlyImplementedInterface, "Interface").WithLocation(10, 14)
);
}
[Fact]
[WorkItem(35619, "https://github.com/dotnet/roslyn/issues/35619")]
public void ExplicitInterface_UsingOuterDefinition()
{
var text = @"
class Outer<T> where T : class
{
internal class Inner<U> where U : class
{
protected internal interface Interface
{
void Method();
}
// The implemented interface is Outer<T!>.Inner<U!>.Interface
internal class Derived6 : Outer<T>.Inner<U>.Interface
{
// The explicit interface is Outer<T>.Inner<U!>.Interface
void Inner<U>.Interface.Method()
{
}
}
}
}
";
CreateCompilation(text, options: WithNonNullTypesTrue()).VerifyDiagnostics(
// (14,18): warning CS8643: Nullability of reference types in explicit interface specifier doesn't match interface implemented by the type.
// void Inner<U>.Interface.Method()
Diagnostic(ErrorCode.WRN_NullabilityMismatchInExplicitlyImplementedInterface, "Inner<U>.Interface").WithLocation(14, 18)
);
}
[Fact]
[WorkItem(35619, "https://github.com/dotnet/roslyn/issues/35619")]
public void ExplicitInterface_WithExplicitOuter()
{
var text = @"
class Outer<T> where T : class
{
internal class Inner<U> where U : class
{
protected internal interface Interface
{
void Method();
}
// The implemented interface is Outer<T!>.Inner<U!>.Interface
internal class Derived6 : Outer<T>.Inner<U>.Interface
{
// The explicit interface is Outer<T!>.Inner<U!>.Interface
void Outer<T>.Inner<U>.Interface.Method()
{
}
}
}
}
";
CreateCompilation(text, options: WithNonNullTypesTrue()).VerifyDiagnostics();
}
[Fact]
[WorkItem(30677, "https://github.com/dotnet/roslyn/issues/30677")]
public void ExplicitInterface_WithExplicitOuter_DisabledT()
{
var text = @"
class Outer<T> where T : class
{
internal class Inner<U> where U : class
{
protected internal interface Interface
{
void Method();
}
// The implemented interface is Outer<T!>.Inner<U!>.Interface
internal class Derived6 : Outer<T>.Inner<U>.Interface
{
// The explicit interface is Outer<T~>.Inner<U!>.Interface
void Outer<
#nullable disable
T
#nullable enable
>.Inner<U>.Interface.Method()
{
}
}
}
}
";
CreateCompilation(text, options: WithNonNullTypesTrue()).VerifyDiagnostics(
// (14,18): warning CS8643: Nullability of reference types in explicit interface specifier doesn't match interface implemented by the type.
// void Outer<
Diagnostic(ErrorCode.WRN_NullabilityMismatchInExplicitlyImplementedInterface, @"Outer<
#nullable disable
T
#nullable enable
>.Inner<U>.Interface").WithLocation(14, 18)
);
}
[Fact]
[WorkItem(30677, "https://github.com/dotnet/roslyn/issues/30677")]
public void ExplicitInterface_WithExplicitOuter_DisabledT_ImplementedInterfaceMatches()
{
var text = @"
class Outer<T> where T : class
{
internal class Inner<U> where U : class
{
protected internal interface Interface
{
void Method();
}
// The implemented interface is Outer<T~>.Inner<U!>.Interface
internal class Derived6 : Inner<U>.Interface
{
// The explicit interface is Outer<T~>.Inner<U!>.Interface
void Outer<
#nullable disable
T
#nullable enable
>.Inner<U>.Interface.Method()
{
}
}
}
}
";
CreateCompilation(text, options: WithNonNullTypesTrue()).VerifyDiagnostics();
}
[Fact]
[WorkItem(30677, "https://github.com/dotnet/roslyn/issues/30677")]
public void TestErrorsImplementingGenericNestedInterfaces_Explicit()
......@@ -85222,22 +85551,19 @@ internal class Derived6 : Outer<T>.Inner<U>.Interface<U, T>
}
";
// https://github.com/dotnet/roslyn/issues/30677, https://github.com/dotnet/roslyn/issues/30673 - The following errors are unexpected:
// (20,22): error CS0540: 'Outer<T>.Inner<U>.Derived4.Derived5.Method<K>(T, U[], List<U>, Dictionary<K, T>)': containing type does not implement interface 'Outer<T>.Inner<U>.Interface<U, T>'
// (30,22): error CS0540: 'Outer<T>.Inner<U>.Derived4.Derived6.Outer<T>.Inner<U>.Interface<U, T>.Method<K>(T, U[], List<U>, Dictionary<T, K>)': containing type does not implement interface 'Outer<T>.Inner<U>.Interface<U, T>'
CreateCompilation(text, options: WithNonNullTypesTrue()).VerifyDiagnostics(
// (14,39): error CS0535: 'Outer<T>.Inner<U>.Derived4.Derived5' does not implement interface member 'Outer<T>.Inner<U>.Interface<U, T>.Method<Z>(T, U[], List<U>, Dictionary<T, Z>)'
// internal class Derived5 : Outer<T>.Inner<U>.Interface<U, T>
Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Outer<T>.Inner<U>.Interface<U, T>").WithArguments("Outer<T>.Inner<U>.Derived4.Derived5", "Outer<T>.Inner<U>.Interface<U, T>.Method<Z>(T, U[], System.Collections.Generic.List<U>, System.Collections.Generic.Dictionary<T, Z>)").WithLocation(14, 39),
// (20,22): error CS0540: 'Outer<T>.Inner<U>.Derived4.Derived5.Method<K>(T, U[], List<U>, Dictionary<K, T>)': containing type does not implement interface 'Outer<T>.Inner<U>.Interface<U, T>'
// (20,22): warning CS8643: Nullability of reference types in explicit interface specifier doesn't match interface implemented by the type.
// void Inner<U>.Interface<U, T>.Method<K>(T a, U[] b, List<U> c, Dictionary<K, T> D)
Diagnostic(ErrorCode.ERR_ClassDoesntImplementInterface, "Inner<U>.Interface<U, T>").WithArguments("Outer<T>.Inner<U>.Derived4.Derived5.Method<K>(T, U[], System.Collections.Generic.List<U>, System.Collections.Generic.Dictionary<K, T>)", "Outer<T>.Inner<U>.Interface<U, T>").WithLocation(20, 22),
// (20,47): error CS0539: 'Outer<T>.Inner<U>.Derived4.Derived5.Method<K>(T, U[], List<U>, Dictionary<K, T>)' in explicit interface declaration is not a member of interface
Diagnostic(ErrorCode.WRN_NullabilityMismatchInExplicitlyImplementedInterface, "Inner<U>.Interface<U, T>").WithLocation(20, 22),
// (20,47): error CS0539: 'Outer<T>.Inner<U>.Derived4.Derived5.Method<K>(T, U[], List<U>, Dictionary<K, T>)' in explicit interface declaration is not found among members of the interface that can be implemented
// void Inner<U>.Interface<U, T>.Method<K>(T a, U[] b, List<U> c, Dictionary<K, T> D)
Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "Method").WithArguments("Outer<T>.Inner<U>.Derived4.Derived5.Method<K>(T, U[], System.Collections.Generic.List<U>, System.Collections.Generic.Dictionary<K, T>)").WithLocation(20, 47),
// (30,22): error CS0540: 'Outer<T>.Inner<U>.Derived4.Derived6.Outer<T>.Inner<U>.Interface<U, T>.Method<K>(T, U[], List<U>, Dictionary<T, K>)': containing type does not implement interface 'Outer<T>.Inner<U>.Interface<U, T>'
// (30,22): warning CS8643: Nullability of reference types in explicit interface specifier doesn't match interface implemented by the type.
// void Inner<U>.Interface<U, T>.Method<K>(T a, U[] b, List<U> c, Dictionary<T, K> D)
Diagnostic(ErrorCode.ERR_ClassDoesntImplementInterface, "Inner<U>.Interface<U, T>").WithArguments("Outer<T>.Inner<U>.Derived4.Derived6.Outer<T>.Inner<U>.Interface<U, T>.Method<K>(T, U[], System.Collections.Generic.List<U>, System.Collections.Generic.Dictionary<T, K>)", "Outer<T>.Inner<U>.Interface<U, T>").WithLocation(30, 22)
Diagnostic(ErrorCode.WRN_NullabilityMismatchInExplicitlyImplementedInterface, "Inner<U>.Interface<U, T>").WithLocation(30, 22)
);
}
......@@ -85270,11 +85596,10 @@ internal class Derived3 : Interface<long, string>
}
";
// https://github.com/dotnet/roslyn/issues/30677, https://github.com/dotnet/roslyn/issues/30673 - Expect no errors
CreateCompilation(source, options: WithNonNullTypesTrue()).VerifyDiagnostics(
// (18,18): error CS0540: 'Outer<T>.Inner<U>.Derived3.Outer<T>.Inner<U>.Interface<long, string>.Method<K>(T, U[], List<long>, Dictionary<string, K>)': containing type does not implement interface 'Outer<T>.Inner<U>.Interface<long, string>'
// (18,18): warning CS8643: Nullability of reference types in explicit interface specifier doesn't match interface implemented by the type.
// void Inner<U>.Interface<long, string>.Method<K>(T a, U[] B, List<long> C, Dictionary<string, K> d)
Diagnostic(ErrorCode.ERR_ClassDoesntImplementInterface, "Inner<U>.Interface<long, string>").WithArguments("Outer<T>.Inner<U>.Derived3.Outer<T>.Inner<U>.Interface<long, string>.Method<K>(T, U[], System.Collections.Generic.List<long>, System.Collections.Generic.Dictionary<string, K>)", "Outer<T>.Inner<U>.Interface<long, string>").WithLocation(18, 18)
Diagnostic(ErrorCode.WRN_NullabilityMismatchInExplicitlyImplementedInterface, "Inner<U>.Interface<long, string>").WithLocation(18, 18)
);
}
......@@ -221,6 +221,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
End Property
Public Overrides Function GetHashCode() As Integer
If Me._substitution.WasConstructedForModifiers() Then
Return OriginalDefinition.GetHashCode()
End If
Dim _hash As Integer = _fullInstanceType.GetHashCode()
_hash = Hash.Combine(ContainingType, _hash)
......
......@@ -491,6 +491,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Public Overrides Function GetHashCode() As Integer
Dim _hash As Integer = OriginalDefinition.GetHashCode()
If Me._substitution.WasConstructedForModifiers() Then
Return _hash
End If
_hash = Hash.Combine(ContainingType, _hash)
' There is a circularity problem here with alpha-renamed type parameters.
......@@ -978,6 +982,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
End Function
Public Overrides Function GetHashCode() As Integer
If Me._substitution.WasConstructedForModifiers() Then
Return OriginalDefinition.GetHashCode()
End If
Dim _hash As Integer = MyBase.GetHashCode()
For Each typeArgument In TypeArgumentsNoUseSiteDiagnostics
......@@ -1201,7 +1209,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Return Me
End Function
End Class
''' <summary>
......
......@@ -904,5 +904,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Return customModifiers
End Function
Public Function WasConstructedForModifiers() As Boolean
For Each pair In _pairs
If Not pair.Key.Equals(pair.Value.Type.OriginalDefinition) Then
Return False
End If
Next
Return If(_parent Is Nothing, True, _parent.WasConstructedForModifiers())
End Function
End Class
End Namespace
......@@ -285,12 +285,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Dim t1IsDefinition = t1.IsDefinition
Dim t2IsDefinition = t2.IsDefinition
If (t1IsDefinition <> t2IsDefinition) AndAlso
Not ((compareKind And TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds) <> 0 AndAlso
(DirectCast(t1, NamedTypeSymbol).HasTypeArgumentsCustomModifiers OrElse DirectCast(t2, NamedTypeSymbol).HasTypeArgumentsCustomModifiers)) Then
Return False
End If
If Not (t1IsDefinition AndAlso t2IsDefinition) Then ' This is a generic instantiation case
If Not t1.OriginalDefinition.Equals(t2.OriginalDefinition) Then
......@@ -303,20 +297,24 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Do
If (compareKind And Global.Microsoft.CodeAnalysis.TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds) = 0 AndAlso
Not HasSameTypeArgumentCustomModifiers(container1, container2) Then
Return False
End If
If Not (container1 Is container1.ConstructedFrom AndAlso container2 Is container2.ConstructedFrom) Then
' No need to compare type arguments on those containers when they didn't add type arguments (that would cause cycles)
Dim args1 As ImmutableArray(Of TypeSymbol) = container1.TypeArgumentsNoUseSiteDiagnostics
Dim args2 As ImmutableArray(Of TypeSymbol) = container2.TypeArgumentsNoUseSiteDiagnostics
If (compareKind And Global.Microsoft.CodeAnalysis.TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds) = 0 AndAlso
Not HasSameTypeArgumentCustomModifiers(container1, container2) Then
For i As Integer = 0 To args1.Length - 1 Step 1
If Not args1(i).IsSameType(args2(i), compareKind) Then
Return False
End If
Next
Dim args1 As ImmutableArray(Of TypeSymbol) = container1.TypeArgumentsNoUseSiteDiagnostics
Dim args2 As ImmutableArray(Of TypeSymbol) = container2.TypeArgumentsNoUseSiteDiagnostics
For i As Integer = 0 To args1.Length - 1 Step 1
If Not args1(i).IsSameType(args2(i), compareKind) Then
Return False
End If
Next
End If
container1 = container1.ContainingType
container2 = container2.ContainingType
......@@ -326,16 +324,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Exit Do
End If
If (container1.IsDefinition <> container2.IsDefinition) AndAlso
Not ((compareKind And TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds) <> 0 AndAlso
(container1.HasTypeArgumentsCustomModifiers OrElse container2.HasTypeArgumentsCustomModifiers)) Then
Return False
End If
Loop
Return True
End If
ElseIf kind = SymbolKind.TypeParameter Then
If Not t1.OriginalDefinition.Equals(t2.OriginalDefinition) Then
Return False ' different definition
End If
Return t1.ContainingType.IsSameType(t2.ContainingType, compareKind)
End If
Return t1.Equals(t2)
......
......@@ -4,6 +4,7 @@ Imports System.Collections.Immutable
Imports Microsoft.CodeAnalysis.Test.Utilities
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Roslyn.Test.Utilities
Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests
......@@ -3782,6 +3783,169 @@ End Interface
Assert.True(i1.IsExplicitDefinitionOfNoPiaLocalType)
End Sub
<WorkItem(30673, "https://github.com/dotnet/roslyn/issues/30673")>
<Fact>
Public Sub TypeSymbolGetHashCode_ContainingType_GenericNestedType()
Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40(
<compilation name="TypeSymbolGetHashCode_ContainingType_GenericNestedType">
<file name="a.vb">
Public Class C(Of T)
Public Interface I(Of U)
End Interface
End Class
</file>
</compilation>)
AssertNoDeclarationDiagnostics(compilation)
Dim modifiers = ImmutableArray.Create(VisualBasicCustomModifier.CreateOptional(compilation.GetSpecialType(SpecialType.System_Object)))
Dim iDefinition = compilation.GetMember(Of NamedTypeSymbol)("C.I")
Assert.Equal("C(Of T).I(Of U)", iDefinition.ToTestDisplayString())
Assert.True(iDefinition.IsDefinition)
' Construct from iDefinition with modified U from iDefinition
Dim modifiedU = ImmutableArray.Create(New TypeWithModifiers(iDefinition.TypeParameters.Single(), modifiers))
Dim i1 = iDefinition.Construct(TypeSubstitution.Create(iDefinition, iDefinition.TypeParameters, modifiedU))
Assert.Equal("C(Of T).I(Of U modopt(System.Object))", i1.ToTestDisplayString())
AssertHashCodesMatch(iDefinition, i1)
Dim cDefinition = iDefinition.ContainingType
Assert.Equal("C(Of T)", cDefinition.ToTestDisplayString())
Assert.True(cDefinition.IsDefinition)
' Construct from cDefinition with modified T from cDefinition
Dim modifiedT = ImmutableArray.Create(New TypeWithModifiers(cDefinition.TypeParameters.Single(), modifiers))
Dim c2 = cDefinition.Construct(TypeSubstitution.Create(cDefinition, cDefinition.TypeParameters, modifiedT))
Dim i2 = c2.GetTypeMember("I")
Assert.Equal("C(Of T modopt(System.Object)).I(Of U)", i2.ToTestDisplayString())
Assert.Same(i2.OriginalDefinition, iDefinition)
AssertHashCodesMatch(iDefinition, i2)
' Construct from i2 with U from iDefinition
Dim i2a = i2.Construct(iDefinition.TypeParameters.Single())
Assert.Equal("C(Of T modopt(System.Object)).I(Of U)", i2a.ToTestDisplayString())
AssertHashCodesMatch(iDefinition, i2a)
' Construct from i2 (reconstructed) with modified U from iDefinition
Dim i2b = iDefinition.Construct(TypeSubstitution.Create(iDefinition,
ImmutableArray.Create(cDefinition.TypeParameters.Single(), iDefinition.TypeParameters.Single()),
ImmutableArray.Create(modifiedT.Single(), modifiedU.Single())))
Assert.Equal("C(Of T modopt(System.Object)).I(Of U modopt(System.Object))", i2b.ToTestDisplayString())
AssertHashCodesMatch(iDefinition, i2b)
' Construct from cDefinition with modified T from cDefinition
Dim c4 = cDefinition.Construct(TypeSubstitution.Create(cDefinition, cDefinition.TypeParameters, modifiedT))
Assert.Equal("C(Of T modopt(System.Object))", c4.ToTestDisplayString())
Assert.False(c4.IsDefinition)
AssertHashCodesMatch(cDefinition, c4)
Dim i4 = c4.GetTypeMember("I")
Assert.Equal("C(Of T modopt(System.Object)).I(Of U)", i4.ToTestDisplayString())
Assert.Same(i4.OriginalDefinition, iDefinition)
AssertHashCodesMatch(iDefinition, i4)
End Sub
<WorkItem(30673, "https://github.com/dotnet/roslyn/issues/30673")>
<Fact>
Public Sub TypeSymbolGetHashCode_ContainingType_GenericNestedType_Nested()
Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40(
<compilation name="TypeSymbolGetHashCode_ContainingType_GenericNestedType">
<file name="a.vb">
Public Class C(Of T)
Public Class C2(Of U)
Public Interface I(Of V)
End Interface
End Class
End Class
</file>
</compilation>)
AssertNoDeclarationDiagnostics(compilation)
Dim modifiers = ImmutableArray.Create(VisualBasicCustomModifier.CreateOptional(compilation.GetSpecialType(SpecialType.System_Object)))
Dim iDefinition = compilation.GetMember(Of NamedTypeSymbol)("C.C2.I")
Assert.Equal("C(Of T).C2(Of U).I(Of V)", iDefinition.ToTestDisplayString())
Assert.True(iDefinition.IsDefinition)
Dim c2Definition = iDefinition.ContainingType
Dim cDefinition = c2Definition.ContainingType
Dim modifiedT = New TypeWithModifiers(cDefinition.TypeParameters.Single(), modifiers)
Dim modifiedU = New TypeWithModifiers(c2Definition.TypeParameters.Single(), modifiers)
Dim modifiedV = New TypeWithModifiers(iDefinition.TypeParameters.Single(), modifiers)
Dim i = iDefinition.Construct(TypeSubstitution.Create(iDefinition,
ImmutableArray.Create(cDefinition.TypeParameters.Single(), c2Definition.TypeParameters.Single(), iDefinition.TypeParameters.Single()),
ImmutableArray.Create(modifiedT, modifiedU, modifiedV)))
Assert.Equal("C(Of T modopt(System.Object)).C2(Of U modopt(System.Object)).I(Of V modopt(System.Object))", i.ToTestDisplayString())
AssertHashCodesMatch(iDefinition, i)
End Sub
<WorkItem(30673, "https://github.com/dotnet/roslyn/issues/30673")>
<Fact>
Public Sub TypeSymbolGetHashCode_SubstitutedErrorType()
Dim missing = CompilationUtils.CreateCompilationWithMscorlib40(
<compilation name="TypeSymbolGetHashCode_SubstitutedErrorType">
<file name="a.vb">
Public Class C(Of T)
Public Class D(Of U)
End Class
End Class
</file>
</compilation>)
AssertNoDeclarationDiagnostics(missing)
Dim reference = CompilationUtils.CreateCompilationWithMscorlib40(
<compilation name="TypeSymbolGetHashCode_SubstitutedErrorType">
<file name="a.vb">
Public Class Reference(Of T, U)
Inherits C(Of T).D(Of U)
End Class
</file>
</compilation>, references:={missing.EmitToImageReference()})
AssertNoDeclarationDiagnostics(reference)
Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40(
<compilation name="TypeSymbolGetHashCode_SubstitutedErrorType">
<file name="a.vb">
Public Class Program(Of V, W)
Inherits Reference(Of V, W)
End Class
</file>
</compilation>, references:={reference.EmitToImageReference()})
compilation.AssertTheseDiagnostics(<errors><![CDATA[
BC31091: Import of type 'C(Of ).D(Of )' from assembly or module 'TypeSymbolGetHashCode_SubstitutedErrorType.dll' failed.
Public Class Program(Of V, W)
~~~~~~~
BC31091: Import of type 'C(Of ).D(Of )' from assembly or module 'TypeSymbolGetHashCode_SubstitutedErrorType.dll' failed.
Inherits Reference(Of V, W)
~~~~~~~~~~~~~~~~~~
]]></errors>)
Dim modifiers = ImmutableArray.Create(VisualBasicCustomModifier.CreateOptional(compilation.GetSpecialType(SpecialType.System_Object)))
Dim programType = compilation.GlobalNamespace.GetTypeMember("Program")
Dim errorType = programType.BaseType.BaseType
Dim definition = errorType.OriginalDefinition
Assert.Equal("Microsoft.CodeAnalysis.VisualBasic.Symbols.SubstitutedErrorType", errorType.GetType().ToString())
Assert.Equal("C(Of )[missing].D(Of )[missing]", definition.ToTestDisplayString())
Assert.True(definition.IsDefinition)
' Construct from definition with modified U from definition
Dim modifiedU = ImmutableArray.Create(New TypeWithModifiers(definition.TypeParameters.Single(), modifiers))
Dim t1 = definition.Construct(TypeSubstitution.Create(definition, definition.TypeParameters, modifiedU))
Assert.Equal("C(Of )[missing].D(Of modopt(System.Object))[missing]", t1.ToTestDisplayString())
AssertHashCodesMatch(definition, t1)
End Sub
Private Shared Sub AssertHashCodesMatch(c As TypeSymbol, c2 As TypeSymbol)
Assert.False(c.IsSameType(c2, TypeCompareKind.ConsiderEverything))
Assert.True(c.IsSameType(c2, (TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds Or TypeCompareKind.IgnoreTupleNames)))
Assert.Equal(c2.GetHashCode(), c.GetHashCode())
End Sub
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册