Skip to content

Commit 02545f5

Browse files
authored
Use method signature comparisons to disambiguate during explicit interface inference (#350)
1 parent 03b6607 commit 02545f5

File tree

1 file changed

+28
-7
lines changed

1 file changed

+28
-7
lines changed

Cpp2IL.Core/Utils/AsmResolver/AsmResolverAssemblyPopulator.cs

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -562,9 +562,6 @@ private static void InferExplicitInterfaceImplementations(TypeDefinition type, R
562562
if (Utf8String.IsNullOrEmpty(method.Name))
563563
continue;
564564

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

578+
if (interfaceType is null)
579+
continue;
580+
581+
var ambiguous = false;
581582
IMethodDefOrRef? interfaceMethod = null;
582-
var underlyingInterface = interfaceType?.GetUnderlyingTypeDefOrRef();
583+
var underlyingInterface = interfaceType.GetUnderlyingTypeDefOrRef();
583584
foreach (var interfaceMethodDef in (underlyingInterface as TypeDefinition)?.Methods ?? [])
584585
{
585586
if (interfaceMethodDef.Name != methodName)
586587
continue;
587588

588589
if (interfaceMethod is not null)
589590
{
590-
// Ambiguity. Checking the method signature would be required to disambiguate.
591+
// Ambiguity. Checking the method signature will be required to disambiguate.
591592
interfaceMethod = null;
593+
ambiguous = true;
592594
break;
593595
}
594596

595-
interfaceMethod = new MemberReference(interfaceType?.ToTypeDefOrRef(), interfaceMethodDef.Name, interfaceMethodDef.Signature);
597+
// This has the implicit assumption that the method signatures match.
598+
// This is a reasonable assumption because there's no other method to match (with this name).
599+
interfaceMethod = new MemberReference(interfaceType.ToTypeDefOrRef(), interfaceMethodDef.Name, interfaceMethodDef.Signature);
600+
}
601+
602+
if (ambiguous)
603+
{
604+
// Ambiguities are very rare, so we only bother signature checking when we have to.
605+
606+
var genericContext = GenericContext.FromType(interfaceType);
607+
foreach (var interfaceMethodDef in (underlyingInterface as TypeDefinition)?.Methods ?? [])
608+
{
609+
if (interfaceMethodDef.Name != methodName)
610+
continue;
611+
612+
if (SignatureComparer.Default.Equals(method.Signature, interfaceMethodDef.Signature?.InstantiateGenericTypes(genericContext)))
613+
{
614+
interfaceMethod = new MemberReference(interfaceType?.ToTypeDefOrRef(), interfaceMethodDef.Name, interfaceMethodDef.Signature);
615+
break;
616+
}
617+
}
596618
}
597619

598620
if (interfaceMethod != null)
@@ -601,5 +623,4 @@ private static void InferExplicitInterfaceImplementations(TypeDefinition type, R
601623
}
602624
}
603625
}
604-
605626
}

0 commit comments

Comments
 (0)