未验证 提交 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 ...@@ -30,11 +30,16 @@ internal static unsafe class DispatchResolve
if (pItfType->IsCloned) if (pItfType->IsCloned)
pItfType = pItfType->CanonicalEEType; 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) while (pCur != null)
{ {
ushort implSlotNumber; ushort implSlotNumber;
if (FindImplSlotForCurrentType( if (FindImplSlotForCurrentType(
pCur, pItfType, itfSlotNumber, &implSlotNumber)) pCur, pItfType, itfSlotNumber, fDoDefaultImplementationLookup, &implSlotNumber))
{ {
IntPtr targetMethod; IntPtr targetMethod;
if (implSlotNumber < pCur->NumVtableSlots) if (implSlotNumber < pCur->NumVtableSlots)
...@@ -63,6 +68,15 @@ internal static unsafe class DispatchResolve ...@@ -63,6 +68,15 @@ internal static unsafe class DispatchResolve
else else
pCur = pCur->NonArrayBaseType; 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; return IntPtr.Zero;
} }
...@@ -70,6 +84,7 @@ internal static unsafe class DispatchResolve ...@@ -70,6 +84,7 @@ internal static unsafe class DispatchResolve
private static bool FindImplSlotForCurrentType(MethodTable* pTgtType, private static bool FindImplSlotForCurrentType(MethodTable* pTgtType,
MethodTable* pItfType, MethodTable* pItfType,
ushort itfSlotNumber, ushort itfSlotNumber,
bool fDoDefaultImplementationLookup,
ushort* pImplSlotNumber) ushort* pImplSlotNumber)
{ {
bool fRes = false; bool fRes = false;
...@@ -87,17 +102,11 @@ internal static unsafe class DispatchResolve ...@@ -87,17 +102,11 @@ internal static unsafe class DispatchResolve
if (pTgtType->HasDispatchMap) 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 // 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 // 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 // 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. // 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 bool fDoVariantLookup = false; // do not check variance for first scan of dispatch map
fRes = FindImplSlotInSimpleMap( fRes = FindImplSlotInSimpleMap(
...@@ -109,13 +118,6 @@ internal static unsafe class DispatchResolve ...@@ -109,13 +118,6 @@ internal static unsafe class DispatchResolve
fRes = FindImplSlotInSimpleMap( fRes = FindImplSlotInSimpleMap(
pTgtType, pItfType, itfSlotNumber, pImplSlotNumber, fDoVariantLookup, fDoDefaultImplementationLookup); 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; return fRes;
......
...@@ -495,6 +495,13 @@ interface IFoo<T> ...@@ -495,6 +495,13 @@ interface IFoo<T>
class Foo<T> : IFoo<T> { } class Foo<T> : IFoo<T> { }
class Base : IFoo
{
int IFoo.GetNumber() => 100;
}
class Derived : Base, IBar { }
public static void Run() public static void Run()
{ {
Console.WriteLine("Testing default interface methods..."); Console.WriteLine("Testing default interface methods...");
...@@ -508,6 +515,9 @@ public static void Run() ...@@ -508,6 +515,9 @@ public static void Run()
if (((IFoo)new Baz()).GetNumber() != 100) if (((IFoo)new Baz()).GetNumber() != 100)
throw new Exception(); throw new Exception();
if (((IFoo)new Derived()).GetNumber() != 100)
throw new Exception();
if (((IFoo<object>)new Foo<object>()).GetInterfaceType() != typeof(IFoo<object>)) if (((IFoo<object>)new Foo<object>()).GetInterfaceType() != typeof(IFoo<object>))
throw new Exception(); throw new Exception();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册