-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Variant static interface dispatch crashes the runtime #78621
Comments
Fwiw, mono does the right thing. e.g. with blazorwasm net8.0 app, paste this code in
|
Cc @trylek @davidwrighton for static virtual bugs |
@lambdageek could you point me at the logic in Mono that is choosing a specific implementation. In particular, I see that @AlekseyTs Do you agree that this should throw at runtime with an |
Would we expect a different behavior from variant dispatch on instance default interface methods? If I change the above program to use instance methods (and pass a this) - program is at the bottom for posterity, I get:
IIRC we had a discussion about ambiguities in the variant cases for instance methods here dotnet/coreclr#21355 (comment) and over emails that I cannot find. This is all just repressed memories at this point. Click to expand the C# programusing System;
Console.WriteLine(GetTheFooString<FooBar, Base>(new FooBar()));
Console.WriteLine(GetTheFooString<FooBar, Mid>(new FooBar()));
Console.WriteLine(GetTheFooString<FooBar, Derived>(new FooBar()));
Console.WriteLine(GetTheBarString<FooBar, Base>(new FooBar()));
Console.WriteLine(GetTheBarString<FooBar, Mid>(new FooBar()));
Console.WriteLine(GetTheBarString<FooBar, Derived>(new FooBar()));
Console.WriteLine(GetTheFooString<FooBarBaz, Base>(new FooBarBaz()));
Console.WriteLine(GetTheFooString<FooBarBaz, Mid>(new FooBarBaz()));
Console.WriteLine(GetTheFooString<FooBarBaz, Derived>(new FooBarBaz()));
Console.WriteLine(GetTheBarString<FooBarBaz, Base>(new FooBarBaz()));
Console.WriteLine(GetTheBarString<FooBarBaz, Mid>(new FooBarBaz()));
Console.WriteLine(GetTheBarString<FooBarBaz, Derived>(new FooBarBaz()));
static string GetTheFooString<T, U>(T o) where T : IFoo<U> => o.GetString();
static string GetTheBarString<T, U>(T o) where T : IBar<U> => o.GetString();
interface IFoo<in T> { string GetString() => $"IFoo<{typeof(T).Name}>"; };
interface IBar<out T> { string GetString() => $"IBar<{typeof(T).Name}>"; };
class FooBar : IFoo<Base>, IBar<Derived> { }
interface IBaz : IFoo<Mid>, IBar<Mid>
{
string IFoo<Mid>.GetString() => "IBaz";
string IBar<Mid>.GetString() => "IBaz";
}
class FooBarBaz : FooBar, IBaz { }
class Base { }
class Mid : Base { }
class Derived : Mid { } |
I do not think I agree. Variance equivalence is not part of the most specific type rule. There is only one implementation of |
In general the code is I haven't traced this specific example to understand what Mono is doing, but it seems like the conflict map would mark at least some of the declarations as ambiguous. On the other hand the vtable will have some arbitrary implementation in there (probably in declaration order - but I haven't checked). I suspect the JIT-time check "are we calling a method declaration that has been marked as ambiguous" isn't working right for some of these cases so we end up with a call to whatever was left in the vtable. The other possibility is that we're not computing the ambiguous declarations correctly and so we don't consider that there are conflicts here. For the instance testcase from #78621 (comment)
note: The cases for |
Ok, so the universal agreement is that this should behave exactly like the instance case does, and that Mono disagrees with CoreCLR in what that exactly means. I'll flesh these test cases out, and make a final test case (that follows CoreCLR behavior, as it looks generally more correct to me than the Mono stuff(Especially as it is more likely customers have taken a dependency on CoreCLR behavior). Also, there is no mechanism for an ambiguous match to occur in this part of the code in CoreCLR, so I may put that in another test case. |
Sounds good - Mono is known to have differences in this area even prior to default/static interface methods (mono/mono#6312). |
… implementations (#88639) - Move the handling for variance so that it is in the same place as it is for instance methods - Validate the behavior of such dispatch is equivalent to the dispatch behavior involving instance variant default dispatch - Rework the fix for #80350 to avoid violating an invariant of the type system (which is that all MethodDef's of a TypeDef are loaded as MethodDescs when loading the open type). Fixes #78621
Expected
Doesn't crash
Actual
The text was updated successfully, but these errors were encountered: