2010-07-14 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / mcs / statement.cs
index 3c0159937e436b094e1ba59c6e68dafa65d2d71d..51a975d549f59797a6eeff5bfbe67ab96fdd1cc1 100644 (file)
@@ -632,6 +632,55 @@ namespace Mono.CSharp {
                }
        }
 
+       //
+       // Simple version of statement list not requiring a block
+       //
+       public class StatementList : Statement
+       {
+               List<Statement> statements;
+
+               public StatementList (Statement first, Statement second)
+               {
+                       statements = new List<Statement> () { first, second };
+               }
+
+               #region Properties
+               public IList<Statement> Statements {
+                       get {
+                               return statements;
+                       }
+               }
+               #endregion
+
+               public void Add (Statement statement)
+               {
+                       statements.Add (statement);
+               }
+
+               public override bool Resolve (BlockContext ec)
+               {
+                       foreach (var s in statements)
+                               s.Resolve (ec);
+
+                       return true;
+               }
+
+               protected override void DoEmit (EmitContext ec)
+               {
+                       foreach (var s in statements)
+                               s.Emit (ec);
+               }
+
+               protected override void CloneTo (CloneContext clonectx, Statement target)
+               {
+                       StatementList t = (StatementList) target;
+
+                       t.statements = new List<Statement> (statements.Count);
+                       foreach (Statement s in statements)
+                               t.statements.Add (s.Clone (clonectx));
+               }
+       }
+
        // A 'return' or a 'yield break'
        public abstract class ExitStatement : Statement
        {
@@ -659,14 +708,23 @@ namespace Mono.CSharp {
        /// <summary>
        ///   Implements the return statement
        /// </summary>
-       public class Return : ExitStatement {
+       public class Return : ExitStatement
+       {
                protected Expression Expr;
                public Return (Expression expr, Location l)
                {
                        Expr = expr;
                        loc = l;
                }
-               
+
+               #region Properties
+               public Expression Expression {
+                       get {
+                               return Expr;
+                       }
+               }
+               #endregion
+
                protected override bool DoResolve (BlockContext ec)
                {
                        if (Expr == null) {
@@ -1447,13 +1505,7 @@ namespace Mono.CSharp {
                        statements = new List<Statement> (4);
                }
 
-               public Block CreateSwitchBlock (Location start)
-               {
-                       // FIXME: should this be implicit?
-                       Block new_block = new ExplicitBlock (this, start, start);
-                       new_block.switch_block = this;
-                       return new_block;
-               }
+               #region Properties
 
                public int ID {
                        get { return this_id; }
@@ -1467,6 +1519,16 @@ namespace Mono.CSharp {
                        }
                }
 
+               #endregion
+
+               public Block CreateSwitchBlock (Location start)
+               {
+                       // FIXME: should this be implicit?
+                       Block new_block = new ExplicitBlock (this, start, start);
+                       new_block.switch_block = this;
+                       return new_block;
+               }
+
                void AddChild (Block b)
                {
                        if (children == null)
@@ -1640,7 +1702,7 @@ namespace Mono.CSharp {
                        return false;
                }
 
-               protected virtual bool CheckParentConflictName (ToplevelBlock block, string name, Location l)
+               protected bool CheckParentConflictName (ToplevelBlock block, string name, Location l)
                {
                        LocalInfo vi = GetLocalInfo (name);
                        if (vi != null) {
@@ -1655,13 +1717,13 @@ namespace Mono.CSharp {
                        }
 
                        if (block != null) {
-                               Expression e = block.GetParameterReference (name, Location.Null);
-                               if (e != null) {
-                                       ParameterReference pr = e as ParameterReference;
-                                       if (this is Linq.QueryBlock && (pr != null && pr.Parameter is Linq.QueryBlock.ImplicitQueryParameter || e is MemberAccess))
+                               var tblock = block.CheckParameterNameConflict (name);
+                               if (tblock != null) {
+                                       if (block == tblock && block is Linq.QueryBlock)
                                                Error_AlreadyDeclared (loc, name);
                                        else
                                                Error_AlreadyDeclared (loc, name, "parent or current");
+
                                        return false;
                                }
                        }
@@ -1674,16 +1736,6 @@ namespace Mono.CSharp {
                        if (!CheckParentConflictName (Toplevel, name, l))
                                return null;
 
-                       if (Toplevel.GenericMethod != null) {
-                               foreach (TypeParameter tp in Toplevel.GenericMethod.CurrentTypeParameters) {
-                                       if (tp.Name == name) {
-                                               Toplevel.Report.SymbolRelatedToPreviousError (tp);
-                                               Error_AlreadyDeclaredTypeParameter (Toplevel.Report, loc, name, "local variable");
-                                               return null;
-                                       }
-                               }
-                       }                       
-
                        IKnownVariable kvi = Explicit.GetKnownVariable (name);
                        if (kvi != null) {
                                Toplevel.Report.SymbolRelatedToPreviousError (kvi.Location, name);
@@ -1725,9 +1777,9 @@ namespace Mono.CSharp {
                                "A local variable named `{0}' is already defined in this scope", name);
                }
                                        
-               public virtual void Error_AlreadyDeclaredTypeParameter (Report r, Location loc, string name, string conflict)
+               public virtual void Error_AlreadyDeclaredTypeParameter (Location loc, string name, string conflict)
                {
-                       r.Error (412, loc, "The type parameter name `{0}' is the same as `{1}'",
+                       Toplevel.Report.Error (412, loc, "The type parameter name `{0}' is the same as `{1}'",
                                name, conflict);
                }
 
@@ -1768,9 +1820,8 @@ namespace Mono.CSharp {
                {
                        LocalInfo ret;
                        for (Block b = this; b != null; b = b.Parent) {
-                               if (b.variables != null) {
-                                       if (b.variables.TryGetValue (name, out ret))
-                                               return ret;
+                               if (b.variables != null && b.variables.TryGetValue (name, out ret)) {
+                                       return ret;
                                }
                        }
 
@@ -2148,8 +2199,7 @@ namespace Mono.CSharp {
                protected override void DoEmit (EmitContext ec)
                {
                        for (int ix = 0; ix < statements.Count; ix++){
-                               Statement s = (Statement) statements [ix];
-                               s.Emit (ec);
+                               statements [ix].Emit (ec);
                        }
                }
 
@@ -2188,7 +2238,7 @@ namespace Mono.CSharp {
 
                public override string ToString ()
                {
-                       return String.Format ("{0} ({1}:{2})", GetType (),ID, StartLocation);
+                       return String.Format ("{0} ({1}:{2})", GetType (), this_id, StartLocation);
                }
 
                protected override void CloneTo (CloneContext clonectx, Statement t)
@@ -2197,7 +2247,7 @@ namespace Mono.CSharp {
 
                        clonectx.AddBlockMap (this, target);
 
-                       //target.Toplevel = (ToplevelBlock) clonectx.LookupBlock (Toplevel);
+                       target.Toplevel = (ToplevelBlock) clonectx.LookupBlock (Toplevel);
                        target.Explicit = (ExplicitBlock) clonectx.LookupBlock (Explicit);
                        if (Parent != null)
                                target.Parent = clonectx.RemapBlockCopy (Parent);
@@ -2370,15 +2420,13 @@ namespace Mono.CSharp {
                        base.EmitMeta (ec);
                }
 
-               internal IKnownVariable GetKnownVariable (string name)
+               public IKnownVariable GetKnownVariable (string name)
                {
                        if (known_variables == null)
                                return null;
 
                        IKnownVariable kw;
-                       if (!known_variables.TryGetValue (name, out kw))
-                               return null;
-
+                       known_variables.TryGetValue (name, out kw);
                        return kw;
                }
 
@@ -2480,9 +2528,8 @@ namespace Mono.CSharp {
                        }
                }
 
-               GenericMethod generic;
                protected ParametersCompiled parameters;
-               ToplevelParameterInfo[] parameter_info;
+               protected ToplevelParameterInfo[] parameter_info;
                LocalInfo this_variable;
                bool resolved;
                bool unreachable;
@@ -2507,10 +2554,6 @@ namespace Mono.CSharp {
                        get { return compiler.Report; }
                }
 
-               public GenericMethod GenericMethod {
-                       get { return generic; }
-               }
-
                public ToplevelBlock Container {
                        get { return Parent == null ? null : Parent.Toplevel; }
                }
@@ -2520,12 +2563,6 @@ namespace Mono.CSharp {
                {
                }
 
-               public ToplevelBlock (CompilerContext ctx, Block parent, ParametersCompiled parameters, GenericMethod generic, Location start) :
-                       this (ctx, parent, parameters, start)
-               {
-                       this.generic = generic;
-               }
-
                public ToplevelBlock (CompilerContext ctx, ParametersCompiled parameters, Location start) :
                        this (ctx, null, (Flags) 0, parameters, start)
                {
@@ -2563,10 +2600,11 @@ namespace Mono.CSharp {
                        ToplevelBlock target = (ToplevelBlock) t;
                        base.CloneTo (clonectx, t);
 
-                       if (parameters.Count != 0)
-                               target.parameter_info = new ToplevelParameterInfo [parameters.Count];
-                       for (int i = 0; i < parameters.Count; ++i)
-                               target.parameter_info [i] = new ToplevelParameterInfo (target, i);
+                       if (parameters.Count != 0) {
+                               target.parameter_info = new ToplevelParameterInfo[parameters.Count];
+                               for (int i = 0; i < parameters.Count; ++i)
+                                       target.parameter_info[i] = new ToplevelParameterInfo (target, i);
+                       }
                }
 
                public bool CheckError158 (string name, Location loc)
@@ -2659,6 +2697,9 @@ namespace Mono.CSharp {
                public Expression GetParameterReference (string name, Location loc)
                {
                        for (ToplevelBlock t = this; t != null; t = t.Container) {
+                               if (t.parameters.IsEmpty)
+                                       continue;
+
                                Expression expr = t.GetParameterReferenceExpression (name, loc);
                                if (expr != null)
                                        return expr;
@@ -2674,6 +2715,21 @@ namespace Mono.CSharp {
                                null : new ParameterReference (parameter_info [idx], loc);
                }
 
+               public ToplevelBlock CheckParameterNameConflict (string name)
+               {
+                       for (ToplevelBlock t = this; t != null; t = t.Container) {
+                               if (t.HasParameterWithName (name))
+                                       return t;
+                       }
+
+                       return null;
+               }
+
+               protected virtual bool HasParameterWithName (string name)
+               {
+                       return parameters.GetParameterIndexByName (name) >= 0;
+               }
+
                // <summary>
                //   Returns the "this" instance variable of this block.
                //   See AddThisVariable() for more information.
@@ -2742,6 +2798,9 @@ namespace Mono.CSharp {
                                        unreachable = top_level.End ();
                                }
                        } catch (Exception e) {
+                               if (e is CompletionResult || rc.Report.IsDisabled)
+                                       throw;
+
                                if (rc.CurrentBlock != null) {
                                        rc.Report.Error (584, rc.CurrentBlock.StartLocation, "Internal compiler error: {0}", e.Message);
                                } else {
@@ -3705,7 +3764,7 @@ namespace Mono.CSharp {
                                Arguments get_value_args = new Arguments (1);
                                get_value_args.Add (new Argument (value));
 
-                               Expression get_item = new IndexerAccess (new ElementAccess (switch_cache_field, get_value_args), loc).Resolve (rc);
+                               Expression get_item = new IndexerAccess (new ElementAccess (switch_cache_field, get_value_args, loc), loc).Resolve (rc);
                                if (get_item == null)
                                        return;
 
@@ -4050,10 +4109,11 @@ namespace Mono.CSharp {
        public class Unchecked : Statement {
                public Block Block;
                
-               public Unchecked (Block b)
+               public Unchecked (Block b, Location loc)
                {
                        Block = b;
                        b.Unchecked = true;
+                       this.loc = loc;
                }
 
                public override bool Resolve (BlockContext ec)
@@ -4079,10 +4139,11 @@ namespace Mono.CSharp {
        public class Checked : Statement {
                public Block Block;
                
-               public Checked (Block b)
+               public Checked (Block b, Location loc)
                {
                        Block = b;
                        b.Unchecked = false;
+                       this.loc = loc;
                }
 
                public override bool Resolve (BlockContext ec)
@@ -4108,11 +4169,11 @@ namespace Mono.CSharp {
        public class Unsafe : Statement {
                public Block Block;
 
-               public Unsafe (Block b)
+               public Unsafe (Block b, Location loc)
                {
                        Block = b;
                        Block.Unsafe = true;
-                       loc = b.StartLocation;
+                       this.loc = loc;
                }
 
                public override bool Resolve (BlockContext ec)
@@ -4331,7 +4392,7 @@ namespace Mono.CSharp {
                                                new Binary (Binary.Operator.Equality, e, new NullLiteral (loc), loc),
                                                new Binary (Binary.Operator.Equality, new MemberAccess (e, "Length"), new IntConstant (0, loc), loc), loc)),
                                                        new NullPointer (loc),
-                                                       converted);
+                                                       converted, loc);
 
                                        converted = converted.Resolve (ec);                                     
 
@@ -4703,54 +4764,87 @@ namespace Mono.CSharp {
        }
 
        // FIXME: Why is it almost exact copy of Using ??
-       public class UsingTemporary : ExceptionStatement {
-               TemporaryVariable local_copy;
-               public Statement Statement;
+       public class UsingTemporary : ExceptionStatement
+       {
+               protected TemporaryVariable local_copy;
+               Statement statement;
                Expression expr;
-               TypeSpec expr_type;
+               protected Statement dispose_call;
 
                public UsingTemporary (Expression expr, Statement stmt, Location l)
                {
                        this.expr = expr;
-                       Statement = stmt;
+                       statement = stmt;
                        loc = l;
                }
 
-               public override bool Resolve (BlockContext ec)
+               #region Properties
+               public Expression Expression {
+                       get {
+                               return expr;
+                       }
+               }
+
+               public Statement Statement {
+                       get {
+                               return statement;
+                       }
+               }
+
+               #endregion
+
+               protected virtual bool DoResolve (BlockContext ec)
                {
                        expr = expr.Resolve (ec);
                        if (expr == null)
                                return false;
 
-                       expr_type = expr.Type;
-
-                       if (!expr_type.ImplementsInterface (TypeManager.idisposable_type) &&
+                       if (!expr.Type.ImplementsInterface (TypeManager.idisposable_type) &&
                                Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) {
-                               if (expr_type != InternalType.Dynamic) {
+                               if (expr.Type != InternalType.Dynamic) {
                                        Using.Error_IsNotConvertibleToIDisposable (ec, expr);
                                        return false;
                                }
 
                                expr = Convert.ImplicitConversionRequired (ec, expr, TypeManager.idisposable_type, loc);
-                               expr_type = expr.Type;
                        }
 
+                       var expr_type = expr.Type;
+
                        local_copy = new TemporaryVariable (expr_type, loc);
                        local_copy.Resolve (ec);
 
+                       if (TypeManager.void_dispose_void == null) {
+                               TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
+                                       TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes);
+                       }
+
+                       var dispose_mg = MethodGroupExpr.CreatePredefined (TypeManager.void_dispose_void, TypeManager.idisposable_type, loc);
+                       dispose_mg.InstanceExpression = TypeManager.IsNullableType (expr_type) ?
+                               new Cast (new TypeExpression (TypeManager.idisposable_type, loc), local_copy, loc).Resolve (ec) :
+                               local_copy;
+
+                       dispose_call = new StatementExpression (new Invocation (dispose_mg, null));
+
+                       // Add conditional call when disposing possible null variable
+                       if (!expr_type.IsStruct || TypeManager.IsNullableType (expr_type))
+                               dispose_call = new If (new Binary (Binary.Operator.Inequality, local_copy, new NullLiteral (loc), loc), dispose_call, loc);
+
+                       return dispose_call.Resolve (ec);
+               }
+
+               public override bool Resolve (BlockContext ec)
+               {
+                       bool ok = DoResolve (ec);
+
                        ec.StartFlowBranching (this);
 
-                       bool ok = Statement.Resolve (ec);
+                       ok &= statement.Resolve (ec);
 
                        ec.EndFlowBranching ();
 
                        ok &= base.Resolve (ec);
 
-                       if (TypeManager.void_dispose_void == null) {
-                               TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
-                                       TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes);
-                       }
-
                        return ok;
                }
 
@@ -4761,34 +4855,12 @@ namespace Mono.CSharp {
 
                protected override void EmitTryBody (EmitContext ec)
                {
-                       Statement.Emit (ec);
+                       statement.Emit (ec);
                }
 
                protected override void EmitFinallyBody (EmitContext ec)
                {
-                       if (!TypeManager.IsStruct (expr_type)) {
-                               Label skip = ec.DefineLabel ();
-                               local_copy.Emit (ec);
-                               ec.Emit (OpCodes.Brfalse, skip);
-                               local_copy.Emit (ec);
-                               ec.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
-                               ec.MarkLabel (skip);
-                               return;
-                       }
-
-                       MethodSpec ms = MemberCache.FindMember (expr_type,
-                               MemberFilter.Method ("Dispose", 0, ParametersCompiled.EmptyReadOnlyParameters, TypeManager.void_type),
-                               BindingRestriction.InstanceOnly) as MethodSpec;
-
-                       if (ms == null) {
-                               local_copy.Emit (ec);
-                               ec.Emit (OpCodes.Box, expr_type);
-                               ec.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
-                               return;
-                       }
-
-                       local_copy.AddressOf (ec, AddressOp.Load);
-                       ec.Emit (OpCodes.Call, ms);
+                       dispose_call.Emit (ec);
                }
 
                protected override void CloneTo (CloneContext clonectx, Statement t)
@@ -4796,7 +4868,7 @@ namespace Mono.CSharp {
                        UsingTemporary target = (UsingTemporary) t;
 
                        target.expr = expr.Clone (clonectx);
-                       target.Statement = Statement.Clone (clonectx);
+                       target.statement = statement.Clone (clonectx);
                }
        }
 
@@ -4846,7 +4918,7 @@ namespace Mono.CSharp {
                                ec.Emit (OpCodes.Brfalse, skip);
                        }
 
-                       Invocation.EmitCall (ec, false, var, TypeManager.void_dispose_void, null, loc);
+                       Invocation.EmitCall (ec, var, TypeManager.void_dispose_void, null, loc);
 
                        if (emit_null_check)
                                ec.MarkLabel (skip);
@@ -4996,7 +5068,7 @@ namespace Mono.CSharp {
                                        list.Add (new Argument (counter [i]));
                                }
 
-                               access = new ElementAccess (copy, list).Resolve (ec);
+                               access = new ElementAccess (copy, list, loc).Resolve (ec);
                                if (access == null)
                                        return false;
 
@@ -5085,16 +5157,16 @@ namespace Mono.CSharp {
                        }
                }
 
-               sealed class CollectionForeach : Statement
+               sealed class CollectionForeach : Statement, MethodGroupExpr.IErrorHandler
                {
-                       class CollectionForeachStatement : Statement
+                       class Body : Statement
                        {
                                TypeSpec type;
                                Expression variable, current, conv;
                                Statement statement;
                                Assign assign;
 
-                               public CollectionForeachStatement (TypeSpec type, Expression variable,
+                               public Body (TypeSpec type, Expression variable,
                                                                   Expression current, Statement statement,
                                                                   Location loc)
                                {
@@ -5137,20 +5209,59 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       Expression variable, expr;
-                       Statement statement;
+                       class Dispose : UsingTemporary
+                       {
+                               LocalTemporary dispose;
+
+                               public Dispose (TemporaryVariable variable, LocalTemporary dispose, Expression expr, Statement statement, Location loc)
+                                       : base (expr, statement, loc)
+                               {
+                                       base.local_copy = variable;
+                                       this.dispose = dispose;
+                               }
+
+                               protected override bool DoResolve (BlockContext ec)
+                               {
+                                       if (TypeManager.void_dispose_void == null) {
+                                               TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
+                                                       TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes);
+                                       }
+
+                                       Expression dispose_var = (Expression) dispose ?? local_copy;
+
+                                       var dispose_mg = MethodGroupExpr.CreatePredefined (TypeManager.void_dispose_void, TypeManager.idisposable_type, loc);
+                                       dispose_mg.InstanceExpression = dispose_var;
+
+                                       dispose_call = new StatementExpression (new Invocation (dispose_mg, null));
+
+                                       if (!dispose_var.Type.IsStruct)
+                                               dispose_call = new If (new Binary (Binary.Operator.Inequality, dispose_var, new NullLiteral (loc), loc), dispose_call, loc);
+
+                                       return dispose_call.Resolve (ec);
+                               }
+
+                               protected override void EmitFinallyBody (EmitContext ec)
+                               {
+                                       Label call_dispose = ec.DefineLabel ();
+                                       if (dispose != null) {
+                                               local_copy.Emit (ec, false);
+                                               ec.Emit (OpCodes.Isinst, dispose.Type);
+                                               dispose.Store (ec);
+                                       }
 
-                       TemporaryVariable enumerator;
-                       Expression init;
-                       Statement loop;
-                       Statement wrapper;
+                                       base.EmitFinallyBody (ec);
 
-                       MethodGroupExpr get_enumerator;
-                       PropertyExpr get_current;
-                       MethodSpec move_next;
+                                       if (dispose != null) {
+                                               ec.MarkLabel (call_dispose);
+                                               dispose.Release (ec);
+                                       }
+                               }
+                       }
+
+                       Expression variable, expr;
+                       Statement statement;
                        Expression var_type;
-                       TypeSpec enumerator_type;
-                       bool enumerator_found;
+                       ExpressionStatement init;
 
                        public CollectionForeach (Expression var_type, Expression var,
                                                  Expression expr, Statement stmt, Location l)
@@ -5167,403 +5278,215 @@ namespace Mono.CSharp {
                                throw new NotImplementedException ();
                        }
 
-                       bool GetEnumeratorFilter (ResolveContext ec, MethodSpec mi)
+                       void Error_WrongEnumerator (ResolveContext rc, MethodSpec enumerator)
                        {
-                               TypeSpec return_type = mi.ReturnType;
+                               rc.Report.SymbolRelatedToPreviousError (enumerator);
+                               rc.Report.Error (202, loc,
+                                       "foreach statement requires that the return type `{0}' of `{1}' must have a suitable public MoveNext method and public Current property",
+                                               enumerator.ReturnType.GetSignatureForError (), enumerator.GetSignatureForError ());
+                       }
 
+                       MethodGroupExpr ResolveGetEnumerator (ResolveContext rc)
+                       {
                                //
-                               // Ok, we can access it, now make sure that we can do something
-                               // with this `GetEnumerator'
+                               // Option 1: Try to match by name GetEnumerator first
                                //
-
-                               if (return_type == TypeManager.ienumerator_type ||
-                                       return_type.ImplementsInterface (TypeManager.ienumerator_type)) {
-                                       //
-                                       // If it is not an interface, lets try to find the methods ourselves.
-                                       // For example, if we have:
-                                       // public class Foo : IEnumerator { public bool MoveNext () {} public int Current { get {}}}
-                                       // We can avoid the iface call. This is a runtime perf boost.
-                                       // even bigger if we have a ValueType, because we avoid the cost
-                                       // of boxing.
-                                       //
-                                       // We have to make sure that both methods exist for us to take
-                                       // this path. If one of the methods does not exist, we will just
-                                       // use the interface. Sadly, this complex if statement is the only
-                                       // way I could do this without a goto
-                                       //
-
-                                       if (TypeManager.bool_movenext_void == null) {
-                                               TypeManager.bool_movenext_void = TypeManager.GetPredefinedMethod (
-                                                       TypeManager.ienumerator_type, "MoveNext", loc, TypeSpec.EmptyTypes);
+                               var mexpr = Expression.MemberLookup (rc.Compiler, rc.CurrentType, null, expr.Type, "GetEnumerator", -1,
+                                       MemberKind.All, BindingRestriction.DefaultMemberLookup | BindingRestriction.AccessibleOnly, loc);
+
+                               var mg = mexpr as MethodGroupExpr;
+                               if (mg != null) {
+                                       mg.InstanceExpression = expr;
+                                       mg.CustomErrorHandler = this;
+                                       Arguments args = new Arguments (0);
+                                       mg = mg.OverloadResolve (rc, ref args, false, loc);
+
+                                       if (mg != null && args.Count == 0 && !mg.BestCandidate.IsStatic && mg.BestCandidate.IsPublic) {
+                                               return mg;
                                        }
+                               }
 
-                                       if (TypeManager.ienumerator_getcurrent == null) {
-                                               TypeManager.ienumerator_getcurrent = TypeManager.GetPredefinedProperty (
-                                                       TypeManager.ienumerator_type, "Current", loc, TypeManager.object_type);
-                                       }
+                               //
+                               // Option 2: Try to match using IEnumerable interfaces with preference of generic version
+                               //
+                               TypeSpec iface_candidate = null;
+                               for (TypeSpec t = expr.Type; t != null && t != TypeManager.object_type; t = t.BaseType) {
+                                       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;
+                                                       }
 
-                                       //
-                                       // Prefer a generic enumerator over a non-generic one.
-                                       //
-                                       if (return_type.IsInterface && TypeManager.IsGenericType (return_type)) {
-                                               enumerator_type = return_type;
-                                               if (!FetchGetCurrent (ec, return_type))
-                                                       get_current = new PropertyExpr (TypeManager.ienumerator_getcurrent, loc);
-                                               if (!FetchMoveNext (return_type))
-                                                       move_next = TypeManager.bool_movenext_void;
-                                               return true;
+                                                       if (iface == TypeManager.ienumerable_type && iface_candidate == null) {
+                                                               iface_candidate = iface;
+                                                       }
+                                               }
                                        }
+                               }
 
-                                       if (return_type.IsInterface ||
-                                           !FetchMoveNext (return_type) ||
-                                           !FetchGetCurrent (ec, return_type)) {
-                                               enumerator_type = return_type;
-                                               move_next = TypeManager.bool_movenext_void;
-                                               get_current = new PropertyExpr (TypeManager.ienumerator_getcurrent, loc);
-                                               return true;
-                                       }
-                               } else {
-                                       //
-                                       // Ok, so they dont return an IEnumerable, we will have to
-                                       // find if they support the GetEnumerator pattern.
-                                       //
+                               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 not accessible",
+                                               expr.Type.GetSignatureForError (), "GetEnumerator");
 
-                                       if (TypeManager.HasElementType (return_type) || !FetchMoveNext (return_type) || !FetchGetCurrent (ec, return_type)) {
-                                               ec.Report.Error (202, loc, "foreach statement requires that the return type `{0}' of `{1}' must have a suitable public MoveNext method and public Current property",
-                                                       TypeManager.CSharpName (return_type), TypeManager.CSharpSignature (mi));
-                                               return false;
-                                       }
+                                       return null;
                                }
 
-                               enumerator_type = return_type;
+                               var method = TypeManager.GetPredefinedMethod (iface_candidate, 
+                                       MemberFilter.Method ("GetEnumerator", 0, ParametersCompiled.EmptyReadOnlyParameters, null), loc);
 
-                               return true;
+                               if (method == null)
+                                       return null;
+
+                               mg = MethodGroupExpr.CreatePredefined (method, expr.Type, loc);
+                               mg.InstanceExpression = expr;
+                               return mg;
                        }
 
-                       //
-                       // Retrieves a `public bool MoveNext ()' method from the Type `t'
-                       //
-                       bool FetchMoveNext (TypeSpec t)
+                       MethodGroupExpr ResolveMoveNext (ResolveContext rc, MethodSpec enumerator)
                        {
-                               move_next = MemberCache.FindMember (t,
+                               var ms = MemberCache.FindMember (enumerator.ReturnType,
                                        MemberFilter.Method ("MoveNext", 0, ParametersCompiled.EmptyReadOnlyParameters, TypeManager.bool_type),
                                        BindingRestriction.InstanceOnly) as MethodSpec;
 
-                               return move_next != null && (move_next.Modifiers & Modifiers.PUBLIC) != 0;
-                       }
-               
-                       //
-                       // Retrieves a `public T get_Current ()' method from the Type `t'
-                       //
-                       bool FetchGetCurrent (ResolveContext ec, TypeSpec t)
-                       {
-                               PropertyExpr pe = Expression.MemberLookup (ec.Compiler,
-                                       ec.CurrentType, t, "Current", 0, MemberKind.Property,
-                                       BindingRestriction.AccessibleOnly, loc) as PropertyExpr;
-                               if (pe == null)
-                                       return false;
+                               if (ms == null || !ms.IsPublic) {
+                                       Error_WrongEnumerator (rc, enumerator);
+                                       return null;
+                               }
 
-                               get_current = pe;
-                               return true;
+                               return MethodGroupExpr.CreatePredefined (ms, enumerator.ReturnType, loc);
                        }
 
-                       void Error_Enumerator (BlockContext ec)
+                       PropertySpec ResolveCurrent (ResolveContext rc, MethodSpec enumerator)
                        {
-                               if (enumerator_found) {
-                                       return;
+                               var ps = MemberCache.FindMember (enumerator.ReturnType,
+                                       MemberFilter.Property ("Current", null),
+                                       BindingRestriction.InstanceOnly) as PropertySpec;
+
+                               if (ps == null || !ps.IsPublic) {
+                                       Error_WrongEnumerator (rc, enumerator);
+                                       return null;
                                }
 
-                           ec.Report.Error (1579, loc,
-                                       "foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `GetEnumerator' or is not accessible",
-                                       TypeManager.CSharpName (expr.Type));
+                               return ps;
                        }
 
-                       bool TryType (ResolveContext ec, TypeSpec t)
+                       public override bool Resolve (BlockContext ec)
                        {
-                               var mg = Expression.MemberLookup (ec.Compiler, ec.CurrentType, null, t, "GetEnumerator", 0,
-                                       MemberKind.Method, BindingRestriction.NoOverrides | BindingRestriction.InstanceOnly, loc) as MethodGroupExpr;
+                               bool is_dynamic = expr.Type == InternalType.Dynamic;
+                               if (is_dynamic)
+                                       expr = Convert.ImplicitConversionRequired (ec, expr, TypeManager.ienumerable_type, loc);
 
-                               if (mg == null)
+                               var get_enumerator_mg = ResolveGetEnumerator (ec);
+                               if (get_enumerator_mg == null) {
                                        return false;
-
-                               MethodSpec result = null;
-                               MethodSpec tmp_move_next = null;
-                               PropertyExpr tmp_get_cur = null;
-                               TypeSpec tmp_enumerator_type = enumerator_type;
-                               foreach (MethodSpec mi in mg.Methods) {
-                                       if (!mi.Parameters.IsEmpty)
-                                               continue;
-                       
-                                       // Check whether GetEnumerator is public
-                                       if ((mi.Modifiers & Modifiers.AccessibilityMask) != Modifiers.PUBLIC)
-                                               continue;
-
-                                       enumerator_found = true;
-
-                                       if (!GetEnumeratorFilter (ec, mi))
-                                               continue;
-
-                                       if (result != null) {
-                                               if (TypeManager.IsGenericType (result.ReturnType)) {
-                                                       if (!TypeManager.IsGenericType (mi.ReturnType))
-                                                               continue;
-
-                                                       ec.Report.SymbolRelatedToPreviousError (t);
-                                                       ec.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",
-                                                                        TypeManager.CSharpName (t), TypeManager.generic_ienumerable_type.GetSignatureForError ());
-                                                       return false;
-                                               }
-
-                                               // Always prefer generics enumerators
-                                               if (!TypeManager.IsGenericType (mi.ReturnType)) {
-                                                       if (mi.DeclaringType.ImplementsInterface (result.DeclaringType) ||
-                                                               result.DeclaringType.ImplementsInterface (mi.DeclaringType))
-                                                               continue;
-
-                                                       ec.Report.SymbolRelatedToPreviousError (result);
-                                                       ec.Report.SymbolRelatedToPreviousError (mi);
-                                                       ec.Report.Warning (278, 2, loc, "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
-                                                                       TypeManager.CSharpName (t), "enumerable", result.GetSignatureForError (), mi.GetSignatureForError ());
-                                                       return false;
-                                               }
-                                       }
-                                       result = mi;
-                                       tmp_move_next = move_next;
-                                       tmp_get_cur = get_current;
-                                       tmp_enumerator_type = enumerator_type;
-                                       if (mi.DeclaringType == t)
-                                               break;
                                }
 
-                               if (result != null) {
-                                       move_next = tmp_move_next;
-                                       get_current = tmp_get_cur;
-                                       enumerator_type = tmp_enumerator_type;
-                                       get_enumerator = new MethodGroupExpr (result, enumerator_type, loc);
-
-                                       if (t != expr.Type) {
-                                               expr = Convert.ExplicitConversion (
-                                                       ec, expr, t, loc);
-                                               if (expr == null)
-                                                       throw new InternalErrorException ();
-                                       }
-
-                                       get_enumerator.InstanceExpression = expr;
-                                       get_enumerator.IsBase = t != expr.Type;
+                               var get_enumerator = get_enumerator_mg.BestCandidate;
+                               var enumerator = new TemporaryVariable (get_enumerator.ReturnType, loc);
+                               enumerator.Resolve (ec);
 
-                                       return true;
+                               // Prepare bool MoveNext ()
+                               var move_next_mg = ResolveMoveNext (ec, get_enumerator);
+                               if (move_next_mg == null) {
+                                       return false;
                                }
 
-                               return false;
-                       }
+                               move_next_mg.InstanceExpression = enumerator;
 
-                       bool ProbeCollectionType (ResolveContext ec, TypeSpec t)
-                       {
-                               int errors = ec.Report.Errors;
-                               for (TypeSpec tt = t; tt != null && tt != TypeManager.object_type;){
-                                       if (TryType (ec, tt))
-                                               return true;
-                                       tt = tt.BaseType;
-                               }
-
-                               if (ec.Report.Errors > errors)
+                               // Prepare ~T~ Current { get; }
+                               var current_prop = ResolveCurrent (ec, get_enumerator);
+                               if (current_prop == null) {
                                        return false;
-
-                               //
-                               // Now try to find the method in the interfaces
-                               //
-                               for (TypeSpec tt = t; tt != null && tt != TypeManager.object_type; ) {
-                                       if (tt.Interfaces != null) {
-                                               foreach (TypeSpec i in tt.Interfaces) {
-                                                       if (TryType (ec, i))
-                                                               return true;
-                                               }
-                                       }
-                                       tt = tt.BaseType;
                                }
 
-                               return false;
-                       }
-
-                       public override bool Resolve (BlockContext ec)
-                       {
-                               enumerator_type = TypeManager.ienumerator_type;
-
-                               bool is_dynamic = expr.Type == InternalType.Dynamic;
-                               if (is_dynamic)
-                                       expr = Convert.ImplicitConversionRequired (ec, expr, TypeManager.ienumerable_type, loc);
-                               
-                               if (!ProbeCollectionType (ec, expr.Type)) {
-                                       Error_Enumerator (ec);
+                               var current_pe = new PropertyExpr (current_prop, loc) { InstanceExpression = enumerator }.Resolve (ec);
+                               if (current_pe == null)
                                        return false;
-                               }
 
                                VarExpr ve = var_type as VarExpr;
                                if (ve != null) {
                                        // Infer implicitly typed local variable from foreach enumerable type
-                                       var_type = new TypeExpression (
-                                               is_dynamic ? InternalType.Dynamic : get_current.Type,
-                                               var_type.Location);
+                                       var_type = new TypeExpression (current_pe.Type, var_type.Location);
                                }
 
                                var_type = var_type.ResolveAsTypeTerminal (ec, false);
                                if (var_type == null)
                                        return false;
-                                                               
-                               enumerator = new TemporaryVariable (enumerator_type, loc);
-                               enumerator.Resolve (ec);
-
-                               init = new Invocation (get_enumerator, null);
-                               init = init.Resolve (ec);
-                               if (init == null)
-                                       return false;
-
-                               Expression move_next_expr;
-                               {
-                                       var mi = new List<MemberSpec> (1) { move_next };
-                                       MethodGroupExpr mg = new MethodGroupExpr (mi, var_type.Type, loc);
-                                       mg.InstanceExpression = enumerator;
-
-                                       move_next_expr = new Invocation (mg, null);
-                               }
 
-                               get_current.InstanceExpression = enumerator;
+                               var init = new Invocation (get_enumerator_mg, null);
+                               init.Resolve (ec);
 
-                               Statement block = new CollectionForeachStatement (
-                                       var_type.Type, variable, get_current, statement, loc);
+                               statement = new While (new BooleanExpression (new Invocation (move_next_mg, null)),
+                                       new Body (var_type.Type, variable, current_pe, statement, loc), loc);
 
-                               loop = new While (new BooleanExpression (move_next_expr), block, loc);
+                               var enum_type = enumerator.Type;
 
-
-                               bool implements_idisposable = enumerator_type.ImplementsInterface (TypeManager.idisposable_type);
-                               if (implements_idisposable || !enumerator_type.IsSealed) {
-                                       wrapper = new DisposableWrapper (this, implements_idisposable);
+                               //
+                               // Add Dispose method call when enumerator can be IDisposable
+                               //
+                               if (!enumerator.Type.ImplementsInterface (TypeManager.idisposable_type)) {
+                                       if (!enum_type.IsSealed && !TypeManager.IsValueType (enum_type)) {
+                                               //
+                                               // Runtime Dispose check
+                                               //
+                                               var tv = new LocalTemporary (TypeManager.idisposable_type);
+                                               statement = new Dispose (enumerator, tv, init, statement, loc);
+                                       } else {
+                                               //
+                                               // No Dispose call needed
+                                               //
+                                               this.init = new SimpleAssign (enumerator, init);
+                                               this.init.Resolve (ec);
+                                       }
                                } else {
-                                       wrapper = new NonDisposableWrapper (this);
+                                       //
+                                       // Static Dispose check
+                                       //
+                                       statement = new Dispose (enumerator, null, init, statement, loc);
                                }
 
-                               return wrapper.Resolve (ec);
+                               return statement.Resolve (ec);
                        }
 
                        protected override void DoEmit (EmitContext ec)
                        {
-                               wrapper.Emit (ec);
-                       }
-
-                       class NonDisposableWrapper : Statement {
-                               CollectionForeach parent;
-
-                               internal NonDisposableWrapper (CollectionForeach parent)
-                               {
-                                       this.parent = parent;
-                               }
+                               if (init != null)
+                                       init.EmitStatement (ec);
 
-                               protected override void CloneTo (CloneContext clonectx, Statement target)
-                               {
-                                       throw new NotSupportedException ();
-                               }
-
-                               public override bool Resolve (BlockContext ec)
-                               {
-                                       return parent.ResolveLoop (ec);
-                               }
-
-                               protected override void DoEmit (EmitContext ec)
-                               {
-                                       parent.EmitLoopInit (ec);
-                                       parent.EmitLoopBody (ec);
-                               }
+                               statement.Emit (ec);
                        }
 
-                       sealed class DisposableWrapper : ExceptionStatement
-                       {
-                               CollectionForeach parent;
-                               bool implements_idisposable;
-
-                               internal DisposableWrapper (CollectionForeach parent, bool implements)
-                               {
-                                       this.parent = parent;
-                                       this.implements_idisposable = implements;
-                               }
+                       #region IErrorHandler Members
 
-                               protected override void CloneTo (CloneContext clonectx, Statement target)
-                               {
-                                       throw new NotSupportedException ();
-                               }
-
-                               public override bool Resolve (BlockContext ec)
-                               {
-                                       bool ok = true;
-
-                                       ec.StartFlowBranching (this);
-
-                                       if (!parent.ResolveLoop (ec))
-                                               ok = false;
-
-                                       ec.EndFlowBranching ();
-
-                                       ok &= base.Resolve (ec);
-
-                                       if (TypeManager.void_dispose_void == null) {
-                                               TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
-                                                       TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes);
-                                       }
-                                       return ok;
-                               }
-
-                               protected override void EmitPreTryBody (EmitContext ec)
-                               {
-                                       parent.EmitLoopInit (ec);
-                               }
-
-                               protected override void EmitTryBody (EmitContext ec)
-                               {
-                                       parent.EmitLoopBody (ec);
-                               }
-
-                               protected override void EmitFinallyBody (EmitContext ec)
-                               {
-                                       Expression instance = parent.enumerator;
-                                       if (!TypeManager.IsValueType (parent.enumerator_type)) {
-
-                                               parent.enumerator.Emit (ec);
-
-                                               Label call_dispose = ec.DefineLabel ();
-
-                                               if (!implements_idisposable) {
-                                                       ec.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
-                                                       LocalTemporary temp = new LocalTemporary (TypeManager.idisposable_type);
-                                                       temp.Store (ec);
-                                                       temp.Emit (ec);
-                                                       instance = temp;
-                                               }
-                                               
-                                               ec.Emit (OpCodes.Brtrue_S, call_dispose);
-
-                                               // using 'endfinally' to empty the evaluation stack
-                                               ec.Emit (OpCodes.Endfinally);
-                                               ec.MarkLabel (call_dispose);
-                                       }
-
-                                       Invocation.EmitCall (ec, false, instance, TypeManager.void_dispose_void, null, loc);
-                               }
-                       }
-
-                       bool ResolveLoop (BlockContext ec)
+                       bool MethodGroupExpr.IErrorHandler.AmbiguousCall (ResolveContext ec, MethodGroupExpr mg, MethodSpec ambiguous)
                        {
-                               return loop.Resolve (ec);
-                       }
+                               ec.Report.SymbolRelatedToPreviousError (mg.BestCandidate);
+                               ec.Report.Warning (278, 2, loc,
+                                       "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
+                                       mg.DeclaringType.GetSignatureForError (), "enumerable",
+                                       mg.BestCandidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
 
-                       void EmitLoopInit (EmitContext ec)
-                       {
-                               enumerator.EmitAssign (ec, init);
+                               return true;
                        }
 
-                       void EmitLoopBody (EmitContext ec)
+                       bool MethodGroupExpr.IErrorHandler.NoExactMatch (ResolveContext ec, MethodSpec method)
                        {
-                               loop.Emit (ec);
+                               return false;
                        }
+
+                       #endregion
                }
 
                Expression type;