Skip to content

Commit

Permalink
Fix issue in type equivalence involving arrays (dotnet#39914)
Browse files Browse the repository at this point in the history
- Fix issue where single dimensional arrays and multidimensional arrays of rank 1 are considered equivalent
  • Loading branch information
davidwrighton authored Jul 25, 2020
1 parent 0e5614c commit 90989b4
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 0 deletions.
8 changes: 8 additions & 0 deletions src/coreclr/src/vm/methodtable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1375,6 +1375,14 @@ BOOL MethodTable::IsEquivalentTo_Worker(MethodTable *pOtherMT COMMA_INDEBUG(Type
if (!pOtherMT->IsArray() || GetRank() != pOtherMT->GetRank())
return FALSE;

if (IsMultiDimArray() != pOtherMT->IsMultiDimArray())
{
// A non-multidimensional array is not equivalent to an SzArray.
// This case is handling the case of a Rank 1 multidimensional array
// when compared to a normal array.
return FALSE;
}

// arrays of structures have their own unshared MTs and will take this path
return (GetArrayElementTypeHandle().IsEquivalentTo(pOtherMT->GetArrayElementTypeHandle() COMMA_INDEBUG(&newVisited)));
}
Expand Down
69 changes: 69 additions & 0 deletions src/tests/baseservices/typeequivalence/simple/Simple.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,71 @@ private static void CallSparseInterface()
Assert.AreEqual(input * 18, sparseType.MultiplyBy18(input));
}

private static void TestArrayEquivalence()
{
Console.WriteLine($"{nameof(TestArrayEquivalence)}");
var inAsm = EmptyType.Create();
var otherAsm = EmptyType2.Create();

Type inAsmInterfaceType = inAsm.GetType().GetInterface(nameof(IEmptyType));
Type otherAsmInterfaceType = otherAsm.GetType().GetInterface(nameof(IEmptyType));

Assert.IsTrue(inAsmInterfaceType.MakeArrayType().IsEquivalentTo(otherAsmInterfaceType.MakeArrayType()));
Assert.IsTrue(inAsmInterfaceType.MakeArrayType(1).IsEquivalentTo(otherAsmInterfaceType.MakeArrayType(1)));
Assert.IsTrue(inAsmInterfaceType.MakeArrayType(2).IsEquivalentTo(otherAsmInterfaceType.MakeArrayType(2)));

Assert.IsFalse(inAsmInterfaceType.MakeArrayType().IsEquivalentTo(otherAsmInterfaceType.MakeArrayType(1)));
Assert.IsFalse(inAsmInterfaceType.MakeArrayType(1).IsEquivalentTo(otherAsmInterfaceType.MakeArrayType(2)));
}

private static void TestByRefEquivalence()
{
Console.WriteLine($"{nameof(TestByRefEquivalence)}");
var inAsm = EmptyType.Create();
var otherAsm = EmptyType2.Create();

Type inAsmInterfaceType = inAsm.GetType().GetInterface(nameof(IEmptyType));
Type otherAsmInterfaceType = otherAsm.GetType().GetInterface(nameof(IEmptyType));

Assert.IsTrue(inAsmInterfaceType.MakeByRefType().IsEquivalentTo(otherAsmInterfaceType.MakeByRefType()));
}

interface IGeneric<in T>
{
void Method(T input);
}

class Generic<V> : IGeneric<V>
{
public void Method(V input)
{
}
}

private static void TestGenericClassNonEquivalence()
{
Console.WriteLine($"{nameof(TestGenericClassNonEquivalence)}");
var inAsm = EmptyType.Create();
var otherAsm = EmptyType2.Create();

Type inAsmInterfaceType = inAsm.GetType().GetInterface(nameof(IEmptyType));
Type otherAsmInterfaceType = otherAsm.GetType().GetInterface(nameof(IEmptyType));

Assert.IsFalse(typeof(Generic<>).MakeGenericType(inAsmInterfaceType).IsEquivalentTo(typeof(Generic<>).MakeGenericType(otherAsmInterfaceType)));
}

private static void TestGenericInterfaceEquivalence()
{
Console.WriteLine($"{nameof(TestGenericInterfaceEquivalence)}");
var inAsm = EmptyType.Create();
var otherAsm = EmptyType2.Create();

Type inAsmInterfaceType = inAsm.GetType().GetInterface(nameof(IEmptyType));
Type otherAsmInterfaceType = otherAsm.GetType().GetInterface(nameof(IEmptyType));

Assert.IsTrue(typeof(IGeneric<>).MakeGenericType(inAsmInterfaceType).IsEquivalentTo(typeof(IGeneric<>).MakeGenericType(otherAsmInterfaceType)));
}

public static int Main(string[] noArgs)
{
try
Expand All @@ -157,6 +222,10 @@ public static int Main(string[] noArgs)
ValidateTypeInstanceEquality();
InterfaceTypesMethodOperations();
CallSparseInterface();
TestByRefEquivalence();
TestArrayEquivalence();
TestGenericClassNonEquivalence();
TestGenericInterfaceEquivalence();
}
catch (Exception e)
{
Expand Down

0 comments on commit 90989b4

Please sign in to comment.