-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Implement two pass algorithm for variant interface dispatch #21355
Implement two pass algorithm for variant interface dispatch #21355
Conversation
Cc @sergiy-k |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we covered the diamond case in discussion, but not the non-diamond case. Please add handling for non-diamond scenarios.
@@ -7323,6 +7347,11 @@ BOOL MethodTable::FindDefaultInterfaceImplementation( | |||
{ | |||
pBestCandidateMT = candidates[i].pMT; | |||
pBestCandidateMD = candidates[i].pMD; | |||
|
|||
// If this is a second pass lookup, we know this is a variant match. As such |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'm starting to understand some of the discussions from email in the last week or so. I don't see a problem with avoiding throwing in the diamond case where there are two most specific implementations, and I believe we should pick some implementation, but I do have a concern that we should be picking between the most specific implementations, not simply picking any possible implementation.
Imagine,
interface IFoo<in T> { string M() { return "IFoo:" + typeof(T).Name; } }
interface IRequiresImpInterface<in T> : IFoo<in T> { string IFoo<T>.M() { return "IRequiresImpInterface:" + typeof(T).Name; } }
class Base {}
class Derived : Base {}
class Test : IFoo<Base>, IRequiresImpInterface<Base>
{
static void Main()
{
var t = new Test();
((IFoo<Base>)t).M(); // Clearly calls IRequiresImpInterface<Base>.M()
((IFoo<Derived>)t).M(); // I think becomes order dependent in this implementation between calling IRequiresImpInterface<Base> and IFoo<Base> That doesn't seem right to me. I believe it should unambiguously call IRequiresImpInterface<Base>.M()
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also if that test above gets codified, it should have the cases in IL where class Test explicitly implements IRequiresImpInterface only, the case where it implements IFoo before IRequiresImpInterface, and the one where it implements IFoo after IRequiresImpInterface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AlekseyTs please chime in if you disagree.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. Only methods that implement interfaces that class explicitly claims to implement in metadata should be considered as candidates for variant interface dispatch. In the example above, method M in IFoo<Base>
doesn't implement any interface that class Test implements. IFoo<T>.M
in IRequiresImpInterface<Base>
implements method IFoo<Base>.M
for class Test. I assume implementations in base classes are handled similarly, i.e. only implementations from most derived bases are considered for variant interface dispatch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It already works that way. The loop that builds the list of candidates already kicks out those that are not most specific. In the second loop (where this comment is attached) we only go over the list of the most specific candidates to see which one is first (for the variant case) or which one is the only one that we came up with (or throw) for the non-variant case.
I've pushed out a commit that adds the test case from your comment to demonstrate we only consider the most specific ones. In that case, the variant dispatch is unambiguous because there's only one most specific implementation for it.
@dotnet-bot test this please |
@dotnet-bot test Ubuntu x64 Checked Innerloop Build and Test |
@dotnet-bot test this please |
@dotnet-bot test Ubuntu arm Cross Checked Innerloop Build and Test |
1 similar comment
@dotnet-bot test Ubuntu arm Cross Checked Innerloop Build and Test |
This keeps failing with weird Jenkinsonisms ( |
Seems like Jenkins is not going to give up to Azure DevOps without making our lives miserable for a bit more. @dotnet-bot test OSX10.12 x64 Checked Innerloop Build and Test |
@dotnet-bot test OSX10.12 x64 Checked Innerloop Build and Test |
1 similar comment
@dotnet-bot test OSX10.12 x64 Checked Innerloop Build and Test |
…oreclr#21355) Fixes dotnet/coreclr#20452. Commit migrated from dotnet/coreclr@1649da1
Fixes #20452.