From 005426df7b8752a8f18605ed336863a0f9009710 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Thu, 14 Aug 2025 12:41:49 -0700 Subject: [PATCH] Rename IsInterface to avoid Reflection issues This is a narrow change to address a user reported issue on System.Runtime and the common implementation detail, System.RuntimeType. --- .../Reflection/RuntimeCustomAttributeData.cs | 4 ++-- .../Reflection/RuntimeMethodInfo.CoreCLR.cs | 4 ++-- .../DynamicInterfaceCastableHelpers.cs | 2 +- .../src/System/RuntimeType.CoreCLR.cs | 20 +++++++++---------- .../src/System.Private.CoreLib.csproj | 2 +- ...untimeType.cs => RuntimeType.NativeAot.cs} | 2 +- .../System/Reflection/Emit/DynamicMethod.cs | 2 +- .../src/System/RuntimeType.cs | 6 +++--- .../System.Private.CoreLib/src/System/Type.cs | 2 +- .../src/System/RuntimeType.Mono.cs | 2 ++ 10 files changed, 24 insertions(+), 22 deletions(-) rename src/coreclr/nativeaot/System.Private.CoreLib/src/System/{RuntimeType.cs => RuntimeType.NativeAot.cs} (99%) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs index f92173602ebca0..ae42fa55d03630 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs @@ -170,7 +170,7 @@ internal static CustomAttributeEncoding TypeToCustomAttributeEncoding(RuntimeTyp if (type.IsClass) return CustomAttributeEncoding.Object; - if (type.IsInterface) + if (type.IsActualInterface) return CustomAttributeEncoding.Object; if (type.IsActualValueType) @@ -2263,7 +2263,7 @@ internal static bool IsDefined(RuntimeFieldInfo field, RuntimeType? caType) internal static StructLayoutAttribute? GetStructLayoutCustomAttribute(RuntimeType type) { - if (type.IsInterface || type.HasElementType || type.IsGenericParameter) + if (type.IsActualInterface || type.HasElementType || type.IsGenericParameter) return null; LayoutKind layoutKind = LayoutKind.Auto; diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs index a4bd430b620082..3a72a2e1174e4b 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs @@ -105,7 +105,7 @@ Signature LazyCreateSignature() internal RuntimeMethodInfo? GetParentDefinition() { - if (!IsVirtual || m_declaringType.IsInterface) + if (!IsVirtual || m_declaringType.IsActualInterface) return null; RuntimeType? parent = (RuntimeType?)m_declaringType.BaseType; @@ -323,7 +323,7 @@ internal void InvokePropertySetter(object? obj, BindingFlags invokeAttr, Binder? public override MethodInfo GetBaseDefinition() { - if (!IsVirtual || IsStatic || m_declaringType == null || m_declaringType.IsInterface) + if (!IsVirtual || IsStatic || m_declaringType == null || m_declaringType.IsActualInterface) return this; int slot = RuntimeMethodHandle.GetSlot(this); diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/DynamicInterfaceCastableHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/DynamicInterfaceCastableHelpers.cs index 0314219f14ce97..260534b1ce799a 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/DynamicInterfaceCastableHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/DynamicInterfaceCastableHelpers.cs @@ -30,7 +30,7 @@ internal static bool IsInterfaceImplemented(IDynamicInterfaceCastable castable, throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, castable.GetType(), interfaceType)); RuntimeType implType = handle.GetRuntimeType(); - if (!implType.IsInterface) + if (!implType.IsActualInterface) throw new InvalidOperationException(SR.Format(SR.IDynamicInterfaceCastable_NotInterface, implType.ToString())); if (!implType.IsDefined(typeof(DynamicInterfaceCastableImplementationAttribute), inherit: false)) diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs index cb602f16c4c72f..1e53282c7fc52c 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs @@ -579,7 +579,7 @@ private unsafe RuntimeMethodInfo[] PopulateMethods(Filter filter) RuntimeType declaringType = ReflectedType; Debug.Assert(declaringType != null); - if (declaringType.IsInterface) + if (declaringType.IsActualInterface) { #region IsInterface @@ -998,7 +998,7 @@ private RuntimeType[] PopulateInterfaces(Filter filter) continue; } - Debug.Assert(interfaceType.IsInterface); + Debug.Assert(interfaceType.IsActualInterface); list.Add(interfaceType); } @@ -1028,7 +1028,7 @@ private RuntimeType[] PopulateInterfaces(Filter filter) for (int i = 0; i < constraints.Length; i++) { RuntimeType constraint = (RuntimeType)constraints[i]; - if (constraint.IsInterface) + if (constraint.IsActualInterface) al.Add(constraint); Type[] temp = constraint.GetInterfaces(); @@ -1113,7 +1113,7 @@ private RuntimeEventInfo[] PopulateEvents(Filter filter) RuntimeType declaringType = ReflectedType; ListBuilder list = default; - if (!declaringType.IsInterface) + if (!declaringType.IsActualInterface) { while (RuntimeTypeHandle.IsGenericVariable(declaringType)) declaringType = declaringType.GetBaseType()!; @@ -1206,7 +1206,7 @@ private RuntimePropertyInfo[] PopulateProperties(Filter filter) ListBuilder list = default; - if (!declaringType.IsInterface) + if (!declaringType.IsActualInterface) { while (RuntimeTypeHandle.IsGenericVariable(declaringType)) declaringType = declaringType.GetBaseType()!; @@ -1258,8 +1258,8 @@ private void PopulateProperties( int numVirtuals = RuntimeTypeHandle.GetNumVirtuals(declaringType); - Debug.Assert((declaringType.IsInterface && isInterface && csPropertyInfos == null) || - (!declaringType.IsInterface && !isInterface && usedSlots.Length >= numVirtuals)); + Debug.Assert((declaringType.IsActualInterface && isInterface && csPropertyInfos == null) || + (!declaringType.IsActualInterface && !isInterface && usedSlots.Length >= numVirtuals)); for (int i = 0; i < tkProperties.Length; i++) { @@ -2697,7 +2697,7 @@ public override InterfaceMapping GetInterfaceMap([DynamicallyAccessedMembers(Dyn TypeHandle.VerifyInterfaceIsImplemented(ifaceRtTypeHandle); Debug.Assert(interfaceType.IsInterface); // VerifyInterfaceIsImplemented enforces this invariant - Debug.Assert(!IsInterface); // VerifyInterfaceIsImplemented enforces this invariant + Debug.Assert(!IsActualInterface); // VerifyInterfaceIsImplemented enforces this invariant // SZArrays implement the methods on IList`1, IEnumerable`1, and ICollection`1 with // SZArrayHelper and some runtime magic. We don't have accurate interface maps for them. @@ -2739,7 +2739,7 @@ public override InterfaceMapping GetInterfaceMap([DynamicallyAccessedMembers(Dyn // If we resolved to an interface method, use the interface type as reflected type. Otherwise use `this`. RuntimeType reflectedType = RuntimeMethodHandle.GetDeclaringType(classRtMethodHandle); - if (!reflectedType.IsInterface) + if (!reflectedType.IsActualInterface) reflectedType = this; // GetMethodBase will convert this to the instantiating/unboxing stub if necessary @@ -3432,7 +3432,7 @@ internal unsafe bool IsActualEnum } } - internal new unsafe bool IsInterface + internal unsafe bool IsActualInterface { get { diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj index 2c96332adf7d00..39d9b041a18d4c 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -186,7 +186,7 @@ - + diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.NativeAot.cs similarity index 99% rename from src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.NativeAot.cs index 1854e6ddeb210d..c417aaad804bb0 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.NativeAot.cs @@ -213,7 +213,7 @@ public override RuntimeTypeHandle TypeHandle } } - internal new unsafe bool IsInterface + internal unsafe bool IsActualInterface { get { diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.cs index d64ccd64a482e0..54cf9e81bfb3b3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.cs @@ -269,7 +269,7 @@ private void Init(string name, if (owner?.UnderlyingSystemType is RuntimeType rtOwner) { if (rtOwner.HasElementType || rtOwner.ContainsGenericParameters - || rtOwner.IsGenericParameter || rtOwner.IsInterface) + || rtOwner.IsGenericParameter || rtOwner.IsActualInterface) throw new ArgumentException(SR.Argument_InvalidTypeForDynamicMethod); _typeOwner = rtOwner; diff --git a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs index 3e884c7074fe44..3b7537bbf32d31 100644 --- a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs @@ -297,7 +297,7 @@ public override bool IsAssignableFrom([NotNullWhen(true)] Type? c) if (c.IsSubclassOf(this)) return true; - if (IsInterface) + if (IsActualInterface) { return c.ImplementInterface(this); } @@ -711,7 +711,7 @@ public override bool IsAssignableFrom([NotNullWhen(true)] Type? c) // `class G3 where T:U where U:Stream`: typeof(G3<,>).GetGenericArguments()[0].BaseType is Object (!) private RuntimeType? GetBaseType() { - if (IsInterface) + if (IsActualInterface) return null; if (RuntimeTypeHandle.IsGenericVariable(this)) @@ -724,7 +724,7 @@ public override bool IsAssignableFrom([NotNullWhen(true)] Type? c) { RuntimeType constraint = (RuntimeType)constraints[i]; - if (constraint.IsInterface) + if (constraint.IsActualInterface) continue; if (constraint.IsGenericParameter) diff --git a/src/libraries/System.Private.CoreLib/src/System/Type.cs b/src/libraries/System.Private.CoreLib/src/System/Type.cs index 52bf4ef524b866..6020b6848a7d5f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Type.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Type.cs @@ -33,7 +33,7 @@ public bool IsInterface { #if !MONO if (this is RuntimeType rt) - return rt.IsInterface; + return rt.IsActualInterface; #endif return (GetAttributeFlagsImpl() & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface; } diff --git a/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs b/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs index 5015ed41f90f05..d27b1a79e7bddc 100644 --- a/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs @@ -1321,6 +1321,8 @@ protected override bool IsValueTypeImpl() return res; } + internal bool IsActualInterface => IsInterface; + // Returns true for actual value types only, ignoring generic parameter constraints. internal bool IsActualValueType => RuntimeTypeHandle.IsValueType(this);