private void InferTypeArgsFirstPhase()
{
Debug.Assert(_pMethodFormalParameterTypes != null);
Debug.Assert(_pMethodArguments != null);
Debug.Assert(_pMethodArguments.carg <= _pMethodFormalParameterTypes.size);
// SPEC: For each of the method arguments Ei:
for (int iArg = 0; iArg < _pMethodArguments.carg; iArg++)
{
// SPEC ISSUE: We never deduce anything helpful from an filled-in
// SPEC ISSUE: optional parameter and sometimes deduce something harmful.
// SPEC ISSUE: Ex: Foo<T>(T t = default(T)) -- we do not want to add
// SPEC ISSUE: "T" to the bound set of "T" in this case and produce
// SPEC ISSUE: a "chicken and egg" problem.
// SPEC ISSUE: We should put language in the spec saying that we skip
// SPEC ISSUE: inference on any argument that was created via the
// SPEC ISSUE: optional parameter mechanism.
EXPR pExpr = _pMethodArguments.prgexpr[iArg];
if (pExpr.IsOptionalArgument)
{
continue;
}
CType pDest = _pMethodFormalParameterTypes.Item(iArg);
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// RUNTIME BINDER ONLY CHANGE
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// dynamic operands enter method type inference with their
// actual runtime type, and in this way can infer implemented
// types that are not visible on more public types. (for ex.,
// private classes that implement IEnumerable, as in iterators).
CType pSource = pExpr.RuntimeObjectActualType != null
? pExpr.RuntimeObjectActualType
: _pMethodArguments.types.Item(iArg);
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// END RUNTIME BINDER ONLY CHANGE
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
bool wasOutOrRef = false;
if (pDest.IsParameterModifierType())
{
pDest = pDest.AsParameterModifierType().GetParameterType();
wasOutOrRef = true;
}
if (pSource.IsParameterModifierType())
{
pSource = pSource.AsParameterModifierType().GetParameterType();
}
// If the argument is a TYPEORNAMESPACEERROR and the pSource is an
// error CType, then we want to set it to the generic error CType
// that has no name text. This is because of the following scenario:
//
// void M<T>(T t) { }
// void Foo()
// {
// UnknownType t;
// M(t);
// M(undefinedVariable);
// }
//
// In the first call to M, we'll have an EXPRLOCAL with an error CType,
// which is correct - we want the parameter help to display that we've
// got an inferred CType of UnknownType, which is an error CType since
// its undefined.
//
// However, for the M in the second call, we DON'T want to display parameter
// help that gives undefinedVariable as the CType parameter for T, because
// there is no parameter of that name, let alone that CType. This appears
// as an EXPRTYPEORNAMESPACEERROR with an ErrorType. We create a new error sym
// without the CType name.
// SPEC: If Ei is an anonymous function, an explicit CType parameter
// SPEC: inference is made from Ei to Ti.
// (We cannot make an output CType inference from a method group
// at this time because we have no fixed types yet to use for
// overload resolution.)
// SPEC: Otherwise, if Ei has a CType U then a lower-bound inference
// SPEC: or exact inference is made from U to Ti.
// SPEC: Otherwise, no inference is made for this argument
if (IsReallyAType(pSource))
{
if (wasOutOrRef)
{
ExactInference(pSource, pDest);
}
else
{
LowerBoundInference(pSource, pDest);
}
}
}
}