diff --git a/src/coreclr/vm/typedesc.cpp b/src/coreclr/vm/typedesc.cpp index 6c3226882503c..95e86ccc96169 100644 --- a/src/coreclr/vm/typedesc.cpp +++ b/src/coreclr/vm/typedesc.cpp @@ -104,6 +104,31 @@ BOOL TypeDesc::IsSharedByGenericInstantiations() return FALSE; } +BOOL TypeDesc::ContainsGenericVariables(BOOL methodOnly) +{ + if (IsGenericVariable()) + { + if (!methodOnly) + return TRUE; + + PTR_TypeVarTypeDesc pTyVar = dac_cast(this); + return TypeFromToken(pTyVar->GetTypeOrMethodDef()) == mdtMethodDef; + } + + if (HasTypeParam()) + { + return GetRootTypeParam().ContainsGenericVariables(methodOnly); + } + + if (IsFnPtr()) + { + return dac_cast(this)->ContainsGenericVariables(methodOnly); + } + + return FALSE; +} + + PTR_BaseDomain TypeDesc::GetDomain() { CONTRACTL @@ -1670,6 +1695,21 @@ FnPtrTypeDesc::IsSharedByGenericInstantiations() return FALSE; } // FnPtrTypeDesc::IsSharedByGenericInstantiations +BOOL +FnPtrTypeDesc::ContainsGenericVariables(BOOL methodOnly) +{ + LIMITED_METHOD_DAC_CONTRACT; + + for (DWORD i = 0; i <= m_NumArgs; i++) + { + if (m_RetAndArgTypes[i].ContainsGenericVariables(methodOnly)) + { + return TRUE; + } + } + return FALSE; +} // FnPtrTypeDesc::ContainsGenericVariables + #ifndef DACCESS_COMPILE // Returns TRUE if all return and argument types are externally visible. diff --git a/src/coreclr/vm/typedesc.h b/src/coreclr/vm/typedesc.h index 51614c3b11077..b86845c81e21c 100644 --- a/src/coreclr/vm/typedesc.h +++ b/src/coreclr/vm/typedesc.h @@ -182,6 +182,8 @@ class TypeDesc BOOL IsSharedByGenericInstantiations(); + BOOL ContainsGenericVariables(BOOL methodOnly); + protected: // See methodtable.h for details of the flags with the same name there enum @@ -527,6 +529,8 @@ class FnPtrTypeDesc : public TypeDesc BOOL IsSharedByGenericInstantiations(); + BOOL ContainsGenericVariables(BOOL methodOnly); + #ifndef DACCESS_COMPILE // Returns TRUE if all return and argument types are externally visible. BOOL IsExternallyVisible() const; diff --git a/src/coreclr/vm/typehandle.cpp b/src/coreclr/vm/typehandle.cpp index 59eed8b5030d8..053cc759217c7 100644 --- a/src/coreclr/vm/typehandle.cpp +++ b/src/coreclr/vm/typehandle.cpp @@ -138,26 +138,10 @@ BOOL TypeHandle::ContainsGenericVariables(BOOL methodOnly /*=FALSE*/) const STATIC_CONTRACT_NOTHROW; SUPPORTS_DAC; - if (HasTypeParam()) - { - return GetTypeParam().ContainsGenericVariables(methodOnly); - } - - if (IsGenericVariable()) - { - if (!methodOnly) - return TRUE; - - PTR_TypeVarTypeDesc pTyVar = dac_cast(AsTypeDesc()); - return TypeFromToken(pTyVar->GetTypeOrMethodDef()) == mdtMethodDef; - } - else if (HasInstantiation()) - { - if (GetMethodTable()->ContainsGenericVariables(methodOnly)) - return TRUE; - } - - return FALSE; + if (IsTypeDesc()) + return AsTypeDesc()->ContainsGenericVariables(methodOnly); + else + return AsMethodTable()->ContainsGenericVariables(methodOnly); } //@GENERICS: diff --git a/src/libraries/Common/tests/System/FunctionPointerTests.cs b/src/libraries/Common/tests/System/FunctionPointerTests.cs index 925c8683f8f7f..8a344e01e7895 100644 --- a/src/libraries/Common/tests/System/FunctionPointerTests.cs +++ b/src/libraries/Common/tests/System/FunctionPointerTests.cs @@ -173,6 +173,22 @@ public static unsafe void RequiredModifiers() Assert.Equal(typeof(Runtime.InteropServices.OutAttribute).Project(), parameters[1].GetRequiredCustomModifiers()[0]); } + [Fact] + public static unsafe void GenericFunctionPointer() + { + Type t = typeof(FunctionPointerHolder).Project(); + + MethodInfo m1 = t.GetMethod(nameof(FunctionPointerHolder.GenericReturnValue), Bindings); + Type fcnPtr1 = m1.ReturnType; + Assert.True(fcnPtr1.IsFunctionPointer); + Assert.True(fcnPtr1.ContainsGenericParameters); + + MethodInfo m2 = t.GetMethod(nameof(FunctionPointerHolder.GenericArgument), Bindings); + Type fcnPtr2 = m2.GetParameters()[1].ParameterType; + Assert.True(fcnPtr2.IsFunctionPointer); + Assert.True(fcnPtr2.ContainsGenericParameters); + } + [Theory] [InlineData(nameof(FunctionPointerHolder.MethodReturnValue1), "MethodReturnValue1()", @@ -278,6 +294,9 @@ private unsafe class FunctionPointerHolder public delegate* unmanaged[Stdcall, MemberFunction] SeveralArguments() => default; public delegate* RequiredModifiers() => default; + public delegate* GenericReturnValue() => default; + public bool GenericArgument(int x, delegate* fptr) => default; + public class MyClass { } public struct MyStruct { } } diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoFunctionPointerType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoFunctionPointerType.cs index 73cd87437551f..426ab7085d9fd 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoFunctionPointerType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoFunctionPointerType.cs @@ -147,7 +147,23 @@ public sealed override bool Equals([NotNullWhen(true)] object? obj) public sealed override bool IsGenericParameter => false; public sealed override bool IsGenericTypeParameter => false; public sealed override bool IsGenericMethodParameter => false; - public sealed override bool ContainsGenericParameters => IsGenericTypeDefinition; + + public sealed override bool ContainsGenericParameters + { + get + { + if (_returnType.ContainsGenericParameters) + return true; + + foreach (Type parameterType in _parameterTypes) + { + if (parameterType.ContainsGenericParameters) + return true; + } + + return false; + } + } protected sealed override TypeCode GetTypeCodeImpl() => TypeCode.Object; 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 e7feb145b1884..5924d5c0640df 100644 --- a/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs @@ -2048,6 +2048,16 @@ public override bool ContainsGenericParameters if (HasElementType) return GetElementType().ContainsGenericParameters; + if (IsFunctionPointer) + { + if (GetFunctionPointerReturnType().ContainsGenericParameters) + return true; + + foreach (Type arg in GetFunctionPointerParameterTypes()) + if (arg.ContainsGenericParameters) + return true; + } + return false; } }