Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[release/8.0] Fix Type.ContainsGenericParameters for function pointers #90963

Merged
merged 4 commits into from
Aug 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions src/coreclr/vm/typedesc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<PTR_TypeVarTypeDesc>(this);
return TypeFromToken(pTyVar->GetTypeOrMethodDef()) == mdtMethodDef;
}

if (HasTypeParam())
{
return GetRootTypeParam().ContainsGenericVariables(methodOnly);
}

if (IsFnPtr())
{
return dac_cast<PTR_FnPtrTypeDesc>(this)->ContainsGenericVariables(methodOnly);
}

return FALSE;
}


PTR_BaseDomain TypeDesc::GetDomain()
{
CONTRACTL
Expand Down Expand Up @@ -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.
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/vm/typedesc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
24 changes: 4 additions & 20 deletions src/coreclr/vm/typehandle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<PTR_TypeVarTypeDesc>(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:
Expand Down
19 changes: 19 additions & 0 deletions src/libraries/Common/tests/System/FunctionPointerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()",
Expand Down Expand Up @@ -278,6 +294,9 @@ private unsafe class FunctionPointerHolder
public delegate* unmanaged[Stdcall, MemberFunction]<string, ref bool*, MyClass, in MyStruct, double> SeveralArguments() => default;
public delegate*<in int, out int, void> RequiredModifiers() => default;

public delegate*<T> GenericReturnValue<T>() => default;
public bool GenericArgument<T>(int x, delegate*<T[], void> fptr) => default;

public class MyClass { }
public struct MyStruct { }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
10 changes: 10 additions & 0 deletions src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
Loading