diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs index bab6cd0e8121df..5f05fdeb9f4703 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs @@ -277,22 +277,22 @@ private static bool IsInterfaceImplementedOnType(MetadataType type, MetadataType private static MethodDesc FindImplFromDeclFromMethodImpls(MetadataType type, MethodDesc decl) { + if (decl.OwningType.IsInterface) + return FindInterfaceImplFromDeclFromMethodImpls(type, decl); + MethodImplRecord[] foundMethodImpls = type.FindMethodsImplWithMatchingDeclName(decl.Name); if (foundMethodImpls == null) return null; - bool interfaceDecl = decl.OwningType.IsInterface; - foreach (MethodImplRecord record in foundMethodImpls) { MethodDesc recordDecl = record.Decl; - if (interfaceDecl != recordDecl.OwningType.IsInterface) + if (recordDecl.OwningType.IsInterface) continue; - if (!interfaceDecl) - recordDecl = FindSlotDefiningMethodForVirtualMethod(recordDecl); + recordDecl = FindSlotDefiningMethodForVirtualMethod(recordDecl); if (recordDecl == decl) { @@ -303,6 +303,56 @@ private static MethodDesc FindImplFromDeclFromMethodImpls(MetadataType type, Met return null; } + private static MethodDesc FindInterfaceImplFromDeclFromMethodImpls(MetadataType type, MethodDesc decl) + { + Debug.Assert(decl.OwningType.IsInterface); + + MethodImplRecord[] foundMethodImpls = type.FindMethodsImplWithMatchingDeclName(decl.Name); + + if (foundMethodImpls == null) + return null; + + // We might find more than one result due to generic parameter folding + var results = new ArrayBuilder(1); + for (int i = 0; i < foundMethodImpls.Length; i++) + { + MethodDesc recordDecl = foundMethodImpls[i].Decl; + if (recordDecl == decl) + { + results.Add(i); + } + } + + if (results.Count == 0) + return null; + + int resultIndex = results[0]; + + // If we found multiple MethodImpls, need to do a tie break using type declaration order + if (results.Count > 1) + { + MetadataType typeDefinition = (MetadataType)type.GetTypeDefinition(); + DefType[] interfacesOnDefinition = typeDefinition.RuntimeInterfaces; + MethodImplRecord[] foundMethodImplsOnDefinition = typeDefinition.FindMethodsImplWithMatchingDeclName(decl.Name); + Debug.Assert(foundMethodImplsOnDefinition.Length == foundMethodImpls.Length); + + int bestInterfaceIndex = int.MaxValue; + + for (int i = 0; i < results.Count; i++) + { + int index = Array.IndexOf(interfacesOnDefinition, foundMethodImplsOnDefinition[results[i]].Decl.OwningType); + Debug.Assert(index >= 0); + if (index < bestInterfaceIndex) + { + bestInterfaceIndex = index; + resultIndex = i; + } + } + } + + return FindSlotDefiningMethodForVirtualMethod(foundMethodImpls[resultIndex].Body); + } + private static bool IsInterfaceExplicitlyImplementedOnType(MetadataType type, MetadataType interfaceType) { foreach (TypeDesc iface in type.ExplicitlyImplementedInterfaces)