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

Use method signature comparisons to disambiguate during explicit interface inference #350

Merged
Merged
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
35 changes: 28 additions & 7 deletions Cpp2IL.Core/Utils/AsmResolver/AsmResolverAssemblyPopulator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -562,9 +562,6 @@ private static void InferExplicitInterfaceImplementations(TypeDefinition type, R
if (Utf8String.IsNullOrEmpty(method.Name))
continue;

// Explicit interface implementation
// Note: This does not handle all cases.
// Specifically, it does not handle the case where the interface has multiple methods with the same name.
var periodLastIndex = method.Name.LastIndexOf('.');
if (periodLastIndex < 0 || !method.IsPrivate || !method.IsVirtual || !method.IsFinal || !method.IsNewSlot)
{
Expand All @@ -578,21 +575,46 @@ private static void InferExplicitInterfaceImplementations(TypeDefinition type, R
: [];
var interfaceType = AsmResolverUtils.TryLookupTypeSignatureByName(interfaceName, genericParameterNames);

if (interfaceType is null)
continue;

var ambiguous = false;
IMethodDefOrRef? interfaceMethod = null;
var underlyingInterface = interfaceType?.GetUnderlyingTypeDefOrRef();
var underlyingInterface = interfaceType.GetUnderlyingTypeDefOrRef();
foreach (var interfaceMethodDef in (underlyingInterface as TypeDefinition)?.Methods ?? [])
{
if (interfaceMethodDef.Name != methodName)
continue;

if (interfaceMethod is not null)
{
// Ambiguity. Checking the method signature would be required to disambiguate.
// Ambiguity. Checking the method signature will be required to disambiguate.
interfaceMethod = null;
ambiguous = true;
break;
}

interfaceMethod = new MemberReference(interfaceType?.ToTypeDefOrRef(), interfaceMethodDef.Name, interfaceMethodDef.Signature);
// This has the implicit assumption that the method signatures match.
// This is a reasonable assumption because there's no other method to match (with this name).
interfaceMethod = new MemberReference(interfaceType.ToTypeDefOrRef(), interfaceMethodDef.Name, interfaceMethodDef.Signature);
}

if (ambiguous)
{
// Ambiguities are very rare, so we only bother signature checking when we have to.

var genericContext = GenericContext.FromType(interfaceType);
foreach (var interfaceMethodDef in (underlyingInterface as TypeDefinition)?.Methods ?? [])
{
if (interfaceMethodDef.Name != methodName)
continue;

if (SignatureComparer.Default.Equals(method.Signature, interfaceMethodDef.Signature?.InstantiateGenericTypes(genericContext)))
{
interfaceMethod = new MemberReference(interfaceType?.ToTypeDefOrRef(), interfaceMethodDef.Name, interfaceMethodDef.Signature);
break;
}
}
}

if (interfaceMethod != null)
Expand All @@ -601,5 +623,4 @@ private static void InferExplicitInterfaceImplementations(TypeDefinition type, R
}
}
}

}
Loading