/***************************************************************************************************
*
* There exists an explicit conversion ...
* From a generic delegate type S to generic delegate type T, provided all of the follow are true:
* o Both types are constructed generic types of the same generic delegate type, D<X1,... Xk>.That is,
* S is D<S1,... Sk> and T is D<T1,... Tk>.
* o S is not compatible with or identical to T.
* o If type parameter Xi is declared to be invariant then Si must be identical to Ti.
* o If type parameter Xi is declared to be covariant ("out") then Si must be convertible
* to Ti via an identify conversion, implicit reference conversion, or explicit reference conversion.
* o If type parameter Xi is declared to be contravariant ("in") then either Si must be identical to Ti,
* or Si and Ti must both be reference types.
***************************************************************************************************/
public static bool HasGenericDelegateExplicitReferenceConversion(SymbolLoader loader, CType pSource, CType pTarget)
{
if (!pSource.isDelegateType() ||
!pTarget.isDelegateType() ||
pSource.getAggregate() != pTarget.getAggregate() ||
loader.HasIdentityOrImplicitReferenceConversion(pSource, pTarget))
{
return(false);
}
TypeArray pTypeParams = pSource.getAggregate().GetTypeVarsAll();
TypeArray pSourceArgs = ((AggregateType)pSource).GetTypeArgsAll();
TypeArray pTargetArgs = ((AggregateType)pTarget).GetTypeArgsAll();
Debug.Assert(pTypeParams.Count == pSourceArgs.Count);
Debug.Assert(pTypeParams.Count == pTargetArgs.Count);
for (int iParam = 0; iParam < pTypeParams.Count; ++iParam)
{
CType pSourceArg = pSourceArgs[iParam];
CType pTargetArg = pTargetArgs[iParam];
// If they're identical then this one is automatically good, so skip it.
// If we have an error type, then we're in some fault tolerance. Let it through.
if (pSourceArg == pTargetArg)
{
continue;
}
TypeParameterType pParam = (TypeParameterType)pTypeParams[iParam];
if (pParam.Invariant)
{
return(false);
}
if (pParam.Covariant)
{
if (!FExpRefConv(loader, pSourceArg, pTargetArg))
{
return(false);
}
}
else if (pParam.Contravariant)
{
if (!pSourceArg.IsRefType() || !pTargetArg.IsRefType())
{
return(false);
}
}
}
return(true);
}