private bool Fix(int iParam)
{
Debug.Assert(IsUnfixed(iParam));
// SPEC: An unfixed CType parameter with a set of bounds is fixed as follows:
// SPEC: The set of candidate types starts out as the set of all types in
// SPEC: the bounds.
// SPEC: We then examine each bound in turn. For each exact bound U of Xi,
// SPEC: all types which are not identical to U are removed from the candidate set.
// Optimization: if we have two or more exact bounds, fixing is impossible.
if (_pExactBounds[iParam].Count >= 2)
{
return false;
}
List<CType> initialCandidates = new List<CType>();
// Optimization: if we have one exact bound then we need not add any
// inexact bounds; we're just going to remove them anyway.
if (_pExactBounds[iParam].IsEmpty())
{
HashSet<CType> typeSet = new HashSet<CType>();
foreach (CType pCurrent in _pLowerBounds[iParam])
{
if (!typeSet.Contains(pCurrent))
{
typeSet.Add(pCurrent);
initialCandidates.Add(pCurrent);
}
}
foreach (CType pCurrent in _pUpperBounds[iParam])
{
if (!typeSet.Contains(pCurrent))
{
typeSet.Add(pCurrent);
initialCandidates.Add(pCurrent);
}
}
}
else
{
initialCandidates.Add(_pExactBounds[iParam].Head());
}
if (initialCandidates.IsEmpty())
{
return false;
}
// SPEC: For each lower bound U of Xi all types to which there is not an
// SPEC: implicit conversion from U are removed from the candidate set.
foreach (CType pBound in _pLowerBounds[iParam])
{
List<CType> removeList = new List<CType>();
foreach (CType pCandidate in initialCandidates)
{
if (pBound != pCandidate && !_binder.canConvert(pBound, pCandidate))
{
removeList.Add(pCandidate);
}
}
foreach (CType pRemove in removeList)
{
initialCandidates.Remove(pRemove);
}
}
// SPEC: For each upper bound U of Xi all types from which there is not an
// SPEC: implicit conversion to U are removed from the candidate set.
foreach (CType pBound in _pUpperBounds[iParam])
{
List<CType> removeList = new List<CType>();
foreach (CType pCandidate in initialCandidates)
{
if (pBound != pCandidate && !_binder.canConvert(pCandidate, pBound))
{
removeList.Add(pCandidate);
}
}
foreach (CType pRemove in removeList)
{
initialCandidates.Remove(pRemove);
}
}
// SPEC: If among the remaining candidate types there is a unique CType V from
// SPEC: which there is an implicit conversion to all the other candidate
// SPEC: types, then the parameter is fixed to V.
CType pBest = null;
foreach (CType pCandidate in initialCandidates)
{
foreach (CType pCandidate2 in initialCandidates)
{
if (pCandidate != pCandidate2 && !_binder.canConvert(pCandidate2, pCandidate))
{
goto OuterBreak;
}
}
if (pBest != null)
{
// best candidate is not unique
return false;
}
pBest = pCandidate;
OuterBreak:
;
}
if (pBest == null)
{
// no best candidate
return false;
}
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// RUNTIME BINDER ONLY CHANGE
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// just as we fix each individual type parameter, we need to
// ensure that we infer accessible type parameters, and so we
// widen them when necessary using the same technique that we
// used to alter the types at the beginning of binding. that
// way we get an accessible type, and if it so happens that
// the selected type is inappropriate (for conversions) then
// we let overload resolution sort it out.
//
// since we can never infer ref/out or pointer types here, we
// are more or less guaranteed a best accessible type. However,
// in the interest of safety, if it becomes impossible to
// choose a "best accessible" type, then we will fail type
// inference so we do not try to pass the inaccessible type
// back to overload resolution.
CType pBestAccessible;
if (GetTypeManager().GetBestAccessibleType(_binder.GetSemanticChecker(), _binder.GetContext(), pBest, out pBestAccessible))
{
pBest = pBestAccessible;
}
else
{
Debug.Assert(false, "Method type inference could not find an accessible type over the best candidate in fixed");
return false;
}
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// END RUNTIME BINDER ONLY CHANGE
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
_pFixedResults[iParam] = pBest;
UpdateDependenciesAfterFix(iParam);
return true;
}