MethodGroupExpr ResolveGetEnumerator (ResolveContext rc)
{
//
// Option 1: Try to match by name GetEnumerator first
//
var mexpr = Expression.MemberLookup (rc, rc.CurrentType, expr.Type,
"GetEnumerator", 0, Expression.MemberLookupRestrictions.ExactArity, loc); // TODO: What if CS0229 ?
var mg = mexpr as MethodGroupExpr;
if (mg != null) {
mg.InstanceExpression = expr;
Arguments args = new Arguments (0);
mg = mg.OverloadResolve (rc, ref args, this, OverloadResolver.Restrictions.None);
// For ambiguous GetEnumerator name warning CS0278 was reported, but Option 2 could still apply
if (ambiguous_getenumerator_name)
mg = null;
if (mg != null && args.Count == 0 && !mg.BestCandidate.IsStatic && mg.BestCandidate.IsPublic) {
return mg;
}
}
//
// Option 2: Try to match using IEnumerable interfaces with preference of generic version
//
TypeSpec iface_candidate = null;
var t = expr.Type;
do {
var ifaces = t.Interfaces;
if (ifaces != null) {
foreach (var iface in ifaces) {
if (TypeManager.generic_ienumerable_type != null && iface.MemberDefinition == TypeManager.generic_ienumerable_type.MemberDefinition) {
if (iface_candidate != null && iface_candidate != TypeManager.ienumerable_type) {
rc.Report.SymbolRelatedToPreviousError (expr.Type);
rc.Report.Error (1640, loc,
"foreach statement cannot operate on variables of type `{0}' because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
expr.Type.GetSignatureForError (), TypeManager.generic_ienumerable_type.GetSignatureForError ());
return null;
}
iface_candidate = iface;
continue;
}
if (iface == TypeManager.ienumerable_type && iface_candidate == null) {
iface_candidate = iface;
}
}
}
if (t.IsGenericParameter)
t = t.BaseType;
else
t = null;
} while (t != null);
if (iface_candidate == null) {
rc.Report.Error (1579, loc,
"foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `{1}' or is inaccessible",
expr.Type.GetSignatureForError (), "GetEnumerator");
return null;
}
var method = TypeManager.GetPredefinedMethod (iface_candidate,
MemberFilter.Method ("GetEnumerator", 0, ParametersCompiled.EmptyReadOnlyParameters, null), loc);
if (method == null)
return null;
mg = MethodGroupExpr.CreatePredefined (method, expr.Type, loc);
mg.InstanceExpression = expr;
return mg;
}