diff options
-rw-r--r-- | src/dlls/mscorrc/mscorrc.rc | 1 | ||||
-rw-r--r-- | src/dlls/mscorrc/resource.h | 1 | ||||
-rw-r--r-- | src/vm/genericdict.cpp | 31 | ||||
-rw-r--r-- | tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.cs | 189 | ||||
-rw-r--r-- | tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.il | 590 |
5 files changed, 182 insertions, 630 deletions
diff --git a/src/dlls/mscorrc/mscorrc.rc b/src/dlls/mscorrc/mscorrc.rc index 59aa7c338f..f3244218f9 100644 --- a/src/dlls/mscorrc/mscorrc.rc +++ b/src/dlls/mscorrc/mscorrc.rc @@ -761,6 +761,7 @@ BEGIN IDS_CLASSLOAD_MI_BAD_SIG "Type '%1' from assembly '%2' contains an invalid method implementation signature." IDS_CLASSLOAD_MI_FINAL_IMPL "Method implementation on an interface '%1' from assembly '%2' must be a final method." IDS_CLASSLOAD_AMBIGUOUS_OVERRIDE "Could not call method '%1' on interface '%2' with type '%3' from assembly '%4' because there are multiple incompatible interface methods overriding this method." + IDS_CLASSLOAD_UNSUPPORTED_DISPATCH "Could not make constrained call to method '%1' on interface '%2' with type '%3' from assembly '%4'. Dispatch to default interface methods is not supported in this situation." IDS_CLASSLOAD_MISSINGMETHODRVA "Could not load type '%1' from assembly '%2' because the method '%3' has no implementation (no RVA)." SECURITY_E_INCOMPATIBLE_EVIDENCE "Assembly '%1' already loaded without additional security evidence." diff --git a/src/dlls/mscorrc/resource.h b/src/dlls/mscorrc/resource.h index 735f315c33..1b71333385 100644 --- a/src/dlls/mscorrc/resource.h +++ b/src/dlls/mscorrc/resource.h @@ -466,6 +466,7 @@ #define IDS_EE_HWINTRINSIC_NGEN_DISALLOWED 0x1ac7 #define IDS_CLASSLOAD_MI_FINAL_IMPL 0x1ac8 #define IDS_CLASSLOAD_AMBIGUOUS_OVERRIDE 0x1ac9 +#define IDS_CLASSLOAD_UNSUPPORTED_DISPATCH 0x1aca #define BFA_INVALID_TOKEN_TYPE 0x2001 #define BFA_INVALID_TOKEN 0x2003 diff --git a/src/vm/genericdict.cpp b/src/vm/genericdict.cpp index 906f5c57fa..90af6395d7 100644 --- a/src/vm/genericdict.cpp +++ b/src/vm/genericdict.cpp @@ -1120,6 +1120,37 @@ Dictionary::PopulateEntry( if (!pResolvedMD) COMPlusThrowHR(COR_E_BADIMAGEFORMAT); +#if FEATURE_DEFAULT_INTERFACES + // If we resolved the constrained call on a value type into a method on a reference type, this is a + // default interface method implementation. + // In such case we would need to box the value type before we can dispatch to the implementation. + // This would require us to make a "boxing stub". For now we leave the boxing stubs unimplemented. + // It's not clear if anyone would need them and the implementation complexity is not worth it at this time. + if (!pResolvedMD->GetMethodTable()->IsValueType() && constraintType.GetMethodTable()->IsValueType()) + { + SString assemblyName; + + constraintType.GetMethodTable()->GetAssembly()->GetDisplayName(assemblyName); + + SString strInterfaceName; + TypeString::AppendType(strInterfaceName, ownerType); + + SString strMethodName; + TypeString::AppendMethod(strMethodName, pMethod, pMethod->GetMethodInstantiation()); + + SString strTargetClassName; + TypeString::AppendType(strTargetClassName, constraintType.GetMethodTable()); + + COMPlusThrow( + kNotSupportedException, + IDS_CLASSLOAD_UNSUPPORTED_DISPATCH, + strMethodName, + strInterfaceName, + strTargetClassName, + assemblyName); + } +#endif + result = (CORINFO_GENERIC_HANDLE)pResolvedMD->GetMultiCallableAddrOfCode(); } else diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.cs b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.cs deleted file mode 100644 index 3f3d1153ee..0000000000 --- a/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.cs +++ /dev/null @@ -1,189 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Generic; - -interface IFoo -{ - int Foo(int c); -} - -interface IAdd -{ - int Add(int c); -} - -// Only needed for writing IFoo.Foo code -class IFoo_Impl : IFoo -{ - public int Foo(int c) - { - IAdd adder = (IAdd) this; - return adder.Add(c); - } -} - -struct FooValue : IFoo, IAdd -{ - public int val; - - public int Foo(int c) - { - val +=c; - return val; - } - - public int Add(int c) - { - val +=c; - return val; - } -} - -interface IHorrible<T> -{ - int GetLocalVal(); - void SetLocalVal(int val); - int Horrible(); -} - -// Only needed for the default interface implementation -class IHorrible_Impl<T> : IHorrible<T> -{ - public int GetLocalVal() { return 0; } - public void SetLocalVal(int val) {} - public int Horrible() - { - int val = GetLocalVal(); - val++; - SetLocalVal(val); - return val; - } -} - -struct HorribleCase<Z> : IHorrible<IList<Z>>, IHorrible<IEnumerable<Z>> -{ - int localVal; - public int GetLocalVal() { return localVal; } - public void SetLocalVal(int val) { localVal = val; } - int IHorrible<IList<Z>>.Horrible() { return ++localVal; } - - // Remove - int IHorrible<IEnumerable<Z>>.Horrible() { return ++localVal; } -} - -class HorribleTest -{ - public static int Horror<T,U>(T t) where T:IHorrible<U> - { - return t.Horrible() + t.Horrible(); - } - - public static void RunTest() - { - Test.Assert(Horror<HorribleCase<object>,IEnumerable<object>>(new HorribleCase<object>())) == 2, "Fail"); - Test.Assert(Horror<HorribleCase<object>,IList<object>>(default(HorribleCase<object>)) == 3, "Fail"); - } -} - -/* -interface IFoo<T> -{ - int Foo(int c); -} - -interface IAdd -{ - int Add(int c); -} - -// Only needed for writing IFoo.Foo code -class IFoo_Impl<T> : IFoo<T> -{ - public int Foo(int c) - { - IAdd adder = (IAdd) this; - return adder.Add(c); - } -} - -struct FooValue<T> : IFoo<T>, IAdd -{ - public int val; - - public int Foo(int c) - { - val +=c; - return val; - } - - public int Add(int c) - { - val +=c; - return val; - } -} -*/ - -class SimpleConstraintTest -{ - public static int CallFoo_WithConstraints<T>(ref T foo, int val) where T : IFoo - { - return foo.Foo(val); - } - - /* - public static int CallFoo_WithConstraints<T>(ref T foo, int val) where T : IFoo<object> - { - return foo.Foo(val); - } - */ - - public static void RunTest() - { - FooValue foo = new FooValue(); - foo.val = 10; - - Console.WriteLine("Calling CallFoo_WithConstraints on FooValue - expecting IFoo::Foo"); - Test.Assert(CallFoo_WithConstraints(ref foo, 10) == 20, "Calling CallFoo_WithConstraints on FooValue"); - - Test.Assert(foo.val == 10, "Expecting boxing on CallFoo_WithConstraints"); - } -} - -class Program -{ - public static int Main() - { - HorribleTest.RunTest(); - SimpleConstraintTest.RunTest(); - - return Test.Ret(); - } -} - -class Test -{ - private static bool Pass = true; - - public static int Ret() - { - return Pass? 100 : 101; - } - - public static void Assert(bool cond, string msg) - { - if (cond) - { - Console.WriteLine("PASS"); - } - else - { - Console.WriteLine("FAIL: " + msg); - Pass = false; - } - } -} - diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.il b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.il index 6e2ca954be..47d51eeed2 100644 --- a/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.il +++ b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.il @@ -2,458 +2,166 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.1055.0 -// Copyright (c) Microsoft Corporation. All rights reserved. +.assembly extern mscorlib { } +.assembly constrainedcall { } - - -// Metadata version: v4.0.30319 -.assembly extern mscorlib -{ - .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. - .ver 4:0:0:0 -} -.assembly constrainedcall -{ - .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) - .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx - 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows. - - // --- The following custom attribute is added automatically, do not uncomment ------- - // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) - - .hash algorithm 0x00008004 - .ver 0:0:0:0 -} -.module constrainedcall.exe -// MVID: {6171EA0F-1009-482D-8EF6-C944886D5D66} -.imagebase 0x00400000 -.file alignment 0x00000200 -.stackreserve 0x00100000 -.subsystem 0x0003 // WINDOWS_CUI -.corflags 0x00000001 // ILONLY -// Image base: 0x01860000 - - -// =============== CLASS MEMBERS DECLARATION =================== - -.class interface private abstract auto ansi IFoo -{ - .method public hidebysig newslot virtual - instance int32 Foo(int32 c) cil managed - { - // Code size 20 (0x14) - .maxstack 2 - .locals init (class IAdd V_0, - int32 V_1) - IL_0000: nop - IL_0001: ldarg.0 - IL_0002: castclass IAdd - IL_0007: stloc.0 - IL_0008: ldloc.0 - IL_0009: ldarg.1 - IL_000a: callvirt instance int32 IAdd::Add(int32) - IL_000f: stloc.1 - IL_0010: br.s IL_0012 - - IL_0012: ldloc.1 - IL_0013: ret - } // end of method IFoo::Foo - -} // end of class IFoo - -.class interface private abstract auto ansi IAdd +.class interface private abstract auto ansi IAdder`1<T> { - .method public hidebysig newslot abstract virtual - instance int32 Add(int32 c) cil managed + .method public hidebysig newslot abstract virtual instance int32 Add(int32) { - } // end of method IAdd::Add - -} // end of class IAdd + } -.class private sequential ansi sealed beforefieldinit FooValue - extends [mscorlib]System.ValueType - implements IFoo, - IAdd -{ - .field public int32 val - - .method public hidebysig newslot virtual final - instance int32 Add(int32 c) cil managed + .method public hidebysig newslot virtual instance int32 PlusPlus() { - // Code size 26 (0x1a) - .maxstack 3 - .locals init (int32 V_0) - IL_0000: nop - IL_0001: ldarg.0 - IL_0002: ldarg.0 - IL_0003: ldfld int32 FooValue::val - IL_0008: ldarg.1 - IL_0009: add - IL_000a: stfld int32 FooValue::val - IL_000f: ldarg.0 - IL_0010: ldfld int32 FooValue::val - IL_0015: stloc.0 - IL_0016: br.s IL_0018 - - IL_0018: ldloc.0 - IL_0019: ret - } // end of method FooValue::Add - -} // end of class FooValue - -.class interface private abstract auto ansi IHorrible`1<T> -{ - .method public hidebysig newslot abstract virtual - instance int32 GetLocalVal() cil managed - { - } // end of method IHorrible`1::GetLocalVal - - .method public hidebysig newslot abstract virtual - instance void SetLocalVal(int32 val) cil managed - { - } // end of method IHorrible`1::SetLocalVal - - .method public hidebysig newslot virtual - instance int32 Horrible() cil managed - { - // Code size 26 (0x1a) - .maxstack 2 - .locals init (int32 V_0, - int32 V_1) - IL_0000: nop - IL_0001: ldarg.0 - IL_0002: callvirt instance int32 class IHorrible`1<!T>::GetLocalVal() - IL_0007: stloc.0 - IL_0008: ldloc.0 - IL_0009: ldc.i4.1 - IL_000a: add - IL_000b: stloc.0 - IL_000c: ldarg.0 - IL_000d: ldloc.0 - IL_000e: callvirt instance void class IHorrible`1<!T>::SetLocalVal(int32) - IL_0013: nop - IL_0014: ldloc.0 - IL_0015: stloc.1 - IL_0016: br.s IL_0018 - - IL_0018: ldloc.1 - IL_0019: ret - } // end of method IHorrible`1::Horrible - -} // end of class IHorrible`1 - -.class private sequential ansi sealed beforefieldinit HorribleCase`1<Z> - extends [mscorlib]System.ValueType - implements class IHorrible`1<class [mscorlib]System.Collections.Generic.IList`1<!Z>>, - class IHorrible`1<class [mscorlib]System.Collections.Generic.IEnumerable`1<!Z>> -{ - .field private int32 localVal - .method public hidebysig newslot virtual final - instance int32 GetLocalVal() cil managed - { - // Code size 12 (0xc) - .maxstack 1 - .locals init (int32 V_0) - IL_0000: nop - IL_0001: ldarg.0 - IL_0002: ldfld int32 valuetype HorribleCase`1<!Z>::localVal - IL_0007: stloc.0 - IL_0008: br.s IL_000a - - IL_000a: ldloc.0 - IL_000b: ret - } // end of method HorribleCase`1::GetLocalVal - - .method public hidebysig newslot virtual final - instance void SetLocalVal(int32 val) cil managed - { - // Code size 9 (0x9) - .maxstack 8 - IL_0000: nop - IL_0001: ldarg.0 - IL_0002: ldarg.1 - IL_0003: stfld int32 valuetype HorribleCase`1<!Z>::localVal - IL_0008: ret - } // end of method HorribleCase`1::SetLocalVal - - .method private hidebysig newslot virtual final - instance int32 'IHorrible<System.Collections.Generic.IList<Z>>.Horrible'() cil managed - { - .override method instance int32 class IHorrible`1<class [mscorlib]System.Collections.Generic.IList`1<!Z>>::Horrible() - // Code size 23 (0x17) - .maxstack 3 - .locals init (int32 V_0, - int32 V_1) - IL_0000: nop - IL_0001: ldarg.0 - IL_0002: ldarg.0 - IL_0003: ldfld int32 valuetype HorribleCase`1<!Z>::localVal - IL_0008: ldc.i4.1 - IL_0009: add - IL_000a: stloc.0 - IL_000b: ldloc.0 - IL_000c: stfld int32 valuetype HorribleCase`1<!Z>::localVal - IL_0011: ldloc.0 - IL_0012: stloc.1 - IL_0013: br.s IL_0015 + ldarg.0 + ldc.i4.0 + callvirt instance int32 class IAdder`1<!0>::Add(int32) + ret + } +} - IL_0015: ldloc.1 - IL_0016: ret - } // end of method HorribleCase`1::'IHorrible<System.Collections.Generic.IList<Z>>.Horrible' -} // end of class HorribleCase`1 +.class interface IGen1`1<T> { } +.class interface IGen2`1<T> { } +.class interface IGen3`1<T> { } -.class private auto ansi beforefieldinit HorribleTest - extends [mscorlib]System.Object +.class value Adder`1<T> implements class IAdder`1<class IGen1`1<!T>>, class IAdder`1<class IGen2`1<!T>>, class IAdder`1<class IGen3`1<!T>> { - .method public hidebysig static int32 Horror<(class IHorrible`1<!!U>) T,U>(!!T t) cil managed - { - // Code size 33 (0x21) - .maxstack 2 - .locals init (int32 V_0) - IL_0000: nop - IL_0001: ldarga.s t - IL_0003: constrained. !!T - IL_0009: callvirt instance int32 class IHorrible`1<!!U>::Horrible() - IL_000e: ldarga.s t - IL_0010: constrained. !!T - IL_0016: callvirt instance int32 class IHorrible`1<!!U>::Horrible() - IL_001b: add - IL_001c: stloc.0 - IL_001d: br.s IL_001f - - IL_001f: ldloc.0 - IL_0020: ret - } // end of method HorribleTest::Horror - - .method public hidebysig static void RunTest() cil managed - { - // Code size 58 (0x3a) - .maxstack 2 - .locals init (valuetype HorribleCase`1<object> V_0) - IL_0000: nop - IL_0001: ldloca.s V_0 - IL_0003: initobj valuetype HorribleCase`1<object> - IL_0009: ldloc.0 - IL_000a: call int32 HorribleTest::Horror<valuetype HorribleCase`1<object>,class [mscorlib]System.Collections.Generic.IEnumerable`1<object>>(!!0) - IL_000f: ldc.i4.3 - IL_0010: ceq - IL_0012: ldstr "Fail" - IL_0017: call void Test::Assert(bool, - string) - IL_001c: nop - IL_001d: ldloca.s V_0 - IL_001f: initobj valuetype HorribleCase`1<object> - IL_0025: ldloc.0 - IL_0026: call int32 HorribleTest::Horror<valuetype HorribleCase`1<object>,class [mscorlib]System.Collections.Generic.IList`1<object>>(!!0) - IL_002b: ldc.i4.0 - IL_002c: ceq - IL_002e: ldstr "Fail" - IL_0033: call void Test::Assert(bool, - string) - IL_0038: nop - IL_0039: ret - } // end of method HorribleTest::RunTest - - .method public hidebysig specialname rtspecialname - instance void .ctor() cil managed - { - // Code size 8 (0x8) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void [mscorlib]System.Object::.ctor() - IL_0006: nop - IL_0007: ret - } // end of method HorribleTest::.ctor - -} // end of class HorribleTest + .field private int32 _field + + .method public hidebysig newslot virtual instance int32 Add(int32) cil managed + { + ldarg.0 + dup + ldfld int32 valuetype Adder`1<!T>::_field + ldarg.1 + add + stfld int32 valuetype Adder`1<!T>::_field + ldarg.0 + ldfld int32 valuetype Adder`1<!T>::_field + ret + } + + .method private hidebysig newslot virtual instance int32 'IAdder<IGen1<T>>.PlusPlus'() + { + .override method instance int32 class IAdder`1<class IGen1`1<!T>>::PlusPlus() + ldarg.0 + ldc.i4.1 + call instance int32 valuetype Adder`1<!T>::Add(int32) + ret + } + + .method private hidebysig newslot virtual instance int32 'IAdder<IGen2<T>>.PlusPlus'() + { + .override method instance int32 class IAdder`1<class IGen2`1<!T>>::PlusPlus() + ldarg.0 + ldc.i4.2 + call instance int32 valuetype Adder`1<!T>::Add(int32) + ret + } +} -.class private auto ansi beforefieldinit SimpleConstraintTest - extends [mscorlib]System.Object +.method public hidebysig static int32 Check<(class IAdder`1<!!U>) T,U>(!!T t) { - .method public hidebysig static int32 CallFoo_WithConstraints<(IFoo) T>(!!T& foo, - int32 val) cil managed - { - // Code size 19 (0x13) - .maxstack 2 - .locals init (int32 V_0) - IL_0000: nop - IL_0001: ldarg.0 - IL_0002: ldarg.1 - IL_0003: constrained. !!T - IL_0009: callvirt instance int32 IFoo::Foo(int32) - IL_000e: stloc.0 - IL_000f: br.s IL_0011 - - IL_0011: ldloc.0 - IL_0012: ret - } // end of method SimpleConstraintTest::CallFoo_WithConstraints - - .method public hidebysig static void RunTest() cil managed - { - // Code size 75 (0x4b) - .maxstack 2 - .locals init (valuetype FooValue V_0) - IL_0000: nop - IL_0001: ldloca.s V_0 - IL_0003: initobj FooValue - IL_0009: ldloca.s V_0 - IL_000b: ldc.i4.s 10 - IL_000d: stfld int32 FooValue::val - IL_0012: ldstr "Calling CallFoo_WithConstraints on FooValue - expe" - + "cting IFoo::Foo" - IL_0017: call void [mscorlib]System.Console::WriteLine(string) - IL_001c: nop - IL_001d: ldloca.s V_0 - IL_001f: ldc.i4.s 10 - IL_0021: call int32 SimpleConstraintTest::CallFoo_WithConstraints<valuetype FooValue>(!!0&, - int32) - IL_0026: ldc.i4.s 20 - IL_0028: ceq - IL_002a: ldstr "Calling CallFoo_WithConstraints on FooValue" - IL_002f: call void Test::Assert(bool, - string) - IL_0034: nop - IL_0035: ldloc.0 - IL_0036: ldfld int32 FooValue::val - IL_003b: ldc.i4.s 10 - IL_003d: ceq - IL_003f: ldstr "Expecting boxing on CallFoo_WithConstraints" - IL_0044: call void Test::Assert(bool, - string) - IL_0049: nop - IL_004a: ret - } // end of method SimpleConstraintTest::RunTest - - .method public hidebysig specialname rtspecialname - instance void .ctor() cil managed - { - // Code size 8 (0x8) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void [mscorlib]System.Object::.ctor() - IL_0006: nop - IL_0007: ret - } // end of method SimpleConstraintTest::.ctor - -} // end of class SimpleConstraintTest + // The constrained calls below may or may not box for a valuetype T + // depending on whether IAdder`1<!!U>::PlusPlus() ends up calling + // the default implementation of the interface method. + + ldarga.s 0 + constrained. !!T + callvirt instance int32 class IAdder`1<!!U>::PlusPlus() + ldarga.s 0 + constrained. !!T + callvirt instance int32 class IAdder`1<!!U>::PlusPlus() + add + ret +} -.class private auto ansi beforefieldinit Program - extends [mscorlib]System.Object +.method public hidebysig static int32 Main() { - .method public hidebysig static int32 Main() cil managed - { .entrypoint - // Code size 23 (0x17) - .maxstack 1 - .locals init (int32 V_0) - IL_0000: nop - IL_0001: call void HorribleTest::RunTest() - IL_0006: nop - IL_0007: call void SimpleConstraintTest::RunTest() - IL_000c: nop - IL_000d: call int32 Test::Ret() - IL_0012: stloc.0 - IL_0013: br.s IL_0015 - - IL_0015: ldloc.0 - IL_0016: ret - } // end of method Program::Main - - .method public hidebysig specialname rtspecialname - instance void .ctor() cil managed - { - // Code size 8 (0x8) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void [mscorlib]System.Object::.ctor() - IL_0006: nop - IL_0007: ret - } // end of method Program::.ctor -} // end of class Program - -.class private auto ansi beforefieldinit Test - extends [mscorlib]System.Object -{ - .field private static bool Pass - .method public hidebysig static int32 Ret() cil managed - { - // Code size 19 (0x13) - .maxstack 1 - .locals init (int32 V_0) - IL_0000: nop - IL_0001: ldsfld bool Test::Pass - IL_0006: brtrue.s IL_000c - - IL_0008: ldc.i4.s 101 - IL_000a: br.s IL_000e - - IL_000c: ldc.i4.s 100 - IL_000e: stloc.0 - IL_000f: br.s IL_0011 - - IL_0011: ldloc.0 - IL_0012: ret - } // end of method Test::Ret - - .method public hidebysig static void Assert(bool cond, - string msg) cil managed - { - // Code size 47 (0x2f) - .maxstack 2 - .locals init (bool V_0) - IL_0000: nop - IL_0001: ldarg.0 - IL_0002: stloc.0 - IL_0003: ldloc.0 - IL_0004: brfalse.s IL_0015 - - IL_0006: nop - IL_0007: ldstr "PASS" - IL_000c: call void [mscorlib]System.Console::WriteLine(string) - IL_0011: nop - IL_0012: nop - IL_0013: br.s IL_002e - - IL_0015: nop - IL_0016: ldstr "FAIL: " - IL_001b: ldarg.1 - IL_001c: call string [mscorlib]System.String::Concat(string, - string) - IL_0021: call void [mscorlib]System.Console::WriteLine(string) - IL_0026: nop - IL_0027: ldc.i4.0 - IL_0028: stsfld bool Test::Pass - IL_002d: nop - IL_002e: ret - } // end of method Test::Assert - - .method public hidebysig specialname rtspecialname - instance void .ctor() cil managed - { - // Code size 8 (0x8) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void [mscorlib]System.Object::.ctor() - IL_0006: nop - IL_0007: ret - } // end of method Test::.ctor - - .method private hidebysig specialname rtspecialname static - void .cctor() cil managed - { - // Code size 7 (0x7) - .maxstack 8 - IL_0000: ldc.i4.1 - IL_0001: stsfld bool Test::Pass - IL_0006: ret - } // end of method Test::.cctor - -} // end of class Test - - -// ============================================================= - -// *********** DISASSEMBLY COMPLETE *********************** -// WARNING: Created Win32 resource file constrainedcall.res + .locals init ( + valuetype Adder`1<object>, + int32 + ) + + // This will end up calling the implementation of IAdder<IGen1<object>>.PlusPlus + // provided by the Adder valuetype. + // The sum returned by the Check method will be 1+2 = 3. + ldloc.0 + call int32 Check<valuetype Adder`1<object>,class IGen1`1<object>>(!!0) + ldc.i4.3 + ceq + brtrue IGen1_OK + + ldc.i4.1 + ret + +IGen1_OK: + + // This will end up calling the implementation of IAdder<IGen2<object>>.PlusPlus + // provided by the Adder valuetype. + // The sum returned by the Check method will be 2+4 = 6. + ldloca 0 + initobj valuetype Adder`1<object> + ldloc.0 + call int32 Check<valuetype Adder`1<object>,class IGen2`1<object>>(!!0) + ldc.i4.6 + ceq + brtrue IGen2_OK + + ldc.i4.2 + ret + +IGen2_OK: + + ldstr "Constrained calls that require runtime lookup are OK" + call void [mscorlib]System.Console::WriteLine(string) + + + // Store a successful result in case the implementation throws. + // We consider both a throw and a successful dispatch a success. + // The throwing behavior is an implementation limitation. + // Successful dispatch is what the spec mandates. + ldc.i4.2 + stloc.1 + + ldloca 0 + initobj valuetype Adder`1<object> + + // This will end up calling the default implementation of IAdder<IGen3<object>>.PlusPlus + // Since each constrained call in Check is going to box, the sum will end up 1+1 = 2. + .try + { + ldloc.0 + call int32 Check<valuetype Adder`1<object>,class IGen3`1<object>>(!!0) + stloc.1 + + ldstr "Runtime supports lookups with runtime determined boxing" + call void [mscorlib]System.Console::WriteLine(string) + + leave AfterBoxingCall + } + catch [mscorlib]System.Exception + { + pop + leave AfterFailedBoxingCall + } + +AfterFailedBoxingCall: + ldstr "Runtime does not support lookups with runtime determined boxing" + call void [mscorlib]System.Console::WriteLine(string) + +AfterBoxingCall: + ldloc.1 + ldc.i4.2 + ceq + brtrue AllOK + + ldc.i4.3 + ret + +AllOK: + ldc.i4 100 + ret +} |