Skip to content

Commit af95bed

Browse files
authored
Fix Type.ContainsGenericParameters for function pointers (#90864)
* Fix Type.ContainsGenericParameters for function pointers Fixes #84916 * Fix System.Reflection.MetadataLoadContext * Fix Mono
1 parent a2df89f commit af95bed

File tree

6 files changed

+94
-21
lines changed

6 files changed

+94
-21
lines changed

src/coreclr/vm/typedesc.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,31 @@ BOOL TypeDesc::IsSharedByGenericInstantiations()
104104
return FALSE;
105105
}
106106

107+
BOOL TypeDesc::ContainsGenericVariables(BOOL methodOnly)
108+
{
109+
if (IsGenericVariable())
110+
{
111+
if (!methodOnly)
112+
return TRUE;
113+
114+
PTR_TypeVarTypeDesc pTyVar = dac_cast<PTR_TypeVarTypeDesc>(this);
115+
return TypeFromToken(pTyVar->GetTypeOrMethodDef()) == mdtMethodDef;
116+
}
117+
118+
if (HasTypeParam())
119+
{
120+
return GetRootTypeParam().ContainsGenericVariables(methodOnly);
121+
}
122+
123+
if (IsFnPtr())
124+
{
125+
return dac_cast<PTR_FnPtrTypeDesc>(this)->ContainsGenericVariables(methodOnly);
126+
}
127+
128+
return FALSE;
129+
}
130+
131+
107132
PTR_BaseDomain TypeDesc::GetDomain()
108133
{
109134
CONTRACTL
@@ -1670,6 +1695,21 @@ FnPtrTypeDesc::IsSharedByGenericInstantiations()
16701695
return FALSE;
16711696
} // FnPtrTypeDesc::IsSharedByGenericInstantiations
16721697

1698+
BOOL
1699+
FnPtrTypeDesc::ContainsGenericVariables(BOOL methodOnly)
1700+
{
1701+
LIMITED_METHOD_DAC_CONTRACT;
1702+
1703+
for (DWORD i = 0; i <= m_NumArgs; i++)
1704+
{
1705+
if (m_RetAndArgTypes[i].ContainsGenericVariables(methodOnly))
1706+
{
1707+
return TRUE;
1708+
}
1709+
}
1710+
return FALSE;
1711+
} // FnPtrTypeDesc::ContainsGenericVariables
1712+
16731713
#ifndef DACCESS_COMPILE
16741714

16751715
// Returns TRUE if all return and argument types are externally visible.

src/coreclr/vm/typedesc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ class TypeDesc
182182

183183
BOOL IsSharedByGenericInstantiations();
184184

185+
BOOL ContainsGenericVariables(BOOL methodOnly);
186+
185187
protected:
186188
// See methodtable.h for details of the flags with the same name there
187189
enum
@@ -527,6 +529,8 @@ class FnPtrTypeDesc : public TypeDesc
527529

528530
BOOL IsSharedByGenericInstantiations();
529531

532+
BOOL ContainsGenericVariables(BOOL methodOnly);
533+
530534
#ifndef DACCESS_COMPILE
531535
// Returns TRUE if all return and argument types are externally visible.
532536
BOOL IsExternallyVisible() const;

src/coreclr/vm/typehandle.cpp

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -138,26 +138,10 @@ BOOL TypeHandle::ContainsGenericVariables(BOOL methodOnly /*=FALSE*/) const
138138
STATIC_CONTRACT_NOTHROW;
139139
SUPPORTS_DAC;
140140

141-
if (HasTypeParam())
142-
{
143-
return GetTypeParam().ContainsGenericVariables(methodOnly);
144-
}
145-
146-
if (IsGenericVariable())
147-
{
148-
if (!methodOnly)
149-
return TRUE;
150-
151-
PTR_TypeVarTypeDesc pTyVar = dac_cast<PTR_TypeVarTypeDesc>(AsTypeDesc());
152-
return TypeFromToken(pTyVar->GetTypeOrMethodDef()) == mdtMethodDef;
153-
}
154-
else if (HasInstantiation())
155-
{
156-
if (GetMethodTable()->ContainsGenericVariables(methodOnly))
157-
return TRUE;
158-
}
159-
160-
return FALSE;
141+
if (IsTypeDesc())
142+
return AsTypeDesc()->ContainsGenericVariables(methodOnly);
143+
else
144+
return AsMethodTable()->ContainsGenericVariables(methodOnly);
161145
}
162146

163147
//@GENERICS:

src/libraries/Common/tests/System/FunctionPointerTests.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,22 @@ public static unsafe void RequiredModifiers()
173173
Assert.Equal(typeof(Runtime.InteropServices.OutAttribute).Project(), parameters[1].GetRequiredCustomModifiers()[0]);
174174
}
175175

176+
[Fact]
177+
public static unsafe void GenericFunctionPointer()
178+
{
179+
Type t = typeof(FunctionPointerHolder).Project();
180+
181+
MethodInfo m1 = t.GetMethod(nameof(FunctionPointerHolder.GenericReturnValue), Bindings);
182+
Type fcnPtr1 = m1.ReturnType;
183+
Assert.True(fcnPtr1.IsFunctionPointer);
184+
Assert.True(fcnPtr1.ContainsGenericParameters);
185+
186+
MethodInfo m2 = t.GetMethod(nameof(FunctionPointerHolder.GenericArgument), Bindings);
187+
Type fcnPtr2 = m2.GetParameters()[1].ParameterType;
188+
Assert.True(fcnPtr2.IsFunctionPointer);
189+
Assert.True(fcnPtr2.ContainsGenericParameters);
190+
}
191+
176192
[Theory]
177193
[InlineData(nameof(FunctionPointerHolder.MethodReturnValue1),
178194
"MethodReturnValue1()",
@@ -278,6 +294,9 @@ private unsafe class FunctionPointerHolder
278294
public delegate* unmanaged[Stdcall, MemberFunction]<string, ref bool*, MyClass, in MyStruct, double> SeveralArguments() => default;
279295
public delegate*<in int, out int, void> RequiredModifiers() => default;
280296

297+
public delegate*<T> GenericReturnValue<T>() => default;
298+
public bool GenericArgument<T>(int x, delegate*<T[], void> fptr) => default;
299+
281300
public class MyClass { }
282301
public struct MyStruct { }
283302
}

src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoFunctionPointerType.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,23 @@ public sealed override bool Equals([NotNullWhen(true)] object? obj)
147147
public sealed override bool IsGenericParameter => false;
148148
public sealed override bool IsGenericTypeParameter => false;
149149
public sealed override bool IsGenericMethodParameter => false;
150-
public sealed override bool ContainsGenericParameters => IsGenericTypeDefinition;
150+
151+
public sealed override bool ContainsGenericParameters
152+
{
153+
get
154+
{
155+
if (_returnType.ContainsGenericParameters)
156+
return true;
157+
158+
foreach (Type parameterType in _parameterTypes)
159+
{
160+
if (parameterType.ContainsGenericParameters)
161+
return true;
162+
}
163+
164+
return false;
165+
}
166+
}
151167

152168
protected sealed override TypeCode GetTypeCodeImpl() => TypeCode.Object;
153169

src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2048,6 +2048,16 @@ public override bool ContainsGenericParameters
20482048
if (HasElementType)
20492049
return GetElementType().ContainsGenericParameters;
20502050

2051+
if (IsFunctionPointer)
2052+
{
2053+
if (GetFunctionPointerReturnType().ContainsGenericParameters)
2054+
return true;
2055+
2056+
foreach (Type arg in GetFunctionPointerParameterTypes())
2057+
if (arg.ContainsGenericParameters)
2058+
return true;
2059+
}
2060+
20512061
return false;
20522062
}
20532063
}

0 commit comments

Comments
 (0)