private bool LowerBoundArrayInference(CType pSource, CType pDest)
{
// SPEC: Otherwise, if U is an array CType Ue[...] and V is either an array
// SPEC: CType Ve[...] of the same rank, or if U is a one-dimensional array
// SPEC: CType Ue[] and V is one of IEnumerable<Ve>, ICollection<Ve>,
// SPEC: IList<Ve>, IReadOnlyCollection<Ve> or IReadOnlyList<Ve> then
// SPEC: if Ue is known to be a reference CType then a lower-bound inference
// SPEC: from Ue to Ve is made.
// SPEC: otherwise an exact inference from Ue to Ve is made.
// Consider the following:
//
// abstract class B<T> { public abstract M<U>(U u) : where U : T; }
// class D : B<int[]> {
// static void M<X>(X[] x) { }
// public override M<U>(U u) { M(u); } // should infer M<int>
// }
if (pSource.IsTypeParameterType())
{
pSource = pSource.AsTypeParameterType().GetEffectiveBaseClass();
}
if (!pSource.IsArrayType())
{
return false;
}
ArrayType pArraySource = pSource.AsArrayType();
CType pElementSource = pArraySource.GetElementType();
CType pElementDest = null;
if (pDest.IsArrayType())
{
ArrayType pArrayDest = pDest.AsArrayType();
if (pArrayDest.rank != pArraySource.rank)
{
return false;
}
pElementDest = pArrayDest.GetElementType();
}
else if (pDest.isPredefType(PredefinedType.PT_G_IENUMERABLE) ||
pDest.isPredefType(PredefinedType.PT_G_ICOLLECTION) ||
pDest.isPredefType(PredefinedType.PT_G_ILIST) ||
pDest.isPredefType(PredefinedType.PT_G_IREADONLYCOLLECTION) ||
pDest.isPredefType(PredefinedType.PT_G_IREADONLYLIST))
{
if (pArraySource.rank != 1)
{
return false;
}
AggregateType pAggregateDest = pDest.AsAggregateType();
pElementDest = pAggregateDest.GetTypeArgsThis().Item(0);
}
else
{
return false;
}
if (pElementSource.IsRefType())
{
LowerBoundInference(pElementSource, pElementDest);
}
else
{
ExactInference(pElementSource, pElementDest);
}
return true;
}