Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Commit

Permalink
More update for default interface methods (#10818)
Browse files Browse the repository at this point in the history
* Support protected methods
* add a test for diamond shape scenario and tentatively throw exception when that happens
  • Loading branch information
yizhang82 authored and Yi Zhang committed May 23, 2017
1 parent c7ade77 commit 7961563
Show file tree
Hide file tree
Showing 7 changed files with 445 additions and 22 deletions.
34 changes: 25 additions & 9 deletions src/vm/clsload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6325,19 +6325,35 @@ BOOL ClassLoader::CanAccessFamily(
_ASSERTE(pCurrentClass);
_ASSERTE(pTargetClass);

BOOL bIsInterface = pTargetClass->IsInterface();

//Look to see if Current is a child of the Target.
while (pCurrentClass) {
MethodTable *pCurInstance = pCurrentClass;

while (pCurInstance) {
//This is correct. csc is incredibly lax about generics. Essentially if you are a subclass of
//any type of generic it lets you access it. Since the standard is totally unclear, mirror that
//behavior here.
if (pCurInstance->HasSameTypeDefAs(pTargetClass)) {
return TRUE;
if (bIsInterface)
{
// Calling a protected interface member
MethodTable::InterfaceMapIterator it = pCurrentClass->IterateInterfaceMap();
while (it.Next())
{
// We only loosely check if they are of the same generic type
if (it.GetInterface()->HasSameTypeDefAs(pTargetClass))
return TRUE;
}
}
else
{
MethodTable *pCurInstance = pCurrentClass;

while (pCurInstance) {
//This is correct. csc is incredibly lax about generics. Essentially if you are a subclass of
//any type of generic it lets you access it. Since the standard is totally unclear, mirror that
//behavior here.
if (pCurInstance->HasSameTypeDefAs(pTargetClass)) {
return TRUE;
}

pCurInstance = pCurInstance->GetParentMethodTable();
pCurInstance = pCurInstance->GetParentMethodTable();
}
}

///Looking at 8.5.3, it looks like a protected member of a nested class in a parent type is also
Expand Down
20 changes: 14 additions & 6 deletions src/vm/methodtable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7041,12 +7041,20 @@ BOOL MethodTable::FindDefaultMethod(
);
}

if (pBestCandidateMT == NULL || // first time
pCurMT->CanCastToInterface(pBestCandidateMT)) // Prefer "more specific"" interface
{
// This is a better match
pBestCandidateMT = pCurMT;
pBestCandidateMD = pCurMD;
if (pBestCandidateMT != pCurMT)
{
if (pBestCandidateMT == NULL || // first time
pCurMT->CanCastToInterface(pBestCandidateMT)) // Prefer "more specific"" interface
{
// This is a better match
pBestCandidateMT = pCurMT;
pBestCandidateMD = pCurMD;
}
else
{
// not good. we have a conflict
COMPlusThrow(kNotSupportedException);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
using System;

interface IFoo
{
int Foo(int a);
}

class IFoo_Impl
{
int Foo(int a)
{
return a;
}
}

interface IFoo2 : IFoo
{
}

class IFoo2_Impl : IFoo
{
int IFoo.Foo(int a)
{
Console.WriteLine("At IFoo2.Foo");
return a + 1;
}
}

interface IFooEx : IFoo
{
}

class IFooEx_Impl : IFoo
{
int IFoo.Foo(int a)
{
Console.WriteLine("At IFooEx.Foo");
return a + 2;
}
}

class FooClass : IFoo2, IFooEx
{
// Dummy
public int Foo(int a)
{
return 0;
}
}

class Program
{
public static int Main()
{
FooClass fooObj = new FooClass();
IFoo foo = (IFoo) fooObj;

Console.WriteLine("Calling IFoo.Foo on Foo - expecting exception.");
try
{
foo.Foo(10);
Test.Assert(false, "Expecting exception");
}
catch(Exception)
{
}

return Test.Ret();
}
}

class Test
{
private static bool Pass = true;

public static int Ret()
{
return Pass? 100 : 101;
}

public static void Assert(bool cond, string msg)
{
if (cond)
{
Console.WriteLine("PASS");
}
else
{
Console.WriteLine("FAIL: " + msg);
Pass = false;
}
}
}

Loading

0 comments on commit 7961563

Please sign in to comment.