diff options
author | Aaron Robinson <arobins@microsoft.com> | 2019-03-08 17:36:37 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-08 17:36:37 -0800 |
commit | c194074a82ee35f31b1e55233b43256713b26467 (patch) | |
tree | 3a619035253d8ebfba896210adc5f1c030d3abef | |
parent | ee56e5874db8780c99d2d93169aacf477f7b73f1 (diff) | |
download | coreclr-c194074a82ee35f31b1e55233b43256713b26467.tar.gz coreclr-c194074a82ee35f31b1e55233b43256713b26467.tar.bz2 coreclr-c194074a82ee35f31b1e55233b43256713b26467.zip |
Properly override IsEquivalentTo() API in RuntimeType (#23137)
* Properly override IsEquivalentTo() API in RuntimeType
* Add tests for API validation
-rw-r--r-- | src/System.Private.CoreLib/src/System/RtType.cs | 19 | ||||
-rw-r--r-- | src/System.Private.CoreLib/src/System/RuntimeHandles.cs | 5 | ||||
-rw-r--r-- | src/vm/ecalllist.h | 1 | ||||
-rw-r--r-- | src/vm/runtimehandles.cpp | 19 | ||||
-rw-r--r-- | src/vm/runtimehandles.h | 2 | ||||
-rw-r--r-- | tests/src/baseservices/typeequivalence/simple/Simple.cs | 31 |
6 files changed, 76 insertions, 1 deletions
diff --git a/src/System.Private.CoreLib/src/System/RtType.cs b/src/System.Private.CoreLib/src/System/RtType.cs index 2a71d2e759..3d03771258 100644 --- a/src/System.Private.CoreLib/src/System/RtType.cs +++ b/src/System.Private.CoreLib/src/System/RtType.cs @@ -3225,6 +3225,25 @@ namespace System return false; } +#if FEATURE_TYPEEQUIVALENCE + // Reflexive, symmetric, transitive. + public override bool IsEquivalentTo(Type other) + { + var otherRtType = other as RuntimeType; + if (otherRtType is null) + { + return false; + } + + if (otherRtType == this) + { + return true; + } + + return RuntimeTypeHandle.IsEquivalentTo(this, otherRtType); + } +#endif // FEATURE_TYPEEQUIVALENCE + public override Type BaseType => GetBaseType(); private RuntimeType GetBaseType() diff --git a/src/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/System.Private.CoreLib/src/System/RuntimeHandles.cs index 1325aa831f..56694c63b8 100644 --- a/src/System.Private.CoreLib/src/System/RuntimeHandles.cs +++ b/src/System.Private.CoreLib/src/System/RuntimeHandles.cs @@ -615,6 +615,11 @@ namespace System { throw new PlatformNotSupportedException(); } + +#if FEATURE_TYPEEQUIVALENCE + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern bool IsEquivalentTo(RuntimeType rtType1, RuntimeType rtType2); +#endif // FEATURE_TYPEEQUIVALENCE } // This type is used to remove the expense of having a managed reference object that is dynamically diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h index 35fbae2160..0298939dbf 100644 --- a/src/vm/ecalllist.h +++ b/src/vm/ecalllist.h @@ -268,6 +268,7 @@ FCFuncStart(gCOMTypeHandleFuncs) FCFuncElement("Allocate", RuntimeTypeHandle::Allocate) //for A.CI FCFuncElement("CompareCanonicalHandles", RuntimeTypeHandle::CompareCanonicalHandles) FCIntrinsic("GetValueInternal", RuntimeTypeHandle::GetValueInternal, CORINFO_INTRINSIC_RTH_GetValueInternal) + FCFuncElement("IsEquivalentTo", RuntimeTypeHandle::IsEquivalentTo) FCFuncEnd() FCFuncStart(gMetaDataImport) diff --git a/src/vm/runtimehandles.cpp b/src/vm/runtimehandles.cpp index dda5d1d139..c8782db7ef 100644 --- a/src/vm/runtimehandles.cpp +++ b/src/vm/runtimehandles.cpp @@ -250,6 +250,25 @@ FCIMPL1_V(EnregisteredTypeHandle, RuntimeTypeHandle::GetValueInternal, FCALLRunt } FCIMPLEND +FCIMPL2(FC_BOOL_RET, RuntimeTypeHandle::IsEquivalentTo, ReflectClassBaseObject *rtType1UNSAFE, ReflectClassBaseObject *rtType2UNSAFE) +{ + FCALL_CONTRACT; + + REFLECTCLASSBASEREF rtType1 = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(rtType1UNSAFE); + REFLECTCLASSBASEREF rtType2 = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(rtType2UNSAFE); + + BOOL areEquivalent = FALSE; + HELPER_METHOD_FRAME_BEGIN_RET_2(rtType1, rtType2); + + if (rtType1 != NULL && rtType2 != NULL) + areEquivalent = rtType1->GetType().IsEquivalentTo(rtType2->GetType()); + + HELPER_METHOD_FRAME_END(); + + FC_RETURN_BOOL(areEquivalent); +} +FCIMPLEND + // TypeEqualsHelper and TypeNotEqualsHelper are almost identical. // Unfortunately we cannot combime them because they need to hardcode the caller's name NOINLINE static BOOL TypeEqualSlow(OBJECTREF refL, OBJECTREF refR, LPVOID __me) diff --git a/src/vm/runtimehandles.h b/src/vm/runtimehandles.h index 6edf61ec99..66a27f4626 100644 --- a/src/vm/runtimehandles.h +++ b/src/vm/runtimehandles.h @@ -152,6 +152,8 @@ public: static FCDECL1_V(ReflectClassBaseObject*, GetTypeFromHandle, FCALLRuntimeTypeHandle th); static FCDECL1_V(EnregisteredTypeHandle, GetValueInternal, FCALLRuntimeTypeHandle RTH); + static FCDECL2(FC_BOOL_RET, IsEquivalentTo, ReflectClassBaseObject *rtType1UNSAFE, ReflectClassBaseObject *rtType2UNSAFE); + static FCDECL2(FC_BOOL_RET, TypeEQ, Object* left, Object* right); static FCDECL2(FC_BOOL_RET, TypeNEQ, Object* left, Object* right); diff --git a/tests/src/baseservices/typeequivalence/simple/Simple.cs b/tests/src/baseservices/typeequivalence/simple/Simple.cs index 0b6a54d14c..56c3ecd3fa 100644 --- a/tests/src/baseservices/typeequivalence/simple/Simple.cs +++ b/tests/src/baseservices/typeequivalence/simple/Simple.cs @@ -38,6 +38,34 @@ public class Simple } } + private static void ValidateTypeInstanceEquality() + { + Console.WriteLine($"{nameof(ValidateTypeInstanceEquality)}"); + var inAsm = EmptyType.Create(); + var otherAsm = EmptyType2.Create(); + + Type inAsmInterfaceType = inAsm.GetType().GetInterface(nameof(IEmptyType)); + Type otherAsmInterfaceType = otherAsm.GetType().GetInterface(nameof(IEmptyType)); + + // Sanity checks + Assert.IsTrue(inAsmInterfaceType == inAsmInterfaceType); + Assert.IsTrue(inAsmInterfaceType.IsEquivalentTo(inAsmInterfaceType)); + Assert.IsFalse(inAsmInterfaceType.IsEquivalentTo(inAsm.GetType())); + Assert.IsTrue(otherAsmInterfaceType == otherAsmInterfaceType); + Assert.IsTrue(otherAsmInterfaceType.IsEquivalentTo(otherAsmInterfaceType)); + Assert.IsFalse(otherAsmInterfaceType.IsEquivalentTo(otherAsm.GetType())); + + // The intrinsic equality operations should fail + Assert.IsFalse(inAsmInterfaceType == otherAsmInterfaceType); + Assert.IsFalse(inAsmInterfaceType.Equals(otherAsmInterfaceType)); + Assert.IsFalse(otherAsmInterfaceType == inAsmInterfaceType); + Assert.IsFalse(otherAsmInterfaceType.Equals(inAsmInterfaceType)); + + // Determination of equal types requires API call + Assert.IsTrue(inAsmInterfaceType.IsEquivalentTo(otherAsmInterfaceType)); + Assert.IsTrue(otherAsmInterfaceType.IsEquivalentTo(inAsmInterfaceType)); + } + private class MethodTestDerived : MethodTestBase { private readonly int scaleValue; @@ -127,6 +155,7 @@ public class Simple try { InterfaceTypesFromDifferentAssembliesAreEquivalent(); + ValidateTypeInstanceEquality(); InterfaceTypesMethodOperations(); CallSparseInterface(); } @@ -138,4 +167,4 @@ public class Simple return 100; } -}
\ No newline at end of file +} |