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

Add correct ImplementingType and InterfaceImpl to DIM cache in TypeMapInfo #98513

Merged
merged 10 commits into from
Feb 22, 2024
2 changes: 1 addition & 1 deletion src/tools/illink/src/linker/Linker.Steps/MarkStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@ void ProcessVirtualMethod (MethodDefinition method)
foreach (var dimInfo in defaultImplementations) {
ProcessDefaultImplementation (dimInfo.ImplementingType, dimInfo.InterfaceImpl, dimInfo.DefaultInterfaceMethod);

var ov = new OverrideInformation (method, dimInfo.DefaultInterfaceMethod, Context);
var ov = new OverrideInformation (method, dimInfo.DefaultInterfaceMethod, Context, dimInfo.InterfaceImpl);
jtschuster marked this conversation as resolved.
Show resolved Hide resolved
if (IsInterfaceImplementationMethodNeededByTypeDueToInterface (ov, dimInfo.ImplementingType))
MarkMethod (ov.Override, new DependencyInfo (DependencyKind.Override, ov.Base), ScopeStack.CurrentScope.Origin);
}
Expand Down
31 changes: 19 additions & 12 deletions src/tools/illink/src/linker/Linker/TypeMapInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ void MapInterfaceMethodsInTypeHierarchy (TypeDefinition type)
}

// Look for a default implementation last.
FindAndAddDefaultInterfaceImplementations (type, resolvedInterfaceMethod);
FindAndAddDefaultInterfaceImplementations (type, type, resolvedInterfaceMethod);
}
}
}
Expand Down Expand Up @@ -279,26 +279,33 @@ void AnnotateMethods (MethodDefinition @base, MethodDefinition @override, Interf
return context.TryResolve (type)?.BaseType;
}

// Returns a list of default implementations of the given interface method on this type.
// Note that this returns a list to potentially cover the diamond case (more than one
// most specific implementation of the given interface methods). ILLink needs to preserve
// all the implementations so that the proper exception can be thrown at runtime.
void FindAndAddDefaultInterfaceImplementations (TypeDefinition type, MethodDefinition interfaceMethod)
/// <summary>
/// Returns a list of default implementations of the given interface method on this type.
/// Note that this returns a list to potentially cover the diamond case (more than one
/// most specific implementation of the given interface methods). ILLink needs to preserve
/// all the implementations so that the proper exception can be thrown at runtime.
/// </summary>
/// <param name="type">The type that implements (directly or via a base interface) the declaring interface of <paramref name="interfaceMethod"/></param>
/// <param name="interfaceMethod">The method to find a default implementation for</param>
/// <param name="implOfInterface">
/// The InterfaceImplementation on <paramref name="type"/> that points to the DeclaringType of <paramref name="interfaceMethod"/>.
/// </param>
void FindAndAddDefaultInterfaceImplementations (TypeDefinition typeThatImplementsInterface, TypeDefinition typeThatMayHaveDIM, MethodDefinition interfaceMethodToBeImplemented)
{
// Go over all interfaces, trying to find a method that is an explicit MethodImpl of the
// interface method in question.

foreach (var interfaceImpl in type.Interfaces) {
foreach (var interfaceImpl in typeThatMayHaveDIM.Interfaces) {
var potentialImplInterface = context.TryResolve (interfaceImpl.InterfaceType);
if (potentialImplInterface == null)
continue;

bool foundImpl = false;

foreach (var potentialImplMethod in potentialImplInterface.Methods) {
if (potentialImplMethod == interfaceMethod &&
if (potentialImplMethod == interfaceMethodToBeImplemented &&
!potentialImplMethod.IsAbstract) {
AddDefaultInterfaceImplementation (interfaceMethod, type, (interfaceImpl, potentialImplMethod));
AddDefaultInterfaceImplementation (interfaceMethodToBeImplemented, typeThatImplementsInterface, (interfaceImpl, potentialImplMethod));
foundImpl = true;
break;
}
Expand All @@ -308,8 +315,8 @@ void FindAndAddDefaultInterfaceImplementations (TypeDefinition type, MethodDefin

// This method is an override of something. Let's see if it's the method we are looking for.
foreach (var @override in potentialImplMethod.Overrides) {
if (context.TryResolve (@override) == interfaceMethod) {
AddDefaultInterfaceImplementation (interfaceMethod, type, (interfaceImpl, @potentialImplMethod));
if (context.TryResolve (@override) == interfaceMethodToBeImplemented) {
AddDefaultInterfaceImplementation (interfaceMethodToBeImplemented, typeThatImplementsInterface, (interfaceImpl, potentialImplMethod));
foundImpl = true;
break;
}
Expand All @@ -323,7 +330,7 @@ void FindAndAddDefaultInterfaceImplementations (TypeDefinition type, MethodDefin
// We haven't found a MethodImpl on the current interface, but one of the interfaces
// this interface requires could still provide it.
if (!foundImpl) {
FindAndAddDefaultInterfaceImplementations (potentialImplInterface, interfaceMethod);
FindAndAddDefaultInterfaceImplementations (typeThatImplementsInterface, potentialImplInterface, interfaceMethodToBeImplemented);
}
}
}
Expand Down
Loading