2007-01-10 Chris Toshok <toshok@ximian.com>
[mono.git] / mcs / mcs / statement.cs
index ebbbb839ff4272cd7750028364e77d934648da63..e2d0752152fda1a988d891c25d17076a686d6865 100644 (file)
@@ -4,6 +4,7 @@
 // Author:
 //   Miguel de Icaza (miguel@ximian.com)
 //   Martin Baulig (martin@ximian.com)
+//   Marek Safar (marek.safar@seznam.cz)
 //
 // (C) 2001, 2002, 2003 Ximian, Inc.
 // (C) 2003, 2004 Novell, Inc.
@@ -882,8 +883,8 @@ namespace Mono.CSharp {
                                Type t = expr.Type;
                                
                                if ((t != TypeManager.exception_type) &&
-                                       !t.IsSubclassOf (TypeManager.exception_type) &&
-                                       !(expr is NullLiteral)) {
+                                   !TypeManager.IsSubclassOf (t, TypeManager.exception_type) &&
+                                   !(expr is NullLiteral)) {
                                        Error (155,
                                                "The type caught or thrown must be derived " +
                                                "from System.Exception");
@@ -962,23 +963,35 @@ namespace Mono.CSharp {
                }
        }
 
+       public abstract class Variable
+       {
+               public abstract Type Type {
+                       get;
+               }
+
+               public abstract bool HasInstance {
+                       get;
+               }
+
+               public abstract bool NeedsTemporary {
+                       get;
+               }
+
+               public abstract void EmitInstance (EmitContext ec);
+
+               public abstract void Emit (EmitContext ec);
+
+               public abstract void EmitAssign (EmitContext ec);
+
+               public abstract void EmitAddressOf (EmitContext ec);
+       }
+
        //
        // The information about a user-perceived local variable
        //
        public class LocalInfo {
                public Expression Type;
 
-               //
-               // Most of the time a variable will be stored in a LocalBuilder
-               //
-               // But sometimes, it will be stored in a field (variables that have been
-               // hoisted by iterators or by anonymous methods).  The context of the field will
-               // be stored in the EmitContext
-               //
-               //
-               public LocalBuilder LocalBuilder;
-               public FieldBuilder FieldBuilder;
-
                public Type VariableType;
                public readonly string Name;
                public readonly Location Location;
@@ -986,6 +999,11 @@ namespace Mono.CSharp {
 
                public VariableInfo VariableInfo;
 
+               Variable var;
+               public Variable Variable {
+                       get { return var; }
+               }
+
                [Flags]
                enum Flags : byte {
                        Used = 1,
@@ -1006,6 +1024,7 @@ namespace Mono.CSharp {
 
                Flags flags;
                ReadOnlyContext ro_context;
+               LocalBuilder builder;
                
                public LocalInfo (Expression type, string name, Block block, Location l)
                {
@@ -1017,23 +1036,35 @@ namespace Mono.CSharp {
 
                public LocalInfo (DeclSpace ds, Block block, Location l)
                {
-                       VariableType = ds.TypeBuilder;
+                       VariableType = ds.IsGeneric ? ds.CurrentType : ds.TypeBuilder;
                        Block = block;
                        Location = l;
                }
 
-               public void DeclareLocal (ILGenerator ig)
+               public void ResolveVariable (EmitContext ec)
                {
-                       if (Pinned) {
-                               //
-                               // This is needed to compile on both .NET 1.x and .NET 2.x
-                               // the later introduced `DeclareLocal (Type t, bool pinned)'
-                               //
-                               LocalBuilder = TypeManager.DeclareLocalPinned (ig, VariableType);
-                               return;
+                       Block theblock = Block;
+                       if (theblock.ScopeInfo != null)
+                               var = theblock.ScopeInfo.GetCapturedVariable (this);
+
+                       if (var == null) {
+                               if (Pinned)
+                                       //
+                                       // This is needed to compile on both .NET 1.x and .NET 2.x
+                                       // the later introduced `DeclareLocal (Type t, bool pinned)'
+                                       //
+                                       builder = TypeManager.DeclareLocalPinned (ec.ig, VariableType);
+                               else
+                                       builder = ec.ig.DeclareLocal (VariableType);
+
+                               var = new LocalVariable (this, builder);
                        }
-                       if (!IsThis && !IsConstant)
-                               LocalBuilder = ig.DeclareLocal (VariableType);
+               }
+
+               public void EmitSymbolInfo (EmitContext ec, string name)
+               {
+                       if (builder != null)
+                               ec.DefineLocalVariable (name, builder);
                }
 
                public bool IsThisAssigned (EmitContext ec, Location loc)
@@ -1184,6 +1215,50 @@ namespace Mono.CSharp {
                                flags = value ? (flags | Flags.IsThis) : (flags & ~Flags.IsThis);
                        }
                }
+
+               protected class LocalVariable : Variable
+               {
+                       public readonly LocalInfo LocalInfo;
+                       LocalBuilder builder;
+
+                       public LocalVariable (LocalInfo local, LocalBuilder builder)
+                       {
+                               this.LocalInfo = local;
+                               this.builder = builder;
+                       }
+
+                       public override Type Type {
+                               get { return LocalInfo.VariableType; }
+                       }
+
+                       public override bool HasInstance {
+                               get { return false; }
+                       }
+
+                       public override bool NeedsTemporary {
+                               get { return false; }
+                       }
+
+                       public override void EmitInstance (EmitContext ec)
+                       {
+                               // Do nothing.
+                       }
+
+                       public override void Emit (EmitContext ec)
+                       {
+                               ec.ig.Emit (OpCodes.Ldloc, builder);
+                       }
+
+                       public override void EmitAssign (EmitContext ec)
+                       {
+                               ec.ig.Emit (OpCodes.Stloc, builder);
+                       }
+
+                       public override void EmitAddressOf (EmitContext ec)
+                       {
+                               ec.ig.Emit (OpCodes.Ldloca, builder);
+                       }
+               }
        }
                
        /// <summary>
@@ -1217,7 +1292,9 @@ namespace Mono.CSharp {
                        IsDestructor = 32,
                        IsToplevel = 64,
                        Unsafe = 128,
-                       HasVarargs = 256 // Used in ToplevelBlock
+                       HasVarargs = 256, // Used in ToplevelBlock
+                       IsIterator = 512
+
                }
                protected Flags flags;
 
@@ -1238,7 +1315,7 @@ namespace Mono.CSharp {
                //
                // The statements in this block
                //
-               ArrayList statements;
+               protected ArrayList statements;
                int num_statements;
 
                //
@@ -1274,6 +1351,10 @@ namespace Mono.CSharp {
                //
                Block switch_block;
 
+               ExpressionStatement scope_init;
+
+               ArrayList anonymous_children;
+
                protected static int id;
 
                int this_id;
@@ -1327,7 +1408,7 @@ namespace Mono.CSharp {
                        get { return this_id; }
                }
 
-               protected IDictionary Variables {
+               public IDictionary Variables {
                        get {
                                if (variables == null)
                                        variables = new ListDictionary ();
@@ -1348,6 +1429,12 @@ namespace Mono.CSharp {
                        EndLocation = loc;
                }
 
+               protected static void Error_158 (string name, Location loc)
+               {
+                       Report.Error (158, loc, "The label `{0}' shadows another label " +
+                                     "by the same name in a contained scope.", name);
+               }
+
                /// <summary>
                ///   Adds a label to the current block. 
                /// </summary>
@@ -1367,7 +1454,8 @@ namespace Mono.CSharp {
                        Block cur = this;
                        while (cur != null) {
                                if (cur.DoLookupLabel (name) != null) {
-                                       Report.Error (140, target.loc, "The label `{0}' is a duplicate", name);
+                                       Report.Error (140, target.loc,
+                                                     "The label `{0}' is a duplicate", name);
                                        return false;
                                }
 
@@ -1379,10 +1467,7 @@ namespace Mono.CSharp {
 
                        while (cur != null) {
                                if (cur.DoLookupLabel (name) != null) {
-                                       Report.Error (
-                                               158, target.loc,
-                                               "The label `{0}' shadows another label by the same name in a contained scope.",
-                                               name);
+                                       Error_158 (name, target.loc);
                                        return false;
                                }
 
@@ -1392,18 +1477,16 @@ namespace Mono.CSharp {
                                                if (s == null)
                                                        continue;
 
-                                               Report.Error (
-                                                       158, s.loc,
-                                                       "The label `{0}' shadows another label by the same name in a contained scope.",
-                                                       name);
+                                               Error_158 (name, target.loc);
                                                return false;
                                        }
                                }
 
-
                                cur = cur.Parent;
                        }
 
+                       Toplevel.CheckError158 (name, target.loc);
+
                        if (labels == null)
                                labels = new Hashtable ();
 
@@ -1459,24 +1542,37 @@ namespace Mono.CSharp {
                        known_variables [name] = info;
                }
 
-               LocalInfo GetKnownVariableInfo (string name)
+               LocalInfo GetKnownVariableInfo (string name, bool recurse)
                {
-                       if (known_variables == null)
+                       if (known_variables != null) {
+                               LocalInfo vi = (LocalInfo) known_variables [name];
+                               if (vi != null)
+                                       return vi;
+                       }
+
+                       if (!recurse || (children == null))
                                return null;
-                       return (LocalInfo) known_variables [name];
+
+                       foreach (Block block in children) {
+                               LocalInfo vi = block.GetKnownVariableInfo (name, true);
+                               if (vi != null)
+                                       return vi;
+                       }
+
+                       return null;
                }
 
                public bool CheckInvariantMeaningInBlock (string name, Expression e, Location loc)
                {
                        Block b = this;
-                       LocalInfo kvi = b.GetKnownVariableInfo (name);
+                       LocalInfo kvi = b.GetKnownVariableInfo (name, true);
                        while (kvi == null) {
                                while (b.Implicit)
                                        b = b.Parent;
                                b = b.Parent;
                                if (b == null)
                                        return true;
-                               kvi = b.GetKnownVariableInfo (name);
+                               kvi = b.GetKnownVariableInfo (name, false);
                        }
 
                        if (kvi.Block == b)
@@ -1522,6 +1618,103 @@ namespace Mono.CSharp {
                        return false;
                }
 
+               public bool CheckError136_InParents (string name, Location loc)
+               {
+                       for (Block b = Parent; b != null; b = b.Parent) {
+                               if (!b.DoCheckError136 (name, "parent or current", loc))
+                                       return false;
+                       }
+
+                       for (Block b = Toplevel.ContainerBlock; b != null; b = b.Toplevel.ContainerBlock) {
+                               if (!b.CheckError136_InParents (name, loc))
+                                       return false;
+                       }
+
+                       return true;
+               }
+
+               public bool CheckError136_InChildren (string name, Location loc)
+               {
+                       if (!DoCheckError136_InChildren (name, loc))
+                               return false;
+
+                       Block b = this;
+                       while (b.Implicit) {
+                               if (!b.Parent.DoCheckError136_InChildren (name, loc))
+                                       return false;
+                               b = b.Parent;
+                       }
+
+                       return true;
+               }
+
+               protected bool DoCheckError136_InChildren (string name, Location loc)
+               {
+                       if (!DoCheckError136 (name, "child", loc))
+                               return false;
+
+                       if (AnonymousChildren != null) {
+                               foreach (ToplevelBlock child in AnonymousChildren) {
+                                       if (!child.DoCheckError136_InChildren (name, loc))
+                                               return false;
+                               }
+                       }
+
+                       if (children != null) {
+                               foreach (Block child in children) {
+                                       if (!child.DoCheckError136_InChildren (name, loc))
+                                               return false;
+                               }
+                       }
+
+                       return true;
+               }
+
+               public bool CheckError136 (string name, string scope, bool check_parents,
+                                          bool check_children, Location loc)
+               {
+                       if (!DoCheckError136 (name, scope, loc))
+                               return false;
+
+                       if (check_parents) {
+                               if (!CheckError136_InParents (name, loc))
+                                       return false;
+                       }
+
+                       if (check_children) {
+                               if (!CheckError136_InChildren (name, loc))
+                                       return false;
+                       }
+
+                       for (Block c = Toplevel.ContainerBlock; c != null; c = c.Toplevel.ContainerBlock) {
+                               if (!c.DoCheckError136 (name, "parent or current", loc))
+                                       return false;
+                       }
+
+                       return true;
+               }
+
+               protected bool DoCheckError136 (string name, string scope, Location loc)
+               {
+                       LocalInfo vi = GetKnownVariableInfo (name, false);
+                       if (vi != null) {
+                               Report.SymbolRelatedToPreviousError (vi.Location, name);
+                               Error_AlreadyDeclared (loc, name, scope != null ? scope : "child");
+                               return false;
+                       }
+
+                       int idx;
+                       Parameter p = Toplevel.Parameters.GetParameterByName (name, out idx);
+                       if (p != null) {
+                               Report.SymbolRelatedToPreviousError (p.Location, name);
+                               Error_AlreadyDeclared (
+                                       loc, name, scope != null ? scope : "method argument");
+                               return false;
+                       }
+
+                       return true;
+               }
+
                public LocalInfo AddVariable (Expression type, string name, Location l)
                {
                        LocalInfo vi = GetLocalInfo (name);
@@ -1535,27 +1728,12 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       vi = GetKnownVariableInfo (name);
-                       if (vi != null) {
-                               Report.SymbolRelatedToPreviousError (vi.Location, name);
-                               Error_AlreadyDeclared (l, name, "child");
-                               return null;
-                       }
-
-                       int idx;
-                       Parameter p = Toplevel.Parameters.GetParameterByName (name, out idx);
-                       if (p != null) {
-                               Report.SymbolRelatedToPreviousError (p.Location, name);
-                               Error_AlreadyDeclared (l, name, "method argument");
+                       if (!CheckError136 (name, null, true, true, l))
                                return null;
-                       }
 
                        vi = new LocalInfo (type, name, this, l);
-
                        Variables.Add (name, vi);
-
-                       for (Block b = this; b != null; b = b.Parent)
-                               b.AddKnownVariable (name, vi);
+                       AddKnownVariable (name, vi);
 
                        if ((flags & Flags.VariablesInitialized) != 0)
                                throw new Exception ();
@@ -1565,8 +1743,10 @@ namespace Mono.CSharp {
 
                void Error_AlreadyDeclared (Location loc, string var, string reason)
                {
-                       Report.Error (136, loc, "A local variable named `{0}' cannot be declared in this scope because it would give a different meaning to `{0}', " +
-                               "which is already used in a `{1}' scope", var, reason);
+                       Report.Error (136, loc, "A local variable named `{0}' cannot be declared " +
+                                     "in this scope because it would give a different meaning " +
+                                     "to `{0}', which is already used in a `{1}' scope " +
+                                     "to denote something else", var, reason);
                }
 
                public bool AddConstant (Expression type, string name, Expression value, Location l)
@@ -1588,6 +1768,8 @@ namespace Mono.CSharp {
 
                public LocalInfo AddTemporaryVariable (TypeExpr te, Location loc)
                {
+                       Report.Debug (64, "ADD TEMPORARY", this, Toplevel, loc);
+
                        if (temporary_variables == null)
                                temporary_variables = new ArrayList ();
 
@@ -1678,6 +1860,28 @@ namespace Mono.CSharp {
                        }
                }
 
+               public ScopeInfo ScopeInfo;
+
+               public ScopeInfo CreateScopeInfo ()
+               {
+                       if (ScopeInfo == null)
+                               ScopeInfo = ScopeInfo.CreateScope (this);
+
+                       return ScopeInfo;
+               }
+
+               public ArrayList AnonymousChildren {
+                       get { return anonymous_children; }
+               }
+
+               public void AddAnonymousChild (ToplevelBlock b)
+               {
+                       if (anonymous_children == null)
+                               anonymous_children = new ArrayList ();
+
+                       anonymous_children.Add (b);
+               }
+
                /// <summary>
                ///   Emits the variable declarations and labels.
                /// </summary>
@@ -1687,6 +1891,8 @@ namespace Mono.CSharp {
                /// </remarks>
                public void ResolveMeta (ToplevelBlock toplevel, EmitContext ec, Parameters ip)
                {
+                       Report.Debug (64, "BLOCK RESOLVE META", this, Parent, toplevel);
+
                        // If some parent block was unsafe, we remain unsafe even if this block
                        // isn't explicitly marked as such.
                        using (ec.With (EmitContext.Flags.InUnsafe, ec.InUnsafe | Unsafe)) {
@@ -1750,6 +1956,11 @@ namespace Mono.CSharp {
                                                // which in turn causes the 'must be constant' error to be triggered.
                                                constants.Remove (name);
 
+                                               if (!Const.IsConstantTypeValid (variable_type)) {
+                                                       Const.Error_InvalidConstantType (variable_type, loc);
+                                                       continue;
+                                               }
+
                                                using (ec.With (EmitContext.Flags.ConstantCheckState, (flags & Flags.Unchecked) == 0)) {
                                                        ec.CurrentBlock = this;
                                                        Expression e = cv.Resolve (ec);
@@ -1758,11 +1969,11 @@ namespace Mono.CSharp {
 
                                                        Constant ce = e as Constant;
                                                        if (ce == null) {
-                                                               Const.Error_ExpressionMustBeConstant (variable_type, vi.Location, name);
+                                                               Const.Error_ExpressionMustBeConstant (vi.Location, name);
                                                                continue;
                                                        }
 
-                                                       e = ce.ToType (variable_type, vi.Location);
+                                                       e = ce.ImplicitConversionRequired (variable_type, vi.Location);
                                                        if (e == null)
                                                                continue;
 
@@ -1790,39 +2001,23 @@ namespace Mono.CSharp {
                //
                // Emits the local variable declarations for a block
                //
-               public void EmitMeta (EmitContext ec)
+               public virtual void EmitMeta (EmitContext ec)
                {
-                       ILGenerator ig = ec.ig;
-                       
-                       if (variables != null){
-                               bool have_captured_vars = ec.HaveCapturedVariables ();
-                               
-                               foreach (DictionaryEntry de in variables){
-                                       LocalInfo vi = (LocalInfo) de.Value;
-
-                                       if (have_captured_vars && ec.IsCaptured (vi))
-                                               continue;
+                       Report.Debug (64, "BLOCK EMIT META", this, Parent, Toplevel, ScopeInfo, ec);
+                       if (ScopeInfo != null) {
+                               scope_init = ScopeInfo.GetScopeInitializer (ec);
+                               Report.Debug (64, "BLOCK EMIT META #1", this, Toplevel, ScopeInfo,
+                                             ec, scope_init);
+                       }
 
-                                       vi.DeclareLocal (ig);
-                               }
+                       if (variables != null){
+                               foreach (LocalInfo vi in variables.Values)
+                                       vi.ResolveVariable (ec);
                        }
 
                        if (temporary_variables != null) {
-                               AnonymousContainer am = ec.CurrentAnonymousMethod;
-                               TypeBuilder scope = null;
-                               if ((am != null) && am.IsIterator) {
-                                       scope = am.Scope.ScopeTypeBuilder;
-                                       if (scope == null)
-                                               throw new InternalErrorException ();
-                               }
-                               foreach (LocalInfo vi in temporary_variables) {
-                                       if (scope != null) {
-                                               if (vi.FieldBuilder == null)
-                                                       vi.FieldBuilder = scope.DefineField (
-                                                               vi.Name, vi.VariableType, FieldAttributes.Assembly);
-                                       } else
-                                               vi.LocalBuilder = ig.DeclareLocal (vi.VariableType);
-                               }
+                               foreach (LocalInfo vi in temporary_variables)
+                                       vi.ResolveVariable (ec);
                        }
 
                        if (children != null){
@@ -1899,6 +2094,12 @@ namespace Mono.CSharp {
 
                        Report.Debug (4, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching);
 
+                       //
+                       // This flag is used to notate nested statements as unreachable from the beginning of this block.
+                       // For the purposes of this resolution, it doesn't matter that the whole block is unreachable 
+                       // from the beginning of the function.  The outer Resolve() that detected the unreachability is
+                       // responsible for handling the situation.
+                       //
                        int statement_count = statements.Count;
                        for (int ix = 0; ix < statement_count; ix++){
                                Statement s = (Statement) statements [ix];
@@ -2029,26 +2230,26 @@ namespace Mono.CSharp {
                        if (emit_debug_info) {
                                if (is_lexical_block)
                                        ec.BeginScope ();
+                       }
+                       ec.Mark (StartLocation, true);
+                       if (scope_init != null)
+                               scope_init.EmitStatement (ec);
+                       DoEmit (ec);
+                       ec.Mark (EndLocation, true); 
+
+                       if (emit_debug_info) {
+                               if (is_lexical_block)
+                                       ec.EndScope ();
 
                                if (variables != null) {
                                        foreach (DictionaryEntry de in variables) {
                                                string name = (string) de.Key;
                                                LocalInfo vi = (LocalInfo) de.Value;
 
-                                               if (vi.LocalBuilder == null)
-                                                       continue;
-
-                                               ec.DefineLocalVariable (name, vi.LocalBuilder);
+                                               vi.EmitSymbolInfo (ec, name);
                                        }
                                }
                        }
-                       ec.Mark (StartLocation, true);
-                       ec.EmitScopeInitFromBlock (this);
-                       DoEmit (ec);
-                       ec.Mark (EndLocation, true); 
-
-                       if (emit_debug_info && is_lexical_block)
-                               ec.EndScope ();
 
                        ec.CurrentBlock = prev_block;
                }
@@ -2087,64 +2288,87 @@ namespace Mono.CSharp {
                // Pointer to the host of this anonymous method, or null
                // if we are the topmost block
                //
-               ToplevelBlock container;
-               CaptureContext capture_context;
+               Block container;
+               ToplevelBlock child;    
+               GenericMethod generic;
                FlowBranchingToplevel top_level_branching;
-
-               Hashtable capture_contexts;
-               ArrayList children;
+               AnonymousContainer anonymous_container;
+               RootScopeInfo root_scope;
 
                public bool HasVarargs {
                        get { return (flags & Flags.HasVarargs) != 0; }
                        set { flags |= Flags.HasVarargs; }
                }
 
+               public bool IsIterator {
+                       get { return (flags & Flags.IsIterator) != 0; }
+               }
+
                //
                // The parameters for the block.
                //
-               public readonly Parameters Parameters;
-                       
-               public void RegisterCaptureContext (CaptureContext cc)
-               {
-                       if (capture_contexts == null)
-                               capture_contexts = new Hashtable ();
-                       capture_contexts [cc] = cc;
+               Parameters parameters;
+               public Parameters Parameters {
+                       get { return parameters; }
                }
 
-               public void CompleteContexts ()
+               public bool CompleteContexts (EmitContext ec)
                {
-                       if (capture_contexts == null)
-                               return;
+                       Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS", this,
+                                     container, root_scope);
+
+                       if (root_scope != null)
+                               root_scope.LinkScopes ();
+
+                       if ((container == null) && (root_scope != null)) {
+                               Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS #1", this,
+                                             root_scope);
 
-                       foreach (CaptureContext cc in capture_contexts.Keys){
-                               cc.LinkScopes ();
+                               if (root_scope.DefineType () == null)
+                                       return false;
+                               if (!root_scope.ResolveType ())
+                                       return false;
+                               if (!root_scope.ResolveMembers ())
+                                       return false;
+                               if (!root_scope.DefineMembers ())
+                                       return false;
                        }
+
+                       return true;
                }
 
-               public CaptureContext ToplevelBlockCaptureContext {
-                       get { return capture_context; }
+               public GenericMethod GenericMethod {
+                       get { return generic; }
                }
 
                public ToplevelBlock Container {
-                       get { return container; }
+                       get { return container != null ? container.Toplevel : null; }
                }
 
-               protected void AddChild (ToplevelBlock block)
-               {
-                       if (children == null)
-                               children = new ArrayList ();
+               public Block ContainerBlock {
+                       get { return container; }
+               }
 
-                       children.Add (block);
+               public AnonymousContainer AnonymousContainer {
+                       get { return anonymous_container; }
+                       set { anonymous_container = value; }
                }
 
                //
                // Parent is only used by anonymous blocks to link back to their
                // parents
                //
-               public ToplevelBlock (ToplevelBlock container, Parameters parameters, Location start) :
+               public ToplevelBlock (Block container, Parameters parameters, Location start) :
                        this (container, (Flags) 0, parameters, start)
                {
                }
+
+               public ToplevelBlock (Block container, Parameters parameters, GenericMethod generic,
+                                     Location start) :
+                       this (container, parameters, start)
+               {
+                       this.generic = generic;
+               }
                
                public ToplevelBlock (Parameters parameters, Location start) :
                        this (null, (Flags) 0, parameters, start)
@@ -2156,28 +2380,78 @@ namespace Mono.CSharp {
                {
                }
 
-               public ToplevelBlock (ToplevelBlock container, Flags flags, Parameters parameters, Location start) :
+               public ToplevelBlock (Block container, Flags flags, Parameters parameters, Location start) :
                        base (null, flags | Flags.IsToplevel, start, Location.Null)
                {
-                       Parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters;
+                       this.parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters;
                        this.container = container;
-
-                       if (container != null)
-                               container.AddChild (this);
                }
 
                public ToplevelBlock (Location loc) : this (null, (Flags) 0, null, loc)
                {
                }
 
-               public void SetHaveAnonymousMethods (Location loc, AnonymousContainer host)
+               public bool CheckError158 (string name, Location loc)
                {
-                       if (capture_context == null)
-                               capture_context = new CaptureContext (this, loc, host);
+                       if (AnonymousChildren != null) {
+                               foreach (ToplevelBlock child in AnonymousChildren) {
+                                       if (!child.CheckError158 (name, loc))
+                                               return false;
+                               }
+                       }
+
+                       for (ToplevelBlock c = Container; c != null; c = c.Container) {
+                               if (!c.DoCheckError158 (name, loc))
+                                       return false;
+                       }
+
+                       return true;
                }
 
-               public CaptureContext CaptureContext {
-                       get { return capture_context; }
+               bool DoCheckError158 (string name, Location loc)
+               {
+                       LabeledStatement s = LookupLabel (name);
+                       if (s != null) {
+                               Error_158 (name, loc);
+                               return false;
+                       }
+
+                       return true;
+               }
+
+               public RootScopeInfo CreateRootScope (TypeContainer host)
+               {
+                       if (root_scope != null)
+                               return root_scope;
+
+                       if (Container == null)
+                               root_scope = new RootScopeInfo (
+                                       this, host, generic, StartLocation);
+
+                       ScopeInfo = root_scope;
+                       return root_scope;
+               }
+
+               public void CreateIteratorHost (RootScopeInfo root)
+               {
+                       Report.Debug (64, "CREATE ITERATOR HOST", this, root,
+                                     container, root_scope);
+
+                       if ((container != null) || (root_scope != null))
+                               throw new InternalErrorException ();
+
+                       ScopeInfo = root_scope = root;
+               }
+
+               public RootScopeInfo RootScope {
+                       get {
+                               if (root_scope != null)
+                                       return root_scope;
+                               else if (Container != null)
+                                       return Container.RootScope;
+                               else
+                                       return null;
+                       }
                }
 
                public FlowBranchingToplevel TopLevelBranching {
@@ -2193,15 +2467,11 @@ namespace Mono.CSharp {
                // null.  Later on, when resolving the iterator, we need to move the
                // anonymous method into that iterator.
                //
-               public void ReParent (ToplevelBlock new_parent, AnonymousContainer new_host)
+               public void ReParent (ToplevelBlock new_parent)
                {
-                       foreach (ToplevelBlock block in children) {
-                               if (block.CaptureContext == null)
-                                       continue;
-
-                               block.container = new_parent;
-                               block.CaptureContext.ReParent (new_parent, new_host);
-                       }
+                       container = new_parent;
+                       Parent = new_parent;
+                       new_parent.child = this;
                }
 
                //
@@ -2286,12 +2556,71 @@ namespace Mono.CSharp {
                        if (top_level_branching != null)
                                return true;
 
+                       if (ip != null)
+                               parameters = ip;
+
+                       if (!IsIterator && (container != null) && (parameters != null)) {
+                               foreach (Parameter p in parameters.FixedParameters) {
+                                       if (!CheckError136_InParents (p.Name, loc))
+                                               return false;
+                               }
+                       }
+
                        ResolveMeta (this, ec, ip);
 
+                       if (child != null)
+                               child.ResolveMeta (this, ec, ip);
+
                        top_level_branching = ec.StartFlowBranching (this);
 
                        return Report.Errors == errors;
                }
+
+               public override void EmitMeta (EmitContext ec)
+               {
+                       base.EmitMeta (ec);
+                       parameters.ResolveVariable (this);
+               }
+
+               public void MakeIterator (Iterator iterator)
+               {
+                       flags |= Flags.IsIterator;
+
+                       Block block = new Block (this);
+                       foreach (Statement stmt in statements)
+                               block.AddStatement (stmt);
+                       statements = new ArrayList ();
+                       statements.Add (new MoveNextStatement (iterator, block));
+               }
+
+               protected class MoveNextStatement : Statement {
+                       Iterator iterator;
+                       Block block;
+
+                       public MoveNextStatement (Iterator iterator, Block block)
+                       {
+                               this.iterator = iterator;
+                               this.block = block;
+                               this.loc = iterator.Location;
+                       }
+
+                       public override bool Resolve (EmitContext ec)
+                       {
+                               return block.Resolve (ec);
+                       }
+
+                       protected override void DoEmit (EmitContext ec)
+                       {
+                               iterator.EmitMoveNext (ec, block);
+                       }
+               }
+
+               public override string ToString ()
+               {
+                       return String.Format ("{0} ({1}:{2}{3}:{4})", GetType (), ID, StartLocation,
+                                             root_scope, anonymous_container != null ?
+                                             anonymous_container.Scope : null);
+               }
        }
        
        public class SwitchLabel {
@@ -2349,7 +2678,7 @@ namespace Mono.CSharp {
                // Resolves the expression, reduces it to a literal if possible
                // and then converts it to the requested type.
                //
-               public bool ResolveAndReduce (EmitContext ec, Type required_type)
+               public bool ResolveAndReduce (EmitContext ec, Type required_type, bool allow_nullable)
                {       
                        Expression e = label.Resolve (ec);
 
@@ -2367,7 +2696,12 @@ namespace Mono.CSharp {
                                return true;
                        }
 
-                       c = c.ToType (required_type, loc);
+                       if (allow_nullable && c.GetValue () == null) {
+                               converted = NullStringCase;
+                               return true;
+                       }
+
+                       c = c.ImplicitConversionRequired (required_type, loc);
                        if (c == null)
                                return false;
 
@@ -2419,11 +2753,27 @@ namespace Mono.CSharp {
                // Computed
                //
                Label default_target;
+               Label null_target;
                Expression new_expr;
                bool is_constant;
                SwitchSection constant_section;
                SwitchSection default_section;
 
+#if GMCS_SOURCE
+               //
+               // Nullable Types support for GMCS.
+               //
+               Nullable.Unwrap unwrap;
+
+               protected bool HaveUnwrap {
+                       get { return unwrap != null; }
+               }
+#else
+               protected bool HaveUnwrap {
+                       get { return false; }
+               }
+#endif
+
                //
                // The types allowed to be implicitly cast from
                // on the governing type
@@ -2455,8 +2805,10 @@ namespace Mono.CSharp {
                // expression that includes any potential conversions to the
                // integral types or to string.
                //
-               Expression SwitchGoverningType (EmitContext ec, Type t)
+               Expression SwitchGoverningType (EmitContext ec, Expression expr)
                {
+                       Type t = expr.Type;
+
                        if (t == TypeManager.byte_type ||
                            t == TypeManager.sbyte_type ||
                            t == TypeManager.ushort_type ||
@@ -2469,7 +2821,7 @@ namespace Mono.CSharp {
                            t == TypeManager.string_type ||
                            t == TypeManager.bool_type ||
                            t.IsSubclassOf (TypeManager.enum_type))
-                               return Expr;
+                               return expr;
 
                        if (allowed_types == null){
                                allowed_types = new Type [] {
@@ -2497,7 +2849,7 @@ namespace Mono.CSharp {
                        foreach (Type tt in allowed_types){
                                Expression e;
                                
-                               e = Convert.ImplicitUserConversion (ec, Expr, tt, loc);
+                               e = Convert.ImplicitUserConversion (ec, expr, tt, loc);
                                if (e == null)
                                        continue;
 
@@ -2512,7 +2864,7 @@ namespace Mono.CSharp {
                                        Report.ExtraInformation (
                                                loc,
                                                String.Format ("reason: more than one conversion to an integral type exist for type {0}",
-                                                              TypeManager.CSharpName (Expr.Type)));
+                                                              TypeManager.CSharpName (expr.Type)));
                                        return null;
                                }
 
@@ -2546,7 +2898,7 @@ namespace Mono.CSharp {
                                                continue;
                                        }
 
-                                       if (!sl.ResolveAndReduce (ec, SwitchType)){
+                                       if (!sl.ResolveAndReduce (ec, SwitchType, HaveUnwrap)) {
                                                error = true;
                                                continue;
                                        }
@@ -2554,11 +2906,10 @@ namespace Mono.CSharp {
                                        object key = sl.Converted;
                                        try {
                                                Elements.Add (key, sl);
+                                       } catch (ArgumentException) {
+                                               sl.Erorr_AlreadyOccurs ();
+                                               error = true;
                                        }
-                                       catch (ArgumentException) {
-                                                sl.Erorr_AlreadyOccurs ();
-                                                error = true;
-                                        }
                                }
                        }
                        return !error;
@@ -2822,20 +3173,30 @@ namespace Mono.CSharp {
 
                        // now emit the code for the sections
                        bool fFoundDefault = false;
+                       bool fFoundNull = false;
+                       foreach (SwitchSection ss in Sections)
+                       {
+                               foreach (SwitchLabel sl in ss.Labels)
+                                       if (sl.Converted == SwitchLabel.NullStringCase)
+                                               fFoundNull = true;
+                       }
+
                        foreach (SwitchSection ss in Sections)
                        {
                                foreach (SwitchLabel sl in ss.Labels)
                                {
                                        ig.MarkLabel (sl.GetILLabel (ec));
                                        ig.MarkLabel (sl.GetILLabelCode (ec));
-                                       if (sl.Label == null)
-                                       {
+                                       if (sl.Converted == SwitchLabel.NullStringCase)
+                                               ig.MarkLabel (null_target);
+                                       else if (sl.Label == null) {
                                                ig.MarkLabel (lblDefault);
                                                fFoundDefault = true;
+                                               if (!fFoundNull)
+                                                       ig.MarkLabel (null_target);
                                        }
                                }
                                ss.Block.Emit (ec);
-                               //ig.Emit (OpCodes.Br, lblEnd);
                        }
                        
                        if (!fFoundDefault) {
@@ -2854,7 +3215,6 @@ namespace Mono.CSharp {
                        ILGenerator ig = ec.ig;
                        Label end_of_switch = ig.DefineLabel ();
                        Label next_test = ig.DefineLabel ();
-                       Label null_target = ig.DefineLabel ();
                        bool first_test = true;
                        bool pending_goto_end = false;
                        bool null_marked = false;
@@ -2959,7 +3319,18 @@ namespace Mono.CSharp {
                        if (Expr == null)
                                return false;
 
-                       new_expr = SwitchGoverningType (ec, Expr.Type);
+                       new_expr = SwitchGoverningType (ec, Expr);
+
+#if GMCS_SOURCE
+                       if ((new_expr == null) && TypeManager.IsNullableType (Expr.Type)) {
+                               unwrap = Nullable.Unwrap.Create (Expr, ec);
+                               if (unwrap == null)
+                                       return false;
+
+                               new_expr = SwitchGoverningType (ec, unwrap);
+                       }
+#endif
+
                        if (new_expr == null){
                                Report.Error (151, loc, "A value of an integral type or string expected for switch");
                                return false;
@@ -2971,6 +3342,9 @@ namespace Mono.CSharp {
                        if (!CheckSwitch (ec))
                                return false;
 
+                       if (HaveUnwrap)
+                               Elements.Remove (SwitchLabel.NullStringCase);
+
                        Switch old_switch = ec.Switch;
                        ec.Switch = this;
                        ec.Switch.SwitchType = SwitchType;
@@ -3026,17 +3400,26 @@ namespace Mono.CSharp {
                {
                        ILGenerator ig = ec.ig;
 
+                       default_target = ig.DefineLabel ();
+                       null_target = ig.DefineLabel ();
+
                        // Store variable for comparission purposes
                        LocalBuilder value;
-                       if (!is_constant) {
+                       if (HaveUnwrap) {
+                               value = ig.DeclareLocal (SwitchType);
+#if GMCS_SOURCE
+                               unwrap.EmitCheck (ec);
+                               ig.Emit (OpCodes.Brfalse, null_target);
+                               new_expr.Emit (ec);
+                               ig.Emit (OpCodes.Stloc, value);
+#endif
+                       } else if (!is_constant) {
                                value = ig.DeclareLocal (SwitchType);
                                new_expr.Emit (ec);
                                ig.Emit (OpCodes.Stloc, value);
                        } else
                                value = null;
 
-                       default_target = ig.DefineLabel ();
-
                        //
                        // Setup the codegen context
                        //
@@ -3261,7 +3644,7 @@ namespace Mono.CSharp {
                        }
 
                        public abstract void Emit (EmitContext ec);
-                       public abstract void EmitExit (ILGenerator ig);
+                       public abstract void EmitExit (EmitContext ec);
                }
 
                class ExpressionEmitter : Emitter {
@@ -3275,14 +3658,14 @@ namespace Mono.CSharp {
                                // Store pointer in pinned location
                                //
                                converted.Emit (ec);
-                               ec.ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
+                               vi.Variable.EmitAssign (ec);
                        }
 
-                       public override void EmitExit (ILGenerator ig)
+                       public override void EmitExit (EmitContext ec)
                        {
-                               ig.Emit (OpCodes.Ldc_I4_0);
-                               ig.Emit (OpCodes.Conv_U);
-                               ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
+                               ec.ig.Emit (OpCodes.Ldc_I4_0);
+                               ec.ig.Emit (OpCodes.Conv_U);
+                               vi.Variable.EmitAssign (ec);
                        }
                }
 
@@ -3312,13 +3695,13 @@ namespace Mono.CSharp {
                                        return;
 
                                converted.Emit (ec);
-                               ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
+                               vi.Variable.EmitAssign (ec);
                        }
 
-                       public override void EmitExit(ILGenerator ig)
+                       public override void EmitExit (EmitContext ec)
                        {
-                               ig.Emit (OpCodes.Ldnull);
-                               ig.Emit (OpCodes.Stloc, pinned_string);
+                               ec.ig.Emit (OpCodes.Ldnull);
+                               ec.ig.Emit (OpCodes.Stloc, pinned_string);
                        }
                }
 
@@ -3405,7 +3788,7 @@ namespace Mono.CSharp {
                                                return false;
 
                                        if (!Convert.ImplicitConversionExists (ec, e, expr_type)) {
-                                               e.Error_ValueCannotBeConverted (e.Location, expr_type, false);
+                                               e.Error_ValueCannotBeConverted (ec, e.Location, expr_type, false);
                                                return false;
                                        }
 
@@ -3516,13 +3899,11 @@ namespace Mono.CSharp {
                        if (has_ret)
                                return;
 
-                       ILGenerator ig = ec.ig;
-
                        //
                        // Clear the pinned variable
                        //
                        for (int i = 0; i < data.Length; i++) {
-                               data [i].EmitExit (ig);
+                               data [i].EmitExit (ec);
                        }
                }
        }
@@ -3558,6 +3939,34 @@ namespace Mono.CSharp {
 
                protected override void DoEmit(EmitContext ec)
                {
+                       ILGenerator ig = ec.ig;
+
+                       if (CatchType != null)
+                               ig.BeginCatchBlock (CatchType);
+                       else
+                               ig.BeginCatchBlock (TypeManager.object_type);
+
+                       if (VarBlock != null)
+                               VarBlock.Emit (ec);
+
+                       if (Name != null) {
+                               LocalInfo vi = Block.GetLocalInfo (Name);
+                               if (vi == null)
+                                       throw new Exception ("Variable does not exist in this block");
+
+                               if (vi.Variable.NeedsTemporary) {
+                                       LocalBuilder e = ig.DeclareLocal (vi.VariableType);
+                                       ig.Emit (OpCodes.Stloc, e);
+
+                                       vi.Variable.EmitInstance (ec);
+                                       ig.Emit (OpCodes.Ldloc, e);
+                                       vi.Variable.EmitAssign (ec);
+                               } else
+                                       vi.Variable.EmitAssign (ec);
+                       } else
+                               ig.Emit (OpCodes.Pop);
+
+                       Block.Emit (ec);
                }
 
                public override bool Resolve (EmitContext ec)
@@ -3729,38 +4138,11 @@ namespace Mono.CSharp {
                                ig.BeginExceptionBlock ();
                        Block.Emit (ec);
 
-                       foreach (Catch c in Specific){
-                               LocalInfo vi;
-                               
-                               ig.BeginCatchBlock (c.CatchType);
-
-                               if (c.VarBlock != null)
-                                       ec.EmitScopeInitFromBlock (c.VarBlock);
-                               if (c.Name != null){
-                                       vi = c.Block.GetLocalInfo (c.Name);
-                                       if (vi == null)
-                                               throw new Exception ("Variable does not exist in this block");
+                       foreach (Catch c in Specific)
+                               c.Emit (ec);
 
-                                       if (vi.IsCaptured){
-                                               LocalBuilder e = ig.DeclareLocal (vi.VariableType);
-                                               ig.Emit (OpCodes.Stloc, e);
-                                               
-                                               ec.EmitCapturedVariableInstance (vi);
-                                               ig.Emit (OpCodes.Ldloc, e);
-                                               ig.Emit (OpCodes.Stfld, vi.FieldBuilder);
-                                       } else
-                                               ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
-                               } else
-                                       ig.Emit (OpCodes.Pop);
-
-                               c.Block.Emit (ec);
-                       }
-
-                       if (General != null){
-                               ig.BeginCatchBlock (TypeManager.object_type);
-                               ig.Emit (OpCodes.Pop);
-                               General.Block.Emit (ec);
-                       }
+                       if (General != null)
+                               General.Emit (ec);
 
                        DoEmitFinally (ec);
                        if (need_exc_block)
@@ -3790,7 +4172,7 @@ namespace Mono.CSharp {
                Expression [] resolved_vars;
                Expression [] converted_vars;
                ExpressionStatement [] assign;
-               LocalBuilder local_copy;
+               TemporaryVariable local_copy;
                
                public Using (object expression_or_block, Statement stmt, Location l)
                {
@@ -3883,6 +4265,9 @@ namespace Mono.CSharp {
                                }
                        }
 
+                       local_copy = new TemporaryVariable (expr_type, loc);
+                       local_copy.Resolve (ec);
+
                        return true;
                }
                
@@ -3901,6 +4286,7 @@ namespace Mono.CSharp {
                                        ig.BeginExceptionBlock ();
                        }
                        Statement.Emit (ec);
+
                        var_list.Reverse ();
 
                        DoEmitFinally (ec);
@@ -3915,6 +4301,9 @@ namespace Mono.CSharp {
                                Expression var = resolved_vars [--i];
                                Label skip = ig.DefineLabel ();
 
+                               if (emit_finally)
+                                       ig.BeginFinallyBlock ();
+                               
                                if (!var.Type.IsValueType) {
                                        var.Emit (ec);
                                        ig.Emit (OpCodes.Brfalse, skip);
@@ -3965,10 +4354,8 @@ namespace Mono.CSharp {
                        // Make a copy of the expression and operate on that.
                        //
                        ILGenerator ig = ec.ig;
-                       local_copy = ig.DeclareLocal (expr_type);
 
-                       expr.Emit (ec);
-                       ig.Emit (OpCodes.Stloc, local_copy);
+                       local_copy.Store (ec, expr);
 
                        if (emit_finally)
                                ig.BeginExceptionBlock ();
@@ -3983,19 +4370,21 @@ namespace Mono.CSharp {
                void EmitExpressionFinally (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
-                       if (!local_copy.LocalType.IsValueType) {
+                       if (!expr_type.IsValueType) {
                                Label skip = ig.DefineLabel ();
-                               ig.Emit (OpCodes.Ldloc, local_copy);
+                               local_copy.Emit (ec);
                                ig.Emit (OpCodes.Brfalse, skip);
-                               ig.Emit (OpCodes.Ldloc, local_copy);
+                               local_copy.Emit (ec);
                                ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
                                ig.MarkLabel (skip);
                        } else {
-                               Expression ml = Expression.MemberLookup(ec.ContainerType, TypeManager.idisposable_type, local_copy.LocalType, "Dispose", Mono.CSharp.Location.Null);
+                               Expression ml = Expression.MemberLookup (
+                                       ec.ContainerType, TypeManager.idisposable_type, expr_type,
+                                       "Dispose", Location.Null);
 
                                if (!(ml is MethodGroupExpr)) {
-                                       ig.Emit (OpCodes.Ldloc, local_copy);
-                                       ig.Emit (OpCodes.Box, local_copy.LocalType);
+                                       local_copy.Emit (ec);
+                                       ig.Emit (OpCodes.Box, expr_type);
                                        ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
                                } else {
                                        MethodInfo mi = null;
@@ -4012,7 +4401,7 @@ namespace Mono.CSharp {
                                                return;
                                        }
 
-                                       ig.Emit (OpCodes.Ldloca, local_copy);
+                                       local_copy.AddressOf (ec, AddressOp.Load);
                                        ig.Emit (OpCodes.Call, mi);
                                }
                        }
@@ -4049,7 +4438,7 @@ namespace Mono.CSharp {
                                return false;
                        }
 
-                       ResolveFinally (branching);                                     
+                       ResolveFinally (branching);
                        FlowBranching.Reachability reachability = ec.EndFlowBranching ();
 
                        if (!reachability.AlwaysReturns) {
@@ -4123,7 +4512,7 @@ namespace Mono.CSharp {
 
                        Type var_type = texpr.Type;
 
-                       if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethod) {
+                       if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
                                Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
                                        expr.ExprClassName);
                                return false;
@@ -4179,7 +4568,7 @@ namespace Mono.CSharp {
                        {
                                EmitThis (ec);
                                ec.ig.Emit (OpCodes.Ldc_I4_0);
-                               EmitStore (ec.ig);
+                               EmitStore (ec);
                        }
 
                        public void Increment (EmitContext ec)
@@ -4188,7 +4577,7 @@ namespace Mono.CSharp {
                                Emit (ec);
                                ec.ig.Emit (OpCodes.Ldc_I4_1);
                                ec.ig.Emit (OpCodes.Add);
-                               EmitStore (ec.ig);
+                               EmitStore (ec);
                        }
                }
 
@@ -4282,7 +4671,7 @@ namespace Mono.CSharp {
 
                                        lengths [i].EmitThis (ec);
                                        ((ArrayAccess) access).EmitGetLength (ec, i);
-                                       lengths [i].EmitStore (ig);
+                                       lengths [i].EmitStore (ec);
                                }
 
                                for (int i = 0; i < rank; i++) {
@@ -4372,9 +4761,25 @@ namespace Mono.CSharp {
                                        // way I could do this without a goto
                                        //
 
+#if GMCS_SOURCE
+                                       //
+                                       // Prefer a generic enumerator over a non-generic one.
+                                       //
+                                       if (return_type.IsInterface && return_type.IsGenericType) {
+                                               enumerator_type = return_type;
+                                               if (!FetchGetCurrent (ec, return_type))
+                                                       get_current = new PropertyExpr (
+                                                               ec.ContainerType, TypeManager.ienumerator_getcurrent, loc);
+                                               if (!FetchMoveNext (return_type))
+                                                       move_next = TypeManager.bool_movenext_void;
+                                               return true;
+                                       }
+#endif
+
                                        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 (
                                                        ec.ContainerType, TypeManager.ienumerator_getcurrent, loc);
@@ -4487,23 +4892,60 @@ namespace Mono.CSharp {
                                if (mg == null)
                                        return false;
 
-                               foreach (MethodBase mb in mg.Methods) {
-                                       if (TypeManager.GetParameterData (mb).Count != 0)
+                               MethodInfo result = null;
+                               MethodInfo tmp_move_next = null;
+                               PropertyExpr tmp_get_cur = null;
+                               Type tmp_enumerator_type = enumerator_type;
+                               foreach (MethodInfo mi in mg.Methods) {
+                                       if (TypeManager.GetParameterData (mi).Count != 0)
                                                continue;
                        
                                        // Check whether GetEnumerator is public
-                                       if ((mb.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
+                                       if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
                                                continue;
 
-                                       if (TypeManager.IsOverride (mb))
+                                       if (TypeManager.IsOverride (mi))
                                                continue;
 
                                        enumerator_found = true;
 
-                                       if (!GetEnumeratorFilter (ec, (MethodInfo) mb))
+                                       if (!GetEnumeratorFilter (ec, mi))
                                                continue;
 
-                                       MethodInfo[] mi = new MethodInfo[] { (MethodInfo) mb };
+                                       if (result != null) {
+                                               if (TypeManager.IsGenericType (result.ReturnType)) {
+                                                       if (!TypeManager.IsGenericType (mi.ReturnType))
+                                                               continue;
+
+                                                       Report.SymbolRelatedToPreviousError(t);
+                                                       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.CSharpSignature (mi));
+                                                       return false;
+                                               }
+
+                                               // Always prefer generics enumerators
+                                               if (TypeManager.IsGenericType(mi.ReturnType))
+                                                       continue;
+
+                                               Report.SymbolRelatedToPreviousError (result);
+                                               Report.SymbolRelatedToPreviousError (mi);
+                                               Report.Warning (278, 2, loc, "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
+                                                       TypeManager.CSharpName (t), "enumerable", TypeManager.CSharpSignature (result), TypeManager.CSharpSignature (mi));
+                                       }
+                                       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;
+                                       MethodInfo[] mi = new MethodInfo[] { (MethodInfo) result };
                                        get_enumerator = new MethodGroupExpr (mi, loc);
 
                                        if (t != expr.Type) {
@@ -4524,12 +4966,16 @@ namespace Mono.CSharp {
 
                        bool ProbeCollectionType (EmitContext ec, Type t)
                        {
+                               int errors = Report.Errors;
                                for (Type tt = t; tt != null && tt != TypeManager.object_type;){
                                        if (TryType (ec, tt))
                                                return true;
                                        tt = tt.BaseType;
                                }
 
+                               if (Report.Errors > errors)
+                                       return false;
+
                                //
                                // Now try to find the method in the interfaces
                                //