diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs
index c55d468a4d4c8e..f93c101788f5ea 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs
@@ -547,6 +547,11 @@ public static unsafe IntPtr ResolveStaticDispatchOnType(RuntimeTypeHandle instan
return result;
}
+ public static unsafe IntPtr ResolveDispatchOnType(RuntimeTypeHandle instanceType, RuntimeTypeHandle interfaceType, int slot)
+ {
+ return RuntimeImports.RhResolveDispatchOnType(instanceType.ToMethodTable(), interfaceType.ToMethodTable(), checked((ushort)slot));
+ }
+
public static bool IsUnmanagedPointerType(RuntimeTypeHandle typeHandle)
{
return typeHandle.ToMethodTable()->IsPointer;
diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/GenericDictionaryCell.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/GenericDictionaryCell.cs
index eb911d4037afde..c630754b50bb5f 100644
--- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/GenericDictionaryCell.cs
+++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/GenericDictionaryCell.cs
@@ -140,10 +140,41 @@ internal override IntPtr Create(TypeBuilder builder)
}
}
+ ///
+ /// Used for non-generic instance constrained Methods
+ ///
+ private class NonGenericInstanceConstrainedMethodCell : GenericDictionaryCell
+ {
+ internal TypeDesc ConstraintType;
+ internal TypeDesc ConstrainedMethodType;
+ internal int ConstrainedMethodSlot;
+
+ internal override void Prepare(TypeBuilder builder)
+ {
+ if (ConstraintType.IsCanonicalSubtype(CanonicalFormKind.Any) || ConstrainedMethodType.IsCanonicalSubtype(CanonicalFormKind.Any))
+ Environment.FailFast("Unable to compute call information for a canonical type/method.");
+
+ builder.RegisterForPreparation(ConstraintType);
+ builder.RegisterForPreparation(ConstrainedMethodType);
+ }
+
+ internal override IntPtr Create(TypeBuilder builder)
+ {
+ IntPtr result = RuntimeAugments.ResolveDispatchOnType(
+ builder.GetRuntimeTypeHandle(ConstraintType),
+ builder.GetRuntimeTypeHandle(ConstrainedMethodType),
+ ConstrainedMethodSlot);
+
+ Debug.Assert(result != IntPtr.Zero);
+
+ return result;
+ }
+ }
+
///
/// Used for generic static constrained Methods
///
- private class GenericStaticConstrainedMethodCell : GenericDictionaryCell
+ private class GenericConstrainedMethodCell : GenericDictionaryCell
{
internal DefType ConstraintType;
internal InstantiatedMethod ConstrainedMethod;
@@ -512,29 +543,45 @@ internal static GenericDictionaryCell ParseAndCreateCell(NativeLayoutInfoLoadCon
break;
case FixupSignatureKind.NonGenericStaticConstrainedMethod:
- {
+ case FixupSignatureKind.NonGenericInstanceConstrainedMethod:
+ {
var constraintType = nativeLayoutInfoLoadContext.GetType(ref parser);
var constrainedMethodType = nativeLayoutInfoLoadContext.GetType(ref parser);
var constrainedMethodSlot = parser.GetUnsigned();
- TypeLoaderLogger.WriteLine("NonGenericStaticConstrainedMethod: " + constraintType.ToString() + " Method " + constrainedMethodType.ToString() + ", slot #" + constrainedMethodSlot.LowLevelToString());
- cell = new NonGenericStaticConstrainedMethodCell()
+ string kindString = kind == FixupSignatureKind.NonGenericStaticConstrainedMethod ? "NonGenericStaticConstrainedMethod: " : "NonGenericInstanceConstrainedMethod: ";
+
+ TypeLoaderLogger.WriteLine(kindString + constraintType.ToString() + " Method " + constrainedMethodType.ToString() + ", slot #" + constrainedMethodSlot.LowLevelToString());
+
+ if (kind == FixupSignatureKind.NonGenericStaticConstrainedMethod)
{
- ConstraintType = constraintType,
- ConstrainedMethodType = constrainedMethodType,
- ConstrainedMethodSlot = (int)constrainedMethodSlot
- };
+ cell = new NonGenericStaticConstrainedMethodCell()
+ {
+ ConstraintType = constraintType,
+ ConstrainedMethodType = constrainedMethodType,
+ ConstrainedMethodSlot = (int)constrainedMethodSlot
+ };
+ }
+ else
+ {
+ cell = new NonGenericInstanceConstrainedMethodCell()
+ {
+ ConstraintType = constraintType,
+ ConstrainedMethodType = constrainedMethodType,
+ ConstrainedMethodSlot = (int)constrainedMethodSlot
+ };
+ }
}
break;
- case FixupSignatureKind.GenericStaticConstrainedMethod:
- {
+ case FixupSignatureKind.GenericConstrainedMethod:
+ {
TypeDesc constraintType = nativeLayoutInfoLoadContext.GetType(ref parser);
MethodDesc constrainedMethod = nativeLayoutInfoLoadContext.GetMethod(ref parser);
- TypeLoaderLogger.WriteLine("GenericStaticConstrainedMethod: " + constraintType.ToString() + " Method " + constrainedMethod.ToString());
+ TypeLoaderLogger.WriteLine("GenericConstrainedMethod: " + constraintType.ToString() + " Method " + constrainedMethod.ToString());
- cell = new GenericStaticConstrainedMethodCell()
+ cell = new GenericConstrainedMethodCell()
{
ConstraintType = (DefType)constraintType,
ConstrainedMethod = (InstantiatedMethod)constrainedMethod,
diff --git a/src/coreclr/tools/Common/Compiler/TypeExtensions.cs b/src/coreclr/tools/Common/Compiler/TypeExtensions.cs
index ac69f6872a6b75..9b655d00578dcd 100644
--- a/src/coreclr/tools/Common/Compiler/TypeExtensions.cs
+++ b/src/coreclr/tools/Common/Compiler/TypeExtensions.cs
@@ -469,7 +469,9 @@ public static MethodDesc TryResolveConstraintMethodApprox(this TypeDesc constrai
potentialInterfaceMethod.GetTypicalMethodDefinition(), (InstantiatedType)potentialInterfaceType);
}
- method = canonType.ResolveInterfaceMethodToVirtualMethodOnType(potentialInterfaceMethod);
+ method = canonType.ResolveInterfaceMethodToVirtualMethodOnType(potentialInterfaceMethod)
+ // Do not lose track of `method` if we were able to resolve it previously
+ ?? method;
// See code:#TryResolveConstraintMethodApprox_DoNotReturnParentMethod
if (method != null && !method.OwningType.IsValueType)
diff --git a/src/coreclr/tools/Common/Internal/NativeFormat/NativeFormat.cs b/src/coreclr/tools/Common/Internal/NativeFormat/NativeFormat.cs
index dbe629602172b5..7962ee0a15d29a 100644
--- a/src/coreclr/tools/Common/Internal/NativeFormat/NativeFormat.cs
+++ b/src/coreclr/tools/Common/Internal/NativeFormat/NativeFormat.cs
@@ -98,9 +98,9 @@ enum FixupSignatureKind : uint
// unused = 0x17,
// unused = 0x18,
// unused = 0x19,
- // unused = 0x20,
+ NonGenericInstanceConstrainedMethod = 0x20,
NonGenericStaticConstrainedMethod = 0x21,
- GenericStaticConstrainedMethod = 0x22,
+ GenericConstrainedMethod = 0x22,
NotYetSupported = 0xee,
}
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs
index 5f05fdeb9f4703..f0eae5441d0c28 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs
@@ -936,8 +936,6 @@ public override DefaultInterfaceMethodResolution ResolveVariantInterfaceMethodTo
public static DefaultInterfaceMethodResolution ResolveVariantInterfaceMethodToDefaultImplementationOnType(MethodDesc interfaceMethod, MetadataType currentType, out MethodDesc impl)
{
- Debug.Assert(interfaceMethod.Signature.IsStatic);
-
MetadataType interfaceType = (MetadataType)interfaceMethod.OwningType;
bool foundInterface = IsInterfaceImplementedOnType(currentType, interfaceType);
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericLookupResult.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericLookupResult.cs
index 49cf52b524c69a..ac646f21778964 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericLookupResult.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericLookupResult.cs
@@ -901,30 +901,38 @@ public override ISymbolNode GetTarget(NodeFactory factory, GenericLookupResultCo
TypeDesc instantiatedConstraintType = _constraintType.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(dictionary.TypeInstantiation, dictionary.MethodInstantiation);
MethodDesc implMethod;
+ MethodDesc instantiatedConstrainedMethodDefinition = instantiatedConstrainedMethod.GetMethodDefinition();
+
if (instantiatedConstrainedMethod.OwningType.IsInterface)
{
if (instantiatedConstrainedMethod.Signature.IsStatic)
{
- implMethod = instantiatedConstraintType.GetClosestDefType().ResolveVariantInterfaceMethodToStaticVirtualMethodOnType(instantiatedConstrainedMethod);
- if (implMethod == null)
- {
- DefaultInterfaceMethodResolution resolution =
- instantiatedConstraintType.GetClosestDefType().ResolveVariantInterfaceMethodToDefaultImplementationOnType(instantiatedConstrainedMethod, out implMethod);
- if (resolution != DefaultInterfaceMethodResolution.DefaultImplementation)
- {
- // TODO: diamond/reabstraction
- ThrowHelper.ThrowInvalidProgramException();
- }
- }
+ implMethod = instantiatedConstraintType.GetClosestDefType().ResolveVariantInterfaceMethodToStaticVirtualMethodOnType(instantiatedConstrainedMethodDefinition);
}
else
{
- throw new NotImplementedException();
+ implMethod = instantiatedConstraintType.GetClosestDefType().ResolveVariantInterfaceMethodToVirtualMethodOnType(instantiatedConstrainedMethodDefinition);
+ }
+
+ if (implMethod == null)
+ {
+ DefaultInterfaceMethodResolution resolution =
+ instantiatedConstraintType.GetClosestDefType().ResolveVariantInterfaceMethodToDefaultImplementationOnType(instantiatedConstrainedMethodDefinition, out implMethod);
+ if (resolution != DefaultInterfaceMethodResolution.DefaultImplementation)
+ {
+ // TODO: diamond/reabstraction: https://github.com/dotnet/runtime/issues/72589
+ ThrowHelper.ThrowInvalidProgramException();
+ }
}
}
else
{
- implMethod = instantiatedConstraintType.GetClosestDefType().FindVirtualFunctionTargetMethodOnObjectType(instantiatedConstrainedMethod);
+ implMethod = instantiatedConstraintType.GetClosestDefType().FindVirtualFunctionTargetMethodOnObjectType(instantiatedConstrainedMethodDefinition);
+ }
+
+ if (instantiatedConstrainedMethod != instantiatedConstrainedMethodDefinition)
+ {
+ implMethod = implMethod.MakeInstantiatedMethod(instantiatedConstrainedMethod.Instantiation);
}
// AOT use of this generic lookup is restricted to finding methods on valuetypes (runtime usage of this slot in universal generics is more flexible)
@@ -933,21 +941,10 @@ public override ISymbolNode GetTarget(NodeFactory factory, GenericLookupResultCo
factory.MetadataManager.NoteOverridingMethod(_constrainedMethod, implMethod);
// TODO-SIZE: this is address taken only in the delegate target case
- if (implMethod.Signature.IsStatic)
- {
- if (implMethod.GetCanonMethodTarget(CanonicalFormKind.Specific).IsSharedByGenericInstantiations)
- return factory.ExactCallableAddressTakenAddress(implMethod);
- else
- return factory.AddressTakenMethodEntrypoint(implMethod);
- }
- else if (implMethod.HasInstantiation)
- {
+ if (implMethod.GetCanonMethodTarget(CanonicalFormKind.Specific).IsSharedByGenericInstantiations)
return factory.ExactCallableAddressTakenAddress(implMethod);
- }
else
- {
- return factory.AddressTakenMethodEntrypoint(implMethod.GetCanonMethodTarget(CanonicalFormKind.Specific));
- }
+ return factory.AddressTakenMethodEntrypoint(implMethod);
}
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NativeLayoutVertexNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NativeLayoutVertexNode.cs
index 60b9a82dd0f930..c57f8ad072c233 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NativeLayoutVertexNode.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NativeLayoutVertexNode.cs
@@ -1414,7 +1414,6 @@ public NativeLayoutConstrainedMethodDictionarySlotNode(MethodDesc constrainedMet
_directCall = directCall;
Debug.Assert(_constrainedMethod.OwningType.IsInterface);
Debug.Assert(!_constrainedMethod.HasInstantiation || !directCall);
- Debug.Assert(_constrainedMethod.Signature.IsStatic);
}
protected sealed override string GetName(NodeFactory factory) =>
@@ -1428,10 +1427,12 @@ protected sealed override FixupSignatureKind SignatureKind
{
get
{
- if (_constrainedMethod.HasInstantiation)
- return FixupSignatureKind.GenericStaticConstrainedMethod;
- else
- return FixupSignatureKind.NonGenericStaticConstrainedMethod;
+ return (_constrainedMethod.HasInstantiation, _constrainedMethod.Signature.IsStatic) switch
+ {
+ (true, _) => FixupSignatureKind.GenericConstrainedMethod,
+ (false, true) => FixupSignatureKind.NonGenericStaticConstrainedMethod,
+ (false, false) => FixupSignatureKind.NonGenericInstanceConstrainedMethod,
+ };
}
}
@@ -1477,13 +1478,13 @@ protected sealed override Vertex WriteSignatureVertex(NativeWriter writer, NodeF
Vertex constraintType = factory.NativeLayout.TypeSignatureVertex(_constraintType).WriteVertex(factory);
if (_constrainedMethod.HasInstantiation)
{
- Debug.Assert(SignatureKind is FixupSignatureKind.GenericStaticConstrainedMethod);
+ Debug.Assert(SignatureKind is FixupSignatureKind.GenericConstrainedMethod);
Vertex constrainedMethodVertex = factory.NativeLayout.MethodEntry(_constrainedMethod).WriteVertex(factory);
return writer.GetTuple(constraintType, constrainedMethodVertex);
}
else
{
- Debug.Assert(SignatureKind is FixupSignatureKind.NonGenericStaticConstrainedMethod);
+ Debug.Assert(SignatureKind is FixupSignatureKind.NonGenericStaticConstrainedMethod or FixupSignatureKind.NonGenericInstanceConstrainedMethod);
Vertex methodType = factory.NativeLayout.TypeSignatureVertex(_constrainedMethod.OwningType).WriteVertex(factory);
var canonConstrainedMethod = _constrainedMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
int interfaceSlot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, canonConstrainedMethod, canonConstrainedMethod.OwningType);
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs
index 31c9035787ee48..74bf75817ef602 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs
@@ -550,42 +550,39 @@ private void ImportCall(ILOpcode opcode, int token)
bool allowInstParam = opcode != ILOpcode.ldvirtftn && opcode != ILOpcode.ldftn;
- if (directCall && resolvedConstraint && exactContextNeedsRuntimeLookup)
+ if (directCall && resolvedConstraint && (exactContextNeedsRuntimeLookup || forceUseRuntimeLookup))
{
// We want to do a direct call to a shared method on a valuetype. We need to provide
// a generic context, but the JitInterface doesn't provide a way for us to do it from here.
// So we do the next best thing and ask RyuJIT to look up a fat pointer.
- //
- // We have the canonical version of the method - find the runtime determined version.
- // This is simplified because we know the method is on a valuetype.
- Debug.Assert(targetMethod.OwningType.IsValueType);
if (forceUseRuntimeLookup)
{
- // The below logic would incorrectly resolve the lookup into the first match we found,
- // but there was a compile-time ambiguity due to shared code. The correct fix should
- // use the ConstrainedMethodUseLookupResult dictionary entry so that the exact
- // dispatch can be computed with the help of the generic dictionary.
- // We fail the compilation here to avoid bad codegen. This is not actually an invalid program.
- // https://github.com/dotnet/runtimelab/issues/1431
- ThrowHelper.ThrowInvalidProgramException();
+ var constrainedCallInfo = new ConstrainedCallInfo(_constrained, runtimeDeterminedMethod);
+ _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.ConstrainedDirectCall, constrainedCallInfo), reason);
}
-
- MethodDesc targetOfLookup;
- if (_constrained.IsRuntimeDeterminedType)
- targetOfLookup = _compilation.TypeSystemContext.GetMethodForRuntimeDeterminedType(targetMethod.GetTypicalMethodDefinition(), (RuntimeDeterminedType)_constrained);
- else if (_constrained.HasInstantiation)
- targetOfLookup = _compilation.TypeSystemContext.GetMethodForInstantiatedType(targetMethod.GetTypicalMethodDefinition(), (InstantiatedType)_constrained);
else
- targetOfLookup = targetMethod.GetMethodDefinition();
- if (targetOfLookup.HasInstantiation)
{
- targetOfLookup = targetOfLookup.MakeInstantiatedMethod(runtimeDeterminedMethod.Instantiation);
- }
- Debug.Assert(targetOfLookup.GetCanonMethodTarget(CanonicalFormKind.Specific) == targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific));
- _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.MethodEntry, targetOfLookup), reason);
+ // We have the canonical version of the method - find the runtime determined version.
+ // This is simplified because we know the method is on a valuetype.
+ Debug.Assert(targetMethod.OwningType.IsValueType);
+
+ MethodDesc targetOfLookup;
+ if (_constrained.IsRuntimeDeterminedType)
+ targetOfLookup = _compilation.TypeSystemContext.GetMethodForRuntimeDeterminedType(targetMethod.GetTypicalMethodDefinition(), (RuntimeDeterminedType)_constrained);
+ else if (_constrained.HasInstantiation)
+ targetOfLookup = _compilation.TypeSystemContext.GetMethodForInstantiatedType(targetMethod.GetTypicalMethodDefinition(), (InstantiatedType)_constrained);
+ else
+ targetOfLookup = targetMethod.GetMethodDefinition();
+ if (targetOfLookup.HasInstantiation)
+ {
+ targetOfLookup = targetOfLookup.MakeInstantiatedMethod(runtimeDeterminedMethod.Instantiation);
+ }
+ Debug.Assert(targetOfLookup.GetCanonMethodTarget(CanonicalFormKind.Specific) == targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific));
+ _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.MethodEntry, targetOfLookup), reason);
- targetForDelegate = targetOfLookup;
+ targetForDelegate = targetOfLookup;
+ }
}
else if (directCall && !allowInstParam && targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg())
{
@@ -700,6 +697,7 @@ private void ImportCall(ILOpcode opcode, int token)
{
Debug.Assert(targetMethod.OwningType.IsInterface && targetMethod.IsVirtual && _constrained != null);
+ // TODO: https://github.com/dotnet/runtime/issues/72589
ThrowHelper.ThrowBadImageFormatException();
}
else if (method.Signature.IsStatic)
diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
index 1cd7c8503a192c..d7a6a5a1a74ec5 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -420,7 +420,7 @@ private void getReadyToRunDelegateCtorHelper(ref CORINFO_RESOLVED_TOKEN pTargetM
}
else if (staticResolution is DefaultInterfaceMethodResolution.Diamond or DefaultInterfaceMethodResolution.Reabstraction)
{
- // TODO
+ // TODO: https://github.com/dotnet/runtime/issues/72589
ThrowHelper.ThrowInvalidProgramException();
}
}
@@ -1377,7 +1377,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO
ThrowHelper.ThrowBadImageFormatException();
}
- if (directCall && resolvedConstraint && pResult->exactContextNeedsRuntimeLookup)
+ if (directCall && resolvedConstraint && (pResult->exactContextNeedsRuntimeLookup || forceUseRuntimeLookup))
{
// We want to do a direct call to a shared method on a type. We need to provide
// a generic context, but the JitInterface doesn't provide a way for us to do it from here.
@@ -1387,39 +1387,43 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO
pResult->codePointerOrStubLookup.constLookup.accessType = InfoAccessType.IAT_VALUE;
pResult->nullInstanceCheck = !targetMethod.Signature.IsStatic;
- // We have the canonical version of the method - find the runtime determined version.
- // For now simplify it by assuming the resolved method is on the same type as the constraint.
- Debug.Assert(targetMethod.OwningType.GetTypeDefinition() == constrainedType.GetTypeDefinition());
TypeDesc runtimeDeterminedConstrainedType = (TypeDesc)GetRuntimeDeterminedObjectForToken(ref *pConstrainedResolvedToken);
+ object targetOfLookup;
+ ReadyToRunHelperId lookupHelper;
if (forceUseRuntimeLookup)
{
- // The below logic would incorrectly resolve the lookup into the first match we found,
- // but there was a compile-time ambiguity due to shared code. The correct fix should
- // use the ConstrainedMethodUseLookupResult dictionary entry so that the exact
- // dispatch can be computed with the help of the generic dictionary.
- // We fail the compilation here to avoid bad codegen. This is not actually an invalid program.
- // https://github.com/dotnet/runtimelab/issues/1431
- ThrowHelper.ThrowInvalidProgramException();
+ MethodDesc runtimeDeterminedInterfaceMethod = (MethodDesc)GetRuntimeDeterminedObjectForToken(ref pResolvedToken);
+ targetOfLookup = new ConstrainedCallInfo(runtimeDeterminedConstrainedType, runtimeDeterminedInterfaceMethod);
+ lookupHelper = ReadyToRunHelperId.ConstrainedDirectCall;
}
-
- MethodDesc targetOfLookup;
- if (runtimeDeterminedConstrainedType.IsRuntimeDeterminedType)
- targetOfLookup = _compilation.TypeSystemContext.GetMethodForRuntimeDeterminedType(targetMethod.GetTypicalMethodDefinition(), (RuntimeDeterminedType)runtimeDeterminedConstrainedType);
- else if (runtimeDeterminedConstrainedType.HasInstantiation)
- targetOfLookup = _compilation.TypeSystemContext.GetMethodForInstantiatedType(targetMethod.GetTypicalMethodDefinition(), (InstantiatedType)runtimeDeterminedConstrainedType);
else
- targetOfLookup = targetMethod.GetMethodDefinition();
- if (targetOfLookup.HasInstantiation)
{
- var methodToGetInstantiation = (MethodDesc)GetRuntimeDeterminedObjectForToken(ref pResolvedToken);
- targetOfLookup = targetOfLookup.MakeInstantiatedMethod(methodToGetInstantiation.Instantiation);
+ // We have the canonical version of the method - find the runtime determined version.
+ // For now simplify it by assuming the resolved method is on the same type as the constraint.
+ Debug.Assert(targetMethod.OwningType.GetTypeDefinition() == constrainedType.GetTypeDefinition());
+
+ MethodDesc lookupMethod;
+ if (runtimeDeterminedConstrainedType.IsRuntimeDeterminedType)
+ lookupMethod = _compilation.TypeSystemContext.GetMethodForRuntimeDeterminedType(targetMethod.GetTypicalMethodDefinition(), (RuntimeDeterminedType)runtimeDeterminedConstrainedType);
+ else if (runtimeDeterminedConstrainedType.HasInstantiation)
+ lookupMethod = _compilation.TypeSystemContext.GetMethodForInstantiatedType(targetMethod.GetTypicalMethodDefinition(), (InstantiatedType)runtimeDeterminedConstrainedType);
+ else
+ lookupMethod = targetMethod.GetMethodDefinition();
+ if (lookupMethod.HasInstantiation)
+ {
+ var methodToGetInstantiation = (MethodDesc)GetRuntimeDeterminedObjectForToken(ref pResolvedToken);
+ lookupMethod = lookupMethod.MakeInstantiatedMethod(methodToGetInstantiation.Instantiation);
+ }
+ Debug.Assert(lookupMethod.GetCanonMethodTarget(CanonicalFormKind.Specific) == targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific));
+
+ targetOfLookup = lookupMethod;
+ lookupHelper = ReadyToRunHelperId.MethodEntry;
}
- Debug.Assert(targetOfLookup.GetCanonMethodTarget(CanonicalFormKind.Specific) == targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific));
ComputeLookup(ref pResolvedToken,
targetOfLookup,
- ReadyToRunHelperId.MethodEntry,
+ lookupHelper,
HandleToObject(callerHandle),
ref pResult->codePointerOrStubLookup);
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2.ilproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2.ilproj
index 439059eb517c92..e0fc0740de6f58 100644
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2.ilproj
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2.ilproj
@@ -1,4 +1,8 @@
+
+
+ true
+
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2_gm.ilproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2_gm.ilproj
index c36a90952e1d22..ea1de7ddf0d4fd 100644
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2_gm.ilproj
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2_gm.ilproj
@@ -1,4 +1,8 @@
+
+
+ true
+
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.ilproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.ilproj
index 9777726ad29a5d..5cf4faecf03a79 100644
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.ilproj
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.ilproj
@@ -1,4 +1,8 @@
+
+
+ true
+
diff --git a/src/tests/Regressions/coreclr/16354/notimplemented.ilproj b/src/tests/Regressions/coreclr/16354/notimplemented.ilproj
index 66165d6484cdb1..6960c9f6da06f6 100644
--- a/src/tests/Regressions/coreclr/16354/notimplemented.ilproj
+++ b/src/tests/Regressions/coreclr/16354/notimplemented.ilproj
@@ -5,7 +5,9 @@
false
-
+
+
+ true
diff --git a/src/tests/issues.targets b/src/tests/issues.targets
index 49ffcb88a3453f..131c11f3341b80 100644
--- a/src/tests/issues.targets
+++ b/src/tests/issues.targets
@@ -965,15 +965,6 @@
https://github.com/dotnet/runtimelab/issues/155: Reflection.Emit
-
-
-
-
-
-
-
-
-
diff --git a/src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs b/src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs
index 5521646cd1fb7f..5850a7343e1201 100644
--- a/src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs
+++ b/src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs
@@ -60,6 +60,7 @@ internal static int Run()
Test104913Regression.Run();
Test105397Regression.Run();
Test105880Regression.Run();
+ TestInterfaceGenericCornerCase.Run();
Test115442Regression.Run();
TestInvokeMemberCornerCaseInGenerics.Run();
TestRefAny.Run();
@@ -3686,6 +3687,85 @@ public static void Run()
}
}
+ class TestInterfaceGenericCornerCase
+ {
+ interface IFoo
+ {
+ string Print(T x);
+
+ string PrintGeneric(T x);
+ }
+
+ class Conversion where T : IFoo, new() where U : class
+ {
+ public string Print()
+ {
+ string result = new T().Print(default);
+
+ Func f = new T().Print;
+ if (f(default) != result)
+ throw new Exception();
+
+ return result;
+ }
+
+ public string PrintGeneric()
+ {
+ string result = new T().PrintGeneric(default);
+
+ Func f = new T().PrintGeneric;
+ if (f(default) != result)
+ throw new Exception();
+
+ return result;
+ }
+ }
+
+ struct MyStruct : IFoo