summaryrefslogtreecommitdiff
path: root/tests/src/reflection
diff options
context:
space:
mode:
authorMichal Strehovský <MichalStrehovsky@users.noreply.github.com>2019-04-08 13:14:39 +0200
committerGitHub <noreply@github.com>2019-04-08 13:14:39 +0200
commit24c92a5939002ecbadefbc5f93c2c8cc371d8b72 (patch)
treee846057269d2774850af5baa75cb1b3edf7cf8aa /tests/src/reflection
parent67e8c9ba99ea32339e2df59d9615a88851fa6dc7 (diff)
downloadcoreclr-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')
-rw-r--r--tests/src/reflection/DefaultInterfaceMethods/Emit.cs64
-rw-r--r--tests/src/reflection/DefaultInterfaceMethods/GetInterfaceMapConsumer.cs78
-rw-r--r--tests/src/reflection/DefaultInterfaceMethods/GetInterfaceMapProvider.il49
-rw-r--r--tests/src/reflection/DefaultInterfaceMethods/InvokeConsumer.cs9
-rw-r--r--tests/src/reflection/DefaultInterfaceMethods/InvokeProvider.il21
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>