// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace Internal.TypeSystem
{
public partial class MethodDesc
{
///
/// Gets the shared runtime determined form of the method. This is a canonical form of the method
/// where generic arguments of the method and the owning type have been converted to runtime determined types.
///
public MethodDesc GetSharedRuntimeFormMethodTarget()
{
MethodDesc result = this;
DefType owningType = OwningType as DefType;
if (owningType != null)
{
// First find the method on the shared runtime form of the owning type
DefType sharedRuntimeOwningType = owningType.ConvertToSharedRuntimeDeterminedForm();
if (sharedRuntimeOwningType != owningType)
{
result = Context.GetMethodForInstantiatedType(
GetTypicalMethodDefinition(), (InstantiatedType)sharedRuntimeOwningType);
}
// Now convert the method instantiation to the shared runtime form
if (result.HasInstantiation)
{
MethodDesc uninstantiatedMethod = result.GetMethodDefinition();
bool changed;
Instantiation sharedInstantiation = RuntimeDeterminedTypeUtilities.ConvertInstantiationToSharedRuntimeForm(
Instantiation, uninstantiatedMethod.Instantiation, out changed);
// If either the instantiation changed, or we switched the owning type, we need to find the matching
// instantiated method.
if (changed || result != this)
{
result = Context.GetInstantiatedMethod(uninstantiatedMethod, sharedInstantiation);
}
}
}
return result;
}
///
/// Gets the type which holds the implementation of this method. This is typically the owning method,
/// unless this method models a target of a constrained method call.
///
public TypeDesc ImplementationType
{
get
{
// TODO: IsConstrainedMethod
return OwningType;
}
}
///
/// Gets a value indicating whether this is a shared method body.
///
public bool IsSharedByGenericInstantiations
{
get
{
return IsCanonicalMethod(CanonicalFormKind.Any);
}
}
///
/// Gets a value indicating whether this is a canonical method that will only become concrete
/// at runtime (after supplying the generic context).
///
public bool IsRuntimeDeterminedExactMethod
{
get
{
TypeDesc containingType = ImplementationType;
if (containingType.IsRuntimeDeterminedSubtype)
return true;
// Handles situation when shared code refers to uninstantiated generic
// method definitions (think: LDTOKEN).
// Walking the instantiation would make us assert. This is simply
// not a runtime determined method.
if (IsGenericMethodDefinition)
return false;
foreach (TypeDesc typeArg in Instantiation)
{
if (typeArg.IsRuntimeDeterminedSubtype)
return true;
}
return false;
}
}
public virtual MethodDesc GetNonRuntimeDeterminedMethodFromRuntimeDeterminedMethodViaSubstitution(Instantiation typeInstantiation, Instantiation methodInstantiation)
{
Instantiation instantiation = Instantiation;
TypeDesc[] clone = null;
for (int i = 0; i < instantiation.Length; i++)
{
TypeDesc uninst = instantiation[i];
TypeDesc inst = uninst.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(typeInstantiation, methodInstantiation);
if (inst != uninst)
{
if (clone == null)
{
clone = new TypeDesc[instantiation.Length];
for (int j = 0; j < clone.Length; j++)
{
clone[j] = instantiation[j];
}
}
clone[i] = inst;
}
}
MethodDesc method = this;
TypeDesc owningType = method.OwningType;
TypeDesc instantiatedOwningType = owningType.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(typeInstantiation, methodInstantiation);
if (owningType != instantiatedOwningType)
{
method = Context.GetMethodForInstantiatedType(method.GetTypicalMethodDefinition(), (InstantiatedType)instantiatedOwningType);
if (clone == null && instantiation.Length != 0)
return Context.GetInstantiatedMethod(method, instantiation);
}
return (clone == null) ? method : Context.GetInstantiatedMethod(method.GetMethodDefinition(), new Instantiation(clone));
}
}
}