summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Strehovský <MichalStrehovsky@users.noreply.github.com>2019-02-18 17:19:55 +0100
committerGitHub <noreply@github.com>2019-02-18 17:19:55 +0100
commit88249918cd01e8729c60c0f6c2cf8145d0bc3c55 (patch)
tree961be409e2b2dee0f722d5e62f7082a53355a65d
parenta8d58d62d1009b41e423923ba66a041a99bea7cc (diff)
downloadcoreclr-88249918cd01e8729c60c0f6c2cf8145d0bc3c55.tar.gz
coreclr-88249918cd01e8729c60c0f6c2cf8145d0bc3c55.tar.bz2
coreclr-88249918cd01e8729c60c0f6c2cf8145d0bc3c55.zip
Fix constrained call corner cases (#22464)
Fixes #22423. I'm still unclear on how JitStress manages to get itself into that situation, but I was able to write a repro that triggers the `!pMDAfterConstraintResolution->IsInterface()` assert using regular IL, so we need to handle that either way. The repro for that is constrained3.il. While figuring out the repro, I wrote a bunch of other test code and found another bug (constrained2), where we would box in a situations that doesn't require boxing (canonically ambiguous situation where there's a suitable default interface implementation and a valuetype implementation of the constrained method that does not requires boxing once we no longer deal with __Canon).
-rw-r--r--src/vm/jitinterface.cpp6
-rw-r--r--src/vm/methodtable.cpp2
-rw-r--r--tests/issues.targets3
-rw-r--r--tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2.il152
-rw-r--r--tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2.ilproj35
-rw-r--r--tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2_gm.il152
-rw-r--r--tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2_gm.ilproj35
-rw-r--r--tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained3.il66
-rw-r--r--tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained3.ilproj35
-rw-r--r--tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained3_gm.il66
-rw-r--r--tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained3_gm.ilproj35
-rw-r--r--tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.il39
12 files changed, 611 insertions, 15 deletions
diff --git a/src/vm/jitinterface.cpp b/src/vm/jitinterface.cpp
index 4df43fe86f..49d4857d9d 100644
--- a/src/vm/jitinterface.cpp
+++ b/src/vm/jitinterface.cpp
@@ -5269,7 +5269,11 @@ void CEEInfo::getCallInfo(
exactType,
pMD,
&fForceUseRuntimeLookup);
- if (directMethod)
+ if (directMethod
+#ifdef FEATURE_DEFAULT_INTERFACES
+ && !directMethod->IsInterface() /* Could be a default interface method implementation */
+#endif
+ )
{
// Either
// 1. no constraint resolution at compile time (!directMethod)
diff --git a/src/vm/methodtable.cpp b/src/vm/methodtable.cpp
index f434a39fc6..0589cb28ce 100644
--- a/src/vm/methodtable.cpp
+++ b/src/vm/methodtable.cpp
@@ -9844,7 +9844,7 @@ MethodTable::TryResolveConstraintMethodApprox(
pMD = pCanonMT->GetMethodDescForInterfaceMethod(thPotentialInterfaceType, pGenInterfaceMD, FALSE /* throwOnConflict */);
// See code:#TryResolveConstraintMethodApprox_DoNotReturnParentMethod
- if ((pMD != NULL) && !pMD->GetMethodTable()->IsValueType())
+ if ((pMD != NULL) && !pMD->GetMethodTable()->IsValueType() && !pMD->IsInterface())
{
LOG((LF_JIT, LL_INFO10000, "TryResolveConstraintMethodApprox: %s::%s not a value type method\n",
pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName));
diff --git a/tests/issues.targets b/tests/issues.targets
index 20edc17032..5c43c0566d 100644
--- a/tests/issues.targets
+++ b/tests/issues.targets
@@ -72,9 +72,6 @@
<ExcludeList Include="$(XunitTestBinBase)/Interop/ExecInDefAppDom/ExecInDefAppDom/*">
<Issue>Issue building native components for the test.</Issue>
</ExcludeList>
- <ExcludeList Include="$(XunitTestBinBase)/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall/*">
- <Issue>22423</Issue>
- </ExcludeList>
</ItemGroup>
<!-- Arm32 All OS -->
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2.il b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2.il
new file mode 100644
index 0000000000..ad63b215c9
--- /dev/null
+++ b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2.il
@@ -0,0 +1,152 @@
+// 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.
+
+.assembly extern mscorlib { }
+.assembly constrained2 { }
+
+.class interface private abstract auto ansi IAdder`1<T>
+{
+ .method public hidebysig newslot abstract virtual instance int32 Add(int32)
+ {
+ }
+
+ .method public hidebysig newslot virtual instance int32 PlusPlus()
+ {
+ ldstr "IAdder`1<T>:PlusPlus"
+ call void [mscorlib]System.Console::WriteLine(string)
+
+ ldarg.0
+ ldc.i4.1
+ callvirt instance int32 class IAdder`1<!0>::Add(int32)
+ ret
+ }
+}
+
+.class value Adder`1<T> implements class IAdder`1<!T>, class IAdder`1<class [mscorlib]System.String>
+{
+ .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<System.String>.PlusPlus'()
+ {
+ .override method instance int32 class IAdder`1<class [mscorlib]System.String>::PlusPlus()
+
+ ldstr "Adder`1<T>:'IAdder<System.String>.PlusPlus'"
+ call void [mscorlib]System.Console::WriteLine(string)
+
+ ldarg.0
+ ldc.i4.2
+ call instance int32 valuetype Adder`1<!T>::Add(int32)
+ ret
+ }
+}
+
+.method public hidebysig static int32 Check<(class IAdder`1<!!U>, class IAdder`1<string>) T,U>(!!T t)
+{
+ // 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<string>::PlusPlus()
+ ldarga.s 0
+ constrained. !!T
+ callvirt instance int32 class IAdder`1<string>::PlusPlus()
+ add
+
+ 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
+
+ add
+
+ ret
+}
+
+.method public hidebysig static int32 Main()
+{
+ .entrypoint
+
+ .locals init (
+ valuetype Adder`1<object>,
+ int32
+ )
+
+ // This will end up calling the implementation of IAdder<string>.PlusPlus
+ // provided by the Adder valuetype.
+ // The sum returned by the Check method will be 2+4+6+8 = 20.
+ ldloc.0
+ call int32 Check<valuetype Adder`1<object>,string>(!!0)
+ ldc.i4 20
+ ceq
+ brtrue String_OK
+
+ ldc.i4 1
+ ret
+
+String_OK:
+
+ // This will end up calling the implementation of IAdder<object>.PlusPlus
+ // provided by the default interface method.
+ // The sum returned by the Check method will be 1+1+2+4 = 8.
+
+ // This requires a runtime that can generate boxing stubs. We will support
+ // both the case when this is not supported, and when it's implemented.
+ ldc.i4.8
+ stloc.1
+
+ .try
+ {
+ ldloca 0
+ initobj valuetype Adder`1<object>
+ ldloc.0
+ call int32 Check<valuetype Adder`1<object>,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 8
+ ceq
+ brtrue Object_OK
+
+ ldc.i4.2
+ ret
+
+Object_OK:
+
+ ldc.i4 100
+ ret
+}
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2.ilproj b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2.ilproj
new file mode 100644
index 0000000000..217eeadb2e
--- /dev/null
+++ b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2.ilproj
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <AssemblyName>constrained2</AssemblyName>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <ReferenceLocalMscorlib>true</ReferenceLocalMscorlib>
+ <OutputType>Exe</OutputType>
+ <CLRTestKind>BuildAndRun</CLRTestKind>
+ <CLRTestPriority>0</CLRTestPriority>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+
+ <ItemGroup>
+ <Compile Include="constrained2.il" />
+ </ItemGroup>
+
+
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2_gm.il b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2_gm.il
new file mode 100644
index 0000000000..119b893b8a
--- /dev/null
+++ b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2_gm.il
@@ -0,0 +1,152 @@
+// 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.
+
+.assembly extern mscorlib { }
+.assembly constrained2_gm { }
+
+.class interface private abstract auto ansi IAdder`1<T>
+{
+ .method public hidebysig newslot abstract virtual instance int32 Add<U>(int32)
+ {
+ }
+
+ .method public hidebysig newslot virtual instance int32 PlusPlus<U>()
+ {
+ ldstr "IAdder`1<T>:PlusPlus"
+ call void [mscorlib]System.Console::WriteLine(string)
+
+ ldarg.0
+ ldc.i4.1
+ callvirt instance int32 class IAdder`1<!0>::Add<!!0>(int32)
+ ret
+ }
+}
+
+.class value Adder`1<T> implements class IAdder`1<!T>, class IAdder`1<class [mscorlib]System.String>
+{
+ .field private int32 _field
+
+ .method public hidebysig newslot virtual instance int32 Add<U>(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<System.String>.PlusPlus'<U>()
+ {
+ .override class IAdder`1<class [mscorlib]System.String>::PlusPlus
+
+ ldstr "Adder`1<T>:'IAdder<System.String>.PlusPlus'"
+ call void [mscorlib]System.Console::WriteLine(string)
+
+ ldarg.0
+ ldc.i4.2
+ call instance int32 valuetype Adder`1<!T>::Add<!!U>(int32)
+ ret
+ }
+}
+
+.method public hidebysig static int32 Check<(class IAdder`1<!!U>, class IAdder`1<string>) T,U>(!!T t)
+{
+ // 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<string>::PlusPlus<object>()
+ ldarga.s 0
+ constrained. !!T
+ callvirt instance int32 class IAdder`1<string>::PlusPlus<object>()
+ add
+
+ ldarga.s 0
+ constrained. !!T
+ callvirt instance int32 class IAdder`1<!!U>::PlusPlus<object>()
+ ldarga.s 0
+ constrained. !!T
+ callvirt instance int32 class IAdder`1<!!U>::PlusPlus<object>()
+ add
+
+ add
+
+ ret
+}
+
+.method public hidebysig static int32 Main()
+{
+ .entrypoint
+
+ .locals init (
+ valuetype Adder`1<object>,
+ int32
+ )
+
+ // This will end up calling the implementation of IAdder<string>.PlusPlus
+ // provided by the Adder valuetype.
+ // The sum returned by the Check method will be 2+4+6+8 = 20.
+ ldloc.0
+ call int32 Check<valuetype Adder`1<object>,string>(!!0)
+ ldc.i4 20
+ ceq
+ brtrue String_OK
+
+ ldc.i4 1
+ ret
+
+String_OK:
+
+ // This will end up calling the implementation of IAdder<object>.PlusPlus
+ // provided by the default interface method.
+ // The sum returned by the Check method will be 1+1+2+4 = 8.
+
+ // This requires a runtime that can generate boxing stubs. We will support
+ // both the case when this is not supported, and when it's implemented.
+ ldc.i4.8
+ stloc.1
+
+ .try
+ {
+ ldloca 0
+ initobj valuetype Adder`1<object>
+ ldloc.0
+ call int32 Check<valuetype Adder`1<object>,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 8
+ ceq
+ brtrue Object_OK
+
+ ldc.i4.2
+ ret
+
+Object_OK:
+
+ ldc.i4 100
+ ret
+}
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2_gm.ilproj b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2_gm.ilproj
new file mode 100644
index 0000000000..fbe067087d
--- /dev/null
+++ b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2_gm.ilproj
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <AssemblyName>constrained2_gm</AssemblyName>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <ReferenceLocalMscorlib>true</ReferenceLocalMscorlib>
+ <OutputType>Exe</OutputType>
+ <CLRTestKind>BuildAndRun</CLRTestKind>
+ <CLRTestPriority>0</CLRTestPriority>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+
+ <ItemGroup>
+ <Compile Include="constrained2_gm.il" />
+ </ItemGroup>
+
+
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained3.il b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained3.il
new file mode 100644
index 0000000000..a09f0829e1
--- /dev/null
+++ b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained3.il
@@ -0,0 +1,66 @@
+// 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.
+
+.assembly extern mscorlib { }
+.assembly constrained3 { }
+
+.class interface private abstract auto ansi IFrobber`1<T>
+{
+ .method public hidebysig newslot virtual instance int32 Frob()
+ {
+ ldstr "IFrobber<T>:Frob"
+ call void [mscorlib]System.Console::WriteLine(string)
+
+ ldc.i4 34
+ ret
+ }
+}
+
+.class interface private abstract auto ansi IRobber`1<T> implements class IFrobber`1<!T>
+{
+ .method public hidebysig final newslot virtual instance int32 Frob()
+ {
+ .override class IFrobber`1<!T>::Frob
+ ldstr "IRobber<T>:Frob"
+ call void [mscorlib]System.Console::WriteLine(string)
+ ldc.i4 66
+ ret
+ }
+}
+
+.class interface private abstract auto ansi IGrabber`1<T> implements class IFrobber`1<!T>
+{
+ .method public hidebysig final newslot virtual instance int32 Frob()
+ {
+ .override class IFrobber`1<!T>::Frob
+ ldstr "IGrabber<T>:Frob"
+ call void [mscorlib]System.Console::WriteLine(string)
+ ldc.i4.3
+ ret
+ }
+}
+
+.class value Adder`1<T, U> implements class IFrobber`1<!T>, class IRobber`1<!U>, class IGrabber`1<!U[]>
+{
+}
+
+.method public hidebysig static int32 Main()
+{
+ .entrypoint
+
+ .locals init (
+ valuetype Adder`1<object, string>
+ )
+
+ ldloca.s 0
+ constrained. valuetype Adder`1<object, string>
+ callvirt instance int32 class IFrobber`1<object>::Frob()
+
+ ldloca.s 0
+ constrained. valuetype Adder`1<object, string>
+ callvirt instance int32 class IFrobber`1<string>::Frob()
+ add
+
+ ret
+}
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained3.ilproj b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained3.ilproj
new file mode 100644
index 0000000000..e4114047d7
--- /dev/null
+++ b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained3.ilproj
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <AssemblyName>constrained3</AssemblyName>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <ReferenceLocalMscorlib>true</ReferenceLocalMscorlib>
+ <OutputType>Exe</OutputType>
+ <CLRTestKind>BuildAndRun</CLRTestKind>
+ <CLRTestPriority>0</CLRTestPriority>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+
+ <ItemGroup>
+ <Compile Include="constrained3.il" />
+ </ItemGroup>
+
+
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained3_gm.il b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained3_gm.il
new file mode 100644
index 0000000000..f9132bcc66
--- /dev/null
+++ b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained3_gm.il
@@ -0,0 +1,66 @@
+// 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.
+
+.assembly extern mscorlib { }
+.assembly constrained3_gm { }
+
+.class interface private abstract auto ansi IFrobber`1<T>
+{
+ .method public hidebysig newslot virtual instance int32 Frob<U>()
+ {
+ ldstr "IFrobber<T>:Frob"
+ call void [mscorlib]System.Console::WriteLine(string)
+
+ ldc.i4 34
+ ret
+ }
+}
+
+.class interface private abstract auto ansi IRobber`1<T> implements class IFrobber`1<!T>
+{
+ .method public hidebysig final newslot virtual instance int32 Frob<U>()
+ {
+ .override class IFrobber`1<!T>::Frob
+ ldstr "IRobber<T>:Frob"
+ call void [mscorlib]System.Console::WriteLine(string)
+ ldc.i4 66
+ ret
+ }
+}
+
+.class interface private abstract auto ansi IGrabber`1<T> implements class IFrobber`1<!T>
+{
+ .method public hidebysig final newslot virtual instance int32 Frob<U>()
+ {
+ .override class IFrobber`1<!T>::Frob
+ ldstr "IGrabber<T>:Frob"
+ call void [mscorlib]System.Console::WriteLine(string)
+ ldc.i4.3
+ ret
+ }
+}
+
+.class value Adder`1<T, U> implements class IFrobber`1<!T>, class IRobber`1<!U>, class IGrabber`1<!U[]>
+{
+}
+
+.method public hidebysig static int32 Main()
+{
+ .entrypoint
+
+ .locals init (
+ valuetype Adder`1<object, string>
+ )
+
+ ldloca.s 0
+ constrained. valuetype Adder`1<object, string>
+ callvirt instance int32 class IFrobber`1<object>::Frob<object>()
+
+ ldloca.s 0
+ constrained. valuetype Adder`1<object, string>
+ callvirt instance int32 class IFrobber`1<string>::Frob<object>()
+ add
+
+ ret
+}
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained3_gm.ilproj b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained3_gm.ilproj
new file mode 100644
index 0000000000..51ed579143
--- /dev/null
+++ b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained3_gm.ilproj
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <AssemblyName>constrained3_gm</AssemblyName>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <ReferenceLocalMscorlib>true</ReferenceLocalMscorlib>
+ <OutputType>Exe</OutputType>
+ <CLRTestKind>BuildAndRun</CLRTestKind>
+ <CLRTestPriority>0</CLRTestPriority>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+
+ <ItemGroup>
+ <Compile Include="constrained3_gm.il" />
+ </ItemGroup>
+
+
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.il b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.il
index 47d51eeed2..f5f46a5522 100644
--- a/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.il
+++ b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.il
@@ -14,7 +14,7 @@
.method public hidebysig newslot virtual instance int32 PlusPlus()
{
ldarg.0
- ldc.i4.0
+ ldc.i4.1
callvirt instance int32 class IAdder`1<!0>::Add(int32)
ret
}
@@ -23,8 +23,9 @@
.class interface IGen1`1<T> { }
.class interface IGen2`1<T> { }
.class interface IGen3`1<T> { }
+.class value Atom { }
-.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>>
+.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>>, class IAdder`1<valuetype Atom>
{
.field private int32 _field
@@ -45,7 +46,7 @@
{
.override method instance int32 class IAdder`1<class IGen1`1<!T>>::PlusPlus()
ldarg.0
- ldc.i4.1
+ ldc.i4.2
call instance int32 valuetype Adder`1<!T>::Add(int32)
ret
}
@@ -54,7 +55,7 @@
{
.override method instance int32 class IAdder`1<class IGen2`1<!T>>::PlusPlus()
ldarg.0
- ldc.i4.2
+ ldc.i4.3
call instance int32 valuetype Adder`1<!T>::Add(int32)
ret
}
@@ -82,15 +83,16 @@
.locals init (
valuetype Adder`1<object>,
- int32
+ int32,
+ valuetype Adder`1<valuetype Atom>
)
// 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.
+ // The sum returned by the Check method will be 2+4 = 6.
ldloc.0
call int32 Check<valuetype Adder`1<object>,class IGen1`1<object>>(!!0)
- ldc.i4.3
+ ldc.i4.6
ceq
brtrue IGen1_OK
@@ -101,12 +103,12 @@ 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.
+ // The sum returned by the Check method will be 3+6 = 9.
ldloca 0
initobj valuetype Adder`1<object>
ldloc.0
call int32 Check<valuetype Adder`1<object>,class IGen2`1<object>>(!!0)
- ldc.i4.6
+ ldc.i4 9
ceq
brtrue IGen2_OK
@@ -156,12 +158,29 @@ AfterBoxingCall:
ldloc.1
ldc.i4.2
ceq
- brtrue AllOK
+ brtrue IGen3_OK
ldc.i4.3
ret
+IGen3_OK:
+
+ ldloca 0
+ initobj valuetype Adder`1<valuetype Atom>
+
+ ldloc.0
+ call int32 Check<valuetype Adder`1<valuetype Atom>,valuetype Atom>(!!0)
+ ldc.i4 2
+ ceq
+ brtrue AllOK
+
+ ldc.i4.4
+ ret
+
AllOK:
+ ldstr "Compile time constraint resolution to default interface method OK"
+ call void [mscorlib]System.Console::WriteLine(string)
+
ldc.i4 100
ret
}