-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix virtual static dispatch for variant interfaces when using default…
… 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
- Loading branch information
1 parent
83bf4b6
commit 57f691a
Showing
7 changed files
with
213 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
133 changes: 133 additions & 0 deletions
133
...sts/Loader/classloader/StaticVirtualMethods/InterfaceVariance/ComplexHierarchyPositive.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System; | ||
using System.Runtime; | ||
using Xunit; | ||
|
||
// This regression test tracks the issue where variant static interface dispatch crashes the runtime, and behaves incorrectly | ||
|
||
namespace VariantStaticInterfaceDispatchRegressionTest | ||
{ | ||
class Test | ||
{ | ||
static int Main() | ||
{ | ||
Console.WriteLine("Test cases"); | ||
|
||
Console.WriteLine("---FooBar"); | ||
TestTheFooString<FooBar, Base>("IFoo<Base>"); | ||
TestTheFooString<FooBar, Mid>("IFoo<Base>"); | ||
TestTheFooString<FooBar, Derived>("IFoo<Base>"); | ||
|
||
TestTheBarString<FooBar, Base>("IBar<Derived>"); | ||
TestTheBarString<FooBar, Mid>("IBar<Derived>"); | ||
TestTheBarString<FooBar, Derived>("IBar<Derived>"); | ||
|
||
Console.WriteLine("---FooBar2"); | ||
TestTheFooString<FooBar2, Base>("IFoo<Base>"); | ||
TestTheFooString<FooBar2, Mid>("IFoo<Mid>"); | ||
TestTheFooString<FooBar2, Derived>("IFoo<Base>"); | ||
|
||
TestTheBarString<FooBar2, Base>("IBar<Derived>"); | ||
TestTheBarString<FooBar2, Mid>("IBar<Mid>"); | ||
TestTheBarString<FooBar2, Derived>("IBar<Derived>"); | ||
|
||
Console.WriteLine("---FooBarBaz"); | ||
TestTheFooString<FooBarBaz, Base>("IFoo<Base>"); | ||
TestTheFooString<FooBarBaz, Mid>("IBaz"); | ||
TestTheFooString<FooBarBaz, Derived>("IBaz"); | ||
|
||
TestTheBarString<FooBarBaz, Base>("IBaz"); | ||
TestTheBarString<FooBarBaz, Mid>("IBaz"); | ||
TestTheBarString<FooBarBaz, Derived>("IBar<Derived>"); | ||
|
||
Console.WriteLine("---FooBarBazBoz"); | ||
TestTheFooString<FooBarBazBoz, Base>("IBoz"); | ||
TestTheFooString<FooBarBazBoz, Mid>("IBaz"); | ||
TestTheFooString<FooBarBazBoz, Derived>("IBoz"); | ||
|
||
TestTheBarString<FooBarBazBoz, Base>("IBoz"); | ||
TestTheBarString<FooBarBazBoz, Mid>("IBaz"); | ||
TestTheBarString<FooBarBazBoz, Derived>("IBoz"); | ||
|
||
Console.WriteLine("---FooBarBaz2"); | ||
TestTheFooString<FooBarBaz2, Base>("IFoo<Base>"); | ||
TestTheFooString<FooBarBaz2, Mid>("IBaz"); | ||
TestTheFooString<FooBarBaz2, Derived>("IFoo<Base>"); | ||
|
||
TestTheBarString<FooBarBaz2, Base>("IBar<Derived>"); | ||
TestTheBarString<FooBarBaz2, Mid>("IBaz"); | ||
TestTheBarString<FooBarBaz2, Derived>("IBar<Derived>"); | ||
|
||
Console.WriteLine("---FooBarBazBoz2"); | ||
TestTheFooString<FooBarBazBoz2, Base>("IBoz"); | ||
TestTheFooString<FooBarBazBoz2, Mid>("IBaz"); | ||
TestTheFooString<FooBarBazBoz2, Derived>("IBoz"); | ||
|
||
TestTheBarString<FooBarBazBoz2, Base>("IBoz"); | ||
TestTheBarString<FooBarBazBoz2, Mid>("IBaz"); | ||
TestTheBarString<FooBarBazBoz2, Derived>("IBoz"); | ||
return 100; | ||
} | ||
|
||
static string GetTheFooString<T, U>() where T : IFoo<U> { try { return T.GetString(); } catch (AmbiguousImplementationException) { return "AmbiguousImplementationException"; } } | ||
static string GetTheBarString<T, U>() where T : IBar<U> { try { return T.GetString(); } catch (AmbiguousImplementationException) { return "AmbiguousImplementationException"; } } | ||
static string GetTheFooStringInstance<T, U>() where T : IFoo<U>, new() { try { return (new T()).GetStringInstance(); } catch (AmbiguousImplementationException) { return "AmbiguousImplementationException"; } } | ||
static string GetTheBarStringInstance<T, U>() where T : IBar<U>, new() { try { return (new T()).GetStringInstance(); } catch (AmbiguousImplementationException) { return "AmbiguousImplementationException"; } } | ||
|
||
static void TestTheFooString<T, U>(string expected) where T : IFoo<U>, new() | ||
{ | ||
Console.WriteLine($"TestTheFooString {typeof(T).Name} {typeof(T).Name} {expected}"); | ||
Assert.Equal(expected, GetTheFooString<T, U>()); | ||
Assert.Equal(expected, GetTheFooStringInstance<T, U>()); | ||
} | ||
|
||
static void TestTheBarString<T, U>(string expected) where T : IBar<U>, new() | ||
{ | ||
Console.WriteLine($"TestTheBarString {typeof(T).Name} {typeof(T).Name} {expected}"); | ||
Assert.Equal(expected, GetTheBarString<T, U>()); | ||
Assert.Equal(expected, GetTheBarStringInstance<T, U>()); | ||
} | ||
|
||
interface IFoo<in T> | ||
{ | ||
static virtual string GetString() => $"IFoo<{typeof(T).Name}>"; | ||
virtual string GetStringInstance() => $"IFoo<{typeof(T).Name}>"; | ||
}; | ||
|
||
interface IBar<out T> | ||
{ | ||
static virtual string GetString() => $"IBar<{typeof(T).Name}>"; | ||
virtual string GetStringInstance() => $"IBar<{typeof(T).Name}>"; | ||
}; | ||
|
||
|
||
interface IBaz : IFoo<Mid>, IBar<Mid> | ||
{ | ||
static string IFoo<Mid>.GetString() => "IBaz"; | ||
static string IBar<Mid>.GetString() => "IBaz"; | ||
string IFoo<Mid>.GetStringInstance() => "IBaz"; | ||
string IBar<Mid>.GetStringInstance() => "IBaz"; | ||
} | ||
|
||
interface IBoz : IFoo<Base>, IBar<Derived> | ||
{ | ||
static string IFoo<Base>.GetString() => "IBoz"; | ||
static string IBar<Derived>.GetString() => "IBoz"; | ||
string IFoo<Base>.GetStringInstance() => "IBoz"; | ||
string IBar<Derived>.GetStringInstance() => "IBoz"; | ||
} | ||
|
||
class FooBar : IFoo<Base>, IBar<Derived> { } | ||
class FooBar2 : IFoo<Base>, IBar<Derived>, IFoo<Mid>, IBar<Mid> { } | ||
class FooBarBaz : FooBar, IBaz { } | ||
class FooBarBaz2 : IFoo<Base>, IBar<Derived>, IBaz { } // Implementation with all interfaces defined on the same type | ||
class FooBarBazBoz : FooBarBaz, IBoz { } | ||
class FooBarBazBoz2 : IFoo<Base>, IBar<Derived>, IBaz, IBoz { } // Implementation with all interfaces defined on the same type | ||
|
||
class Base { } | ||
class Mid : Base { } | ||
class Derived : Mid { } | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
...Loader/classloader/StaticVirtualMethods/InterfaceVariance/ComplexHierarchyPositive.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<PropertyGroup> | ||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||
<OutputType>Exe</OutputType> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<Compile Include="$(MSBuildProjectName).cs" /> | ||
</ItemGroup> | ||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters