Skip to content

Commit

Permalink
Clean up ILLink logic for "inflating" generic types (dotnet#106211)
Browse files Browse the repository at this point in the history
- Avoid passing LinkContext through. This was only used to resolve the
  generic context type to get its parameter index, which was
  unnecessary.

- Use non-nullable return type and simplify some callsites.

This cleanup helps with
dotnet#105345 - it makes it so we
don't have to pass through LinkContext when operating on our proxy
types just to get the generic instantiation.
  • Loading branch information
sbomer authored Aug 12, 2024
1 parent 44b4d33 commit 98967ce
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@ public static string GetDisplayName (this MethodReference method)
return sb.ToString ();
}

public static TypeReference? GetReturnType (this MethodReference method, LinkContext context)
public static TypeReference GetReturnType (this MethodReference method)
{
if (method.DeclaringType is GenericInstanceType genericInstance)
return TypeReferenceExtensions.InflateGenericType (genericInstance, method.ReturnType, context);
return TypeReferenceExtensions.InflateGenericType (genericInstance, method.ReturnType);

return method.ReturnType;
}
Expand All @@ -84,11 +84,11 @@ public static bool ReturnsVoid (this IMethodSignature method)
return method.ReturnType.WithoutModifiers ().MetadataType == MetadataType.Void;
}

public static TypeReference? GetInflatedParameterType (this MethodReference method, int parameterIndex, LinkContext context)
public static TypeReference GetInflatedParameterType (this MethodReference method, int parameterIndex)
{
#pragma warning disable RS0030 // MethodReference.Parameters is banned -- it's best to leave this as is for now
if (method.DeclaringType is GenericInstanceType genericInstance)
return TypeReferenceExtensions.InflateGenericType (genericInstance, method.Parameters[parameterIndex].ParameterType, context);
return TypeReferenceExtensions.InflateGenericType (genericInstance, method.Parameters[parameterIndex].ParameterType);

return method.Parameters[parameterIndex].ParameterType;
#pragma warning restore RS0030 // Do not used banned APIs
Expand Down
24 changes: 7 additions & 17 deletions src/tools/illink/src/linker/Linker/TypeMapInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,26 +150,20 @@ protected virtual void MapType (TypeDefinition type)
static void AddRecursiveInterfaces (TypeReference typeRef, IEnumerable<InterfaceImplementation> pathToType, List<(TypeReference, List<InterfaceImplementation>)> firstImplementationChain, LinkContext Context)
{
var type = Context.TryResolve (typeRef);
// If we can't resolve the interface type we can't find recursive interfaces
if (type is null)
return;
// Get all explicit interfaces of this type
foreach (var iface in type.Interfaces) {
var interfaceType = iface.InterfaceType.TryInflateFrom (typeRef, Context);
if (interfaceType is null) {
continue;
}
var interfaceType = iface.InterfaceType.InflateFrom (typeRef);
if (!firstImplementationChain.Any (i => TypeReferenceEqualityComparer.AreEqual (i.Item1, interfaceType, Context))) {
firstImplementationChain.Add ((interfaceType, pathToType.Append (iface).ToList ()));
}
}

// Recursive interfaces after all direct interfaces to preserve Inherit/Implement tree order
foreach (var iface in type.Interfaces) {
// If we can't resolve the interface type we can't find recursive interfaces
var ifaceDirectlyOnType = iface.InterfaceType.TryInflateFrom (typeRef, Context);
if (ifaceDirectlyOnType is null) {
continue;
}
var ifaceDirectlyOnType = iface.InterfaceType.InflateFrom (typeRef);
AddRecursiveInterfaces (ifaceDirectlyOnType, pathToType.Append (iface), firstImplementationChain, Context);
}
}
Expand Down Expand Up @@ -310,7 +304,7 @@ void AnnotateMethods (MethodDefinition @base, MethodDefinition @override, Interf
var baseType = context.TryResolve (type)?.BaseType;

if (baseType is GenericInstanceType)
return TypeReferenceExtensions.InflateGenericType (genericInstance, baseType, context);
return TypeReferenceExtensions.InflateGenericType (genericInstance, baseType);

return baseType;
}
Expand Down Expand Up @@ -389,7 +383,7 @@ void FindAndAddDefaultInterfaceImplementations (TypeDefinition typeThatImplement
}

[SuppressMessage ("ApiDesign", "RS0030:Do not used banned APIs", Justification = "It's best to leave working code alone.")]
bool MethodMatch (MethodReference candidate, MethodReference method)
static bool MethodMatch (MethodReference candidate, MethodReference method)
{
if (candidate.HasParameters != method.HasMetadataParameters ())
return false;
Expand All @@ -402,9 +396,7 @@ bool MethodMatch (MethodReference candidate, MethodReference method)

// we need to track what the generic parameter represent - as we cannot allow it to
// differ between the return type or any parameter
if (candidate.GetReturnType (context) is not TypeReference candidateReturnType ||
method.GetReturnType (context) is not TypeReference methodReturnType ||
!TypeMatch (candidateReturnType, methodReturnType))
if (!TypeMatch (candidate.GetReturnType (), method.GetReturnType ()))
return false;

if (!candidate.HasMetadataParameters ())
Expand All @@ -419,9 +411,7 @@ bool MethodMatch (MethodReference candidate, MethodReference method)
return false;

for (int i = 0; i < cp.Count; i++) {
if (candidate.GetInflatedParameterType (i, context) is not TypeReference candidateParameterType ||
method.GetInflatedParameterType (i, context) is not TypeReference methodParameterType ||
!TypeMatch (candidateParameterType, methodParameterType))
if (!TypeMatch (candidate.GetInflatedParameterType (i), method.GetInflatedParameterType (i)))
return false;
}

Expand Down
43 changes: 18 additions & 25 deletions src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,10 @@ void parseArrayDimensions (ArrayType at)
return null;
}

public static TypeReference? TryInflateFrom (this TypeReference typeToInflate, TypeReference maybeGenericInstanceProvider, ITryResolveMetadata resolver)
public static TypeReference InflateFrom (this TypeReference typeToInflate, TypeReference maybeGenericInstanceProvider)
{
if (maybeGenericInstanceProvider is GenericInstanceType genericInstanceProvider)
return InflateGenericType (genericInstanceProvider, typeToInflate, resolver);
return InflateGenericType (genericInstanceProvider, typeToInflate);
return typeToInflate;
}

Expand All @@ -166,21 +166,18 @@ void parseArrayDimensions (ArrayType at)
yield break;

if (typeRef is GenericInstanceType genericInstance) {
foreach (var interfaceImpl in typeDef.Interfaces) {
// InflateGenericType only returns null when inflating generic parameters (and the generic instance type doesn't resolve).
// Here we are not inflating a generic parameter but an interface type reference.
yield return (InflateGenericType (genericInstance, interfaceImpl.InterfaceType, resolver), interfaceImpl)!;
}
foreach (var interfaceImpl in typeDef.Interfaces)
yield return (InflateGenericType (genericInstance, interfaceImpl.InterfaceType), interfaceImpl);
} else {
foreach (var interfaceImpl in typeDef.Interfaces)
yield return (interfaceImpl.InterfaceType, interfaceImpl);
}
}

public static TypeReference? InflateGenericType (GenericInstanceType genericInstanceProvider, TypeReference typeToInflate, ITryResolveMetadata resolver)
public static TypeReference InflateGenericType (GenericInstanceType genericInstanceProvider, TypeReference typeToInflate)
{
if (typeToInflate is ArrayType arrayType) {
var inflatedElementType = InflateGenericType (genericInstanceProvider, arrayType.ElementType, resolver);
var inflatedElementType = InflateGenericType (genericInstanceProvider, arrayType.ElementType);

if (inflatedElementType != arrayType.ElementType)
return new ArrayType (inflatedElementType, arrayType.Rank);
Expand All @@ -189,35 +186,31 @@ void parseArrayDimensions (ArrayType at)
}

if (typeToInflate is GenericInstanceType genericInst)
return MakeGenericType (genericInstanceProvider, genericInst, resolver);
return MakeGenericType (genericInstanceProvider, genericInst);

if (typeToInflate is GenericParameter genericParameter) {
if (genericParameter.Owner is MethodReference)
return genericParameter;

var elementType = resolver.TryResolve (genericInstanceProvider.ElementType);
if (elementType == null)
return null;
var parameter = elementType.GenericParameters.Single (p => p == genericParameter);
return genericInstanceProvider.GenericArguments[parameter.Position];
return genericInstanceProvider.GenericArguments[genericParameter.Position];
}

if (typeToInflate is FunctionPointerType functionPointerType) {
var result = new FunctionPointerType {
ReturnType = InflateGenericType (genericInstanceProvider, functionPointerType.ReturnType, resolver)
ReturnType = InflateGenericType (genericInstanceProvider, functionPointerType.ReturnType)
};

for (int i = 0; i < functionPointerType.Parameters.Count; i++) {
var inflatedParameterType = InflateGenericType (genericInstanceProvider, functionPointerType.Parameters[i].ParameterType, resolver);
var inflatedParameterType = InflateGenericType (genericInstanceProvider, functionPointerType.Parameters[i].ParameterType);
result.Parameters.Add (new ParameterDefinition (inflatedParameterType));
}

return result;
}

if (typeToInflate is IModifierType modifierType) {
var modifier = InflateGenericType (genericInstanceProvider, modifierType.ModifierType, resolver);
var elementType = InflateGenericType (genericInstanceProvider, modifierType.ElementType, resolver);
var modifier = InflateGenericType (genericInstanceProvider, modifierType.ModifierType);
var elementType = InflateGenericType (genericInstanceProvider, modifierType.ElementType);

if (modifierType is OptionalModifierType) {
return new OptionalModifierType (modifier, elementType);
Expand All @@ -227,7 +220,7 @@ void parseArrayDimensions (ArrayType at)
}

if (typeToInflate is PinnedType pinnedType) {
var elementType = InflateGenericType (genericInstanceProvider, pinnedType.ElementType, resolver);
var elementType = InflateGenericType (genericInstanceProvider, pinnedType.ElementType);

if (elementType != pinnedType.ElementType)
return new PinnedType (elementType);
Expand All @@ -236,7 +229,7 @@ void parseArrayDimensions (ArrayType at)
}

if (typeToInflate is PointerType pointerType) {
var elementType = InflateGenericType (genericInstanceProvider, pointerType.ElementType, resolver);
var elementType = InflateGenericType (genericInstanceProvider, pointerType.ElementType);

if (elementType != pointerType.ElementType)
return new PointerType (elementType);
Expand All @@ -245,7 +238,7 @@ void parseArrayDimensions (ArrayType at)
}

if (typeToInflate is ByReferenceType byReferenceType) {
var elementType = InflateGenericType (genericInstanceProvider, byReferenceType.ElementType, resolver);
var elementType = InflateGenericType (genericInstanceProvider, byReferenceType.ElementType);

if (elementType != byReferenceType.ElementType)
return new ByReferenceType (elementType);
Expand All @@ -254,7 +247,7 @@ void parseArrayDimensions (ArrayType at)
}

if (typeToInflate is SentinelType sentinelType) {
var elementType = InflateGenericType (genericInstanceProvider, sentinelType.ElementType, resolver);
var elementType = InflateGenericType (genericInstanceProvider, sentinelType.ElementType);

if (elementType != sentinelType.ElementType)
return new SentinelType (elementType);
Expand All @@ -265,12 +258,12 @@ void parseArrayDimensions (ArrayType at)
return typeToInflate;
}

private static GenericInstanceType MakeGenericType (GenericInstanceType genericInstanceProvider, GenericInstanceType type, ITryResolveMetadata resolver)
private static GenericInstanceType MakeGenericType (GenericInstanceType genericInstanceProvider, GenericInstanceType type)
{
var result = new GenericInstanceType (type.ElementType);

for (var i = 0; i < type.GenericArguments.Count; ++i) {
result.GenericArguments.Add (InflateGenericType (genericInstanceProvider, type.GenericArguments[i], resolver));
result.GenericArguments.Add (InflateGenericType (genericInstanceProvider, type.GenericArguments[i]));
}

return result;
Expand Down

0 comments on commit 98967ce

Please sign in to comment.