未验证 提交 631389fb 编写于 作者: M Michal Strehovský 提交者: GitHub

Fix ordering in default interface method lookup (#67379)

* Fix ordering in default interface method lookup

The previous implementation would find a default implementation in the current type before looking for non-default implementation in the base. Default implementations should be looked at last.

In fact the default implementation in the current type is unreachable if there's a non-default implementation in the base type - the compiler shouldn't even have bothered to emit it into the dispatch map. That can be a separate fix - this fix is still logically correct and necessary to get variant dispatch corner cases correctly.

* Regression test
上级 43ab6b87
......@@ -30,11 +30,16 @@ internal static unsafe class DispatchResolve
if (pItfType->IsCloned)
pItfType = pItfType->CanonicalEEType;
// We first look at non-default implementation. Default implementations are only considered
// if the "old algorithm" didn't come up with an answer.
bool fDoDefaultImplementationLookup = false;
again:
while (pCur != null)
{
ushort implSlotNumber;
if (FindImplSlotForCurrentType(
pCur, pItfType, itfSlotNumber, &implSlotNumber))
pCur, pItfType, itfSlotNumber, fDoDefaultImplementationLookup, &implSlotNumber))
{
IntPtr targetMethod;
if (implSlotNumber < pCur->NumVtableSlots)
......@@ -63,6 +68,15 @@ internal static unsafe class DispatchResolve
else
pCur = pCur->NonArrayBaseType;
}
// If we haven't found an implementation, do a second pass looking for a default implementation.
if (!fDoDefaultImplementationLookup)
{
fDoDefaultImplementationLookup = true;
pCur = pTgtType;
goto again;
}
return IntPtr.Zero;
}
......@@ -70,6 +84,7 @@ internal static unsafe class DispatchResolve
private static bool FindImplSlotForCurrentType(MethodTable* pTgtType,
MethodTable* pItfType,
ushort itfSlotNumber,
bool fDoDefaultImplementationLookup,
ushort* pImplSlotNumber)
{
bool fRes = false;
......@@ -87,17 +102,11 @@ internal static unsafe class DispatchResolve
if (pTgtType->HasDispatchMap)
{
// We first look at non-default implementation. Default implementations are only considered
// if the "old algorithm" didn't come up with an answer.
bool fDoDefaultImplementationLookup = false;
// For variant interface dispatch, the algorithm is to walk the parent hierarchy, and at each level
// attempt to dispatch exactly first, and then if that fails attempt to dispatch variantly. This can
// result in interesting behavior such as a derived type only overriding one particular instantiation
// and funneling all the dispatches to it, but its the algorithm.
again:
bool fDoVariantLookup = false; // do not check variance for first scan of dispatch map
fRes = FindImplSlotInSimpleMap(
......@@ -109,13 +118,6 @@ internal static unsafe class DispatchResolve
fRes = FindImplSlotInSimpleMap(
pTgtType, pItfType, itfSlotNumber, pImplSlotNumber, fDoVariantLookup, fDoDefaultImplementationLookup);
}
// If we haven't found anything and haven't looked at the default implementations yet, look now
if (!fRes && !fDoDefaultImplementationLookup)
{
fDoDefaultImplementationLookup = true;
goto again;
}
}
return fRes;
......
......@@ -495,6 +495,13 @@ interface IFoo<T>
class Foo<T> : IFoo<T> { }
class Base : IFoo
{
int IFoo.GetNumber() => 100;
}
class Derived : Base, IBar { }
public static void Run()
{
Console.WriteLine("Testing default interface methods...");
......@@ -508,6 +515,9 @@ public static void Run()
if (((IFoo)new Baz()).GetNumber() != 100)
throw new Exception();
if (((IFoo)new Derived()).GetNumber() != 100)
throw new Exception();
if (((IFoo<object>)new Foo<object>()).GetInterfaceType() != typeof(IFoo<object>))
throw new Exception();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册