summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dlls/mscorrc/mscorrc.rc1
-rw-r--r--src/dlls/mscorrc/resource.h1
-rw-r--r--src/vm/genericdict.cpp31
-rw-r--r--tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.cs189
-rw-r--r--tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.il590
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
+}