diff options
author | Michal Strehovský <MichalStrehovsky@users.noreply.github.com> | 2019-04-08 13:14:39 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-08 13:14:39 +0200 |
commit | 24c92a5939002ecbadefbc5f93c2c8cc371d8b72 (patch) | |
tree | e846057269d2774850af5baa75cb1b3edf7cf8aa /tests/src/reflection | |
parent | 67e8c9ba99ea32339e2df59d9615a88851fa6dc7 (diff) | |
download | coreclr-24c92a5939002ecbadefbc5f93c2c8cc371d8b72.tar.gz coreclr-24c92a5939002ecbadefbc5f93c2c8cc371d8b72.tar.bz2 coreclr-24c92a5939002ecbadefbc5f93c2c8cc371d8b72.zip |
Allow reabstraction of default interface methods (#23313)
Allow the runtime to load types with incomplete interface implementations. With this change, we allow (in pseudo-C#):
```csharp
interface IFoo { void Frob() { } }
interface IBar : IFoo { abstract void IFoo.Frob() }
class Fooer : IBar { }
```
Calling IFoo.Frob on an instance of `Fooer` will result in new exception being thrown because the default implementation of `IFoo.Frob` was re-abstracted by `IBar`.
Diffstat (limited to 'tests/src/reflection')
5 files changed, 213 insertions, 8 deletions
diff --git a/tests/src/reflection/DefaultInterfaceMethods/Emit.cs b/tests/src/reflection/DefaultInterfaceMethods/Emit.cs index e57f7c1f6f..4cd872ad64 100644 --- a/tests/src/reflection/DefaultInterfaceMethods/Emit.cs +++ b/tests/src/reflection/DefaultInterfaceMethods/Emit.cs @@ -73,14 +73,66 @@ class Program // Test what we created // - object o = Activator.CreateInstance(fooType); - int result = 0; - result |= (int)ifooType.GetMethod("InstanceMethod").Invoke(o, null); - result |= (int)ifooType.GetMethod("DefaultMethod").Invoke(o, null); - result |= (int)ifooType.GetMethod("InterfaceMethod").Invoke(o, null); + { + object o = Activator.CreateInstance(fooType); + + result |= (int)ifooType.GetMethod("InstanceMethod").Invoke(o, null); + result |= (int)ifooType.GetMethod("DefaultMethod").Invoke(o, null); + result |= (int)ifooType.GetMethod("InterfaceMethod").Invoke(o, null); + } + + // + // Set up the IBaz interface + // + + var ibazType = modb.DefineType("IBaz", TypeAttributes.Interface | TypeAttributes.Abstract | TypeAttributes.Public, null, new Type[] { ifooType }); + + // Override the default interface method on IFoo with a reabstraction + { + var mb = ibazType.DefineMethod("DefaultMethodImpl", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Final | MethodAttributes.Abstract, typeof(int), Type.EmptyTypes); + ibazType.DefineMethodOverride(mb, ifooType.GetMethod("DefaultMethod")); + } + + // Override the regular interface method on IFoo with a reabstraction + { + var mb = ibazType.DefineMethod("InterfaceMethodImpl", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Final | MethodAttributes.Abstract, typeof(int), Type.EmptyTypes); + ibazType.DefineMethodOverride(mb, ifooType.GetMethod("InterfaceMethod")); + } + + ibazType.CreateTypeInfo(); + + // + // Make a simple Baz class that implements IBaz + // + + var bazType = modb.DefineType("Baz", TypeAttributes.Class | TypeAttributes.Public, typeof(object), new Type[] { ibazType }); + + bazType.CreateTypeInfo(); + + { + object o = Activator.CreateInstance(bazType); + + try + { + ifooType.GetMethod("DefaultMethod").Invoke(o, null); + } + catch (EntryPointNotFoundException) + { + result |= 0x10; + } + + try + { + ifooType.GetMethod("InterfaceMethod").Invoke(o, null); + } + catch (EntryPointNotFoundException) + { + result |= 0x20; + } + } - return result == 0x07 ? 100 : result; + return result == 0x37 ? 100 : result; } } diff --git a/tests/src/reflection/DefaultInterfaceMethods/GetInterfaceMapConsumer.cs b/tests/src/reflection/DefaultInterfaceMethods/GetInterfaceMapConsumer.cs index ecb6373291..845cf49005 100644 --- a/tests/src/reflection/DefaultInterfaceMethods/GetInterfaceMapConsumer.cs +++ b/tests/src/reflection/DefaultInterfaceMethods/GetInterfaceMapConsumer.cs @@ -85,12 +85,86 @@ class Program return 10; } + + { + var map = typeof(Reabstractor).GetInterfaceMap(typeof(IFoo)); + + int foundMatchMask = 0; + + MethodInfo ifooDefaultMethod = typeof(IFoo).GetMethod("DefaultMethod"); + MethodInfo ifooOtherMethod = typeof(IFoo).GetMethod("OtherMethod"); + + for (int i = 0; i < map.InterfaceMethods.Length; i++) + { + MethodInfo declMethod = map.InterfaceMethods[i]; + MethodInfo implMethod = map.TargetMethods[i]; + + Console.Write("{0} ({1}) - {2} ({3}) - ", declMethod, declMethod.DeclaringType, implMethod, implMethod?.DeclaringType); + + if (declMethod.Equals(ifooDefaultMethod)) + { + foundMatchMask |= 1; + CheckEqual(ref failed, implMethod, null); + } + else if (declMethod.Equals(ifooOtherMethod)) + { + foundMatchMask |= 2; + CheckEqual(ref failed, implMethod, null); + } + else + { + Console.WriteLine("UNEXPECTED"); + failed = true; + } + } + + if (foundMatchMask != 3) + return 10; + } + + { + var map = typeof(Diamond).GetInterfaceMap(typeof(IFoo)); + + int foundMatchMask = 0; + + MethodInfo ifooDefaultMethod = typeof(IFoo).GetMethod("DefaultMethod"); + MethodInfo ifooOtherMethod = typeof(IFoo).GetMethod("OtherMethod"); + + for (int i = 0; i < map.InterfaceMethods.Length; i++) + { + MethodInfo declMethod = map.InterfaceMethods[i]; + MethodInfo implMethod = map.TargetMethods[i]; + + Console.Write("{0} ({1}) - {2} ({3}) - ", declMethod, declMethod.DeclaringType, implMethod, implMethod?.DeclaringType); + + if (declMethod.Equals(ifooDefaultMethod)) + { + foundMatchMask |= 1; + CheckEqual(ref failed, implMethod, ifooDefaultMethod); + } + else if (declMethod.Equals(ifooOtherMethod)) + { + foundMatchMask |= 2; + CheckEqual(ref failed, implMethod, null); + } + else + { + Console.WriteLine("UNEXPECTED"); + failed = true; + } + } + + if (foundMatchMask != 3) + return 10; + } + + return failed ? -1 : 100; } static void CheckEqual(ref bool failed, MethodInfo method1, MethodInfo method2) { - if (method1.Equals(method2)) + if (Object.Equals(method1, method2)) Console.WriteLine("OK"); else { @@ -98,4 +172,4 @@ class Program failed = true; } } -}
\ No newline at end of file +} diff --git a/tests/src/reflection/DefaultInterfaceMethods/GetInterfaceMapProvider.il b/tests/src/reflection/DefaultInterfaceMethods/GetInterfaceMapProvider.il index 03785988e0..9ad1a7db4f 100644 --- a/tests/src/reflection/DefaultInterfaceMethods/GetInterfaceMapProvider.il +++ b/tests/src/reflection/DefaultInterfaceMethods/GetInterfaceMapProvider.il @@ -43,6 +43,29 @@ } } +.class interface public abstract auto ansi IBaz implements IFoo +{ + .method public hidebysig newslot virtual final instance int32 OtherMethod(int32) cil managed + { + .override IFoo::OtherMethod + ldarg.1 + ret + } +} + +.class interface public abstract auto ansi IReabstractor implements IFoo +{ + .method public hidebysig newslot abstract virtual final instance int32 DefaultMethod(int32) cil managed + { + .override IFoo::DefaultMethod + } + + .method public hidebysig newslot abstract virtual final instance int32 OtherMethod(int32) cil managed + { + .override IFoo::OtherMethod + } +} + .class interface public abstract auto ansi IFoo`1<T> { .method public hidebysig newslot virtual instance valuetype [mscorlib]System.RuntimeTypeHandle DefaultMethod() cil managed @@ -79,3 +102,29 @@ ret } } + +.class public auto ansi beforefieldinit Reabstractor + extends [mscorlib]System.Object + implements IReabstractor +{ + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } +} + +.class public auto ansi beforefieldinit Diamond + extends [mscorlib]System.Object + implements IBar, IBaz +{ + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } +} diff --git a/tests/src/reflection/DefaultInterfaceMethods/InvokeConsumer.cs b/tests/src/reflection/DefaultInterfaceMethods/InvokeConsumer.cs index 4ac82f9a1b..247b830b24 100644 --- a/tests/src/reflection/DefaultInterfaceMethods/InvokeConsumer.cs +++ b/tests/src/reflection/DefaultInterfaceMethods/InvokeConsumer.cs @@ -38,6 +38,15 @@ class Program if (!((RuntimeTypeHandle)typeof(IFoo<Fooer>).GetMethod("InstanceMethod").Invoke(new ValueFooer(), new object[] { })).Equals(typeof(Fooer[]).TypeHandle)) return 33; + try + { + typeof(IFoo).GetMethod("DefaultMethod").Invoke(new Reabstractor(), new object[] { 1 }); + return 501; + } + catch (EntryPointNotFoundException) + { + } + return 100; } } diff --git a/tests/src/reflection/DefaultInterfaceMethods/InvokeProvider.il b/tests/src/reflection/DefaultInterfaceMethods/InvokeProvider.il index d1f6e73af8..4c43089571 100644 --- a/tests/src/reflection/DefaultInterfaceMethods/InvokeProvider.il +++ b/tests/src/reflection/DefaultInterfaceMethods/InvokeProvider.il @@ -33,6 +33,14 @@ } } +.class interface public abstract auto ansi IReabstractor implements IFoo +{ + .method public hidebysig newslot virtual abstract final instance int32 DefaultMethod(int32) cil managed + { + .override IFoo::DefaultMethod + } +} + .class interface public abstract auto ansi IFoo`1<T> { .method public hidebysig newslot virtual instance valuetype [mscorlib]System.RuntimeTypeHandle DefaultMethod() cil managed @@ -67,6 +75,19 @@ } } +.class public auto ansi beforefieldinit Reabstractor + extends [mscorlib]System.Object + implements IReabstractor +{ + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } +} + .class public sequential ansi sealed beforefieldinit ValueFooer extends [mscorlib]System.ValueType implements IFoo, class IFoo`1<class Fooer> |