2007-06-20 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / statement.cs
index bb0aea29d491d3cdbd7e7e6bc11809553aff51b2..207cf7bdc70a3094169c02bd3ad59728084d6a15 100644 (file)
@@ -85,9 +85,85 @@ namespace Mono.CSharp {
                {
                        ec.Mark (loc, true);
                        DoEmit (ec);
-               }               
+               }
+
+               //
+               // This routine must be overrided in derived classes and make copies
+               // of all the data that might be modified if resolved
+               // 
+               protected virtual void CloneTo (CloneContext clonectx, Statement target)
+               {
+                       throw new Exception (String.Format ("Statement.CloneTo not implemented for {0}", this.GetType ()));
+               }
+               
+               public Statement Clone (CloneContext clonectx)
+               {
+                       Statement s = (Statement) this.MemberwiseClone ();
+                       CloneTo (clonectx, s);
+                       return s;
+               }
+
+               public Statement PerformClone ()
+               {
+                       CloneContext clonectx = new CloneContext ();
+
+                       return Clone (clonectx);
+               }
+
        }
 
+       //
+       // This class is used during the Statement.Clone operation
+       // to remap objects that have been cloned.
+       //
+       // Since blocks are cloned by Block.Clone, we need a way for
+       // expressions that must reference the block to be cloned
+       // pointing to the new cloned block.
+       //
+       public class CloneContext {
+               Hashtable block_map = new Hashtable ();
+               Hashtable variable_map;
+               
+               public void AddBlockMap (Block from, Block to)
+               {
+                       if (block_map.Contains (from))
+                               return;
+                       block_map [from] = to;
+               }
+               
+               public Block LookupBlock (Block from)
+               {
+                       Block result = (Block) block_map [from];
+
+                       if (result == null){
+                               result = (Block) from.Clone (this);
+                               block_map [from] = result;
+                       }
+
+                       return result;
+               }
+
+               public void AddVariableMap (LocalInfo from, LocalInfo to)
+               {
+                       if (variable_map == null)
+                               variable_map = new Hashtable ();
+                       
+                       if (variable_map.Contains (from))
+                               return;
+                       variable_map [from] = to;
+               }
+               
+               public LocalInfo LookupVariable (LocalInfo from)
+               {
+                       LocalInfo result = (LocalInfo) variable_map [from];
+
+                       if (result == null)
+                               throw new Exception ("LookupVariable: looking up a variable that has not been registered yet");
+
+                       return result;
+               }
+       }
+       
        public sealed class EmptyStatement : Statement {
                
                private EmptyStatement () {}
@@ -182,7 +258,7 @@ namespace Mono.CSharp {
                        
                        ok &= TrueStatement.Resolve (ec);
 
-                       is_true_ret = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable;
+                       is_true_ret = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
 
                        ec.CurrentBranching.CreateSibling ();
 
@@ -239,11 +315,21 @@ namespace Mono.CSharp {
                                ig.MarkLabel (false_target);
                        }
                }
+
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       If target = (If) t;
+
+                       target.expr = expr.Clone (clonectx);
+                       target.TrueStatement = TrueStatement.Clone (clonectx);
+                       if (FalseStatement != null)
+                               target.FalseStatement = FalseStatement.Clone (clonectx);
+               }
        }
 
        public class Do : Statement {
                public Expression expr;
-               public readonly Statement  EmbeddedStatement;
+               public Statement  EmbeddedStatement;
                bool infinite;
                
                public Do (Statement statement, Expression boolExpr, Location l)
@@ -259,14 +345,14 @@ namespace Mono.CSharp {
 
                        ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
 
-                       bool was_unreachable = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable;
+                       bool was_unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
 
                        ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
                        if (!EmbeddedStatement.Resolve (ec))
                                ok = false;
                        ec.EndFlowBranching ();
 
-                       if (ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable && !was_unreachable)
+                       if (ec.CurrentBranching.CurrentUsageVector.IsUnreachable && !was_unreachable)
                                Report.Warning (162, 2, expr.Location, "Unreachable code detected");
 
                        expr = Expression.ResolveBoolean (ec, expr, loc);
@@ -316,11 +402,19 @@ namespace Mono.CSharp {
                        ec.LoopBegin = old_begin;
                        ec.LoopEnd = old_end;
                }
+
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       Do target = (Do) t;
+
+                       target.EmbeddedStatement = EmbeddedStatement.Clone (clonectx);
+                       target.expr = expr.Clone (clonectx);
+               }
        }
 
        public class While : Statement {
                public Expression expr;
-               public readonly Statement Statement;
+               public Statement Statement;
                bool infinite, empty;
                
                public While (Expression boolExpr, Statement statement, Location l)
@@ -413,13 +507,21 @@ namespace Mono.CSharp {
                        ec.LoopBegin = old_begin;
                        ec.LoopEnd = old_end;
                }
+
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       While target = (While) t;
+
+                       target.expr = expr.Clone (clonectx);
+                       target.Statement = Statement.Clone (clonectx);
+               }
        }
 
        public class For : Statement {
                Expression Test;
-               readonly Statement InitStatement;
-               readonly Statement Increment;
-               public readonly Statement Statement;
+               Statement InitStatement;
+               Statement Increment;
+               public Statement Statement;
                bool infinite, empty;
                
                public For (Statement initStatement,
@@ -469,7 +571,7 @@ namespace Mono.CSharp {
                        if (!infinite)
                                ec.CurrentBranching.CreateSibling ();
 
-                       bool was_unreachable = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable;
+                       bool was_unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
 
                        ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
                        if (!Statement.Resolve (ec))
@@ -477,7 +579,7 @@ namespace Mono.CSharp {
                        ec.EndFlowBranching ();
 
                        if (Increment != null){
-                               if (ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable) {
+                               if (ec.CurrentBranching.CurrentUsageVector.IsUnreachable) {
                                        if (!Increment.ResolveUnreachable (ec, !was_unreachable))
                                                ok = false;
                                } else {
@@ -542,6 +644,19 @@ namespace Mono.CSharp {
                        ec.LoopBegin = old_begin;
                        ec.LoopEnd = old_end;
                }
+
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       For target = (For) t;
+
+                       if (InitStatement != null)
+                               target.InitStatement = InitStatement.Clone (clonectx);
+                       if (Test != null)
+                               target.Test = Test.Clone (clonectx);
+                       if (Increment != null)
+                               target.Increment = Increment.Clone (clonectx);
+                       target.Statement = Statement.Clone (clonectx);
+               }
        }
        
        public class StatementExpression : Statement {
@@ -569,6 +684,13 @@ namespace Mono.CSharp {
                {
                        return "StatementExpression (" + expr + ")";
                }
+
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       StatementExpression target = (StatementExpression) t;
+
+                       target.expr = (ExpressionStatement) expr.Clone (clonectx);
+               }
        }
 
        /// <summary>
@@ -596,10 +718,10 @@ namespace Mono.CSharp {
 
                        if (ec.ReturnType == null){
                                if (Expr != null){
-                                       if (ec.CurrentAnonymousMethod != null){
+                                       if (am != null){
                                                Report.Error (1662, loc,
                                                        "Cannot convert anonymous method block to delegate type `{0}' because some of the return types in the block are not implicitly convertible to the delegate return type",
-                                                       ec.CurrentAnonymousMethod.GetSignatureForError ());
+                                                       am.GetSignatureForError ());
                                        }
                                        Error (127, "A return keyword must not be followed by any expression when method returns void");
                                        return false;
@@ -617,10 +739,14 @@ namespace Mono.CSharp {
                                        return false;
 
                                if (Expr.Type != ec.ReturnType) {
-                                       Expr = Convert.ImplicitConversionRequired (
-                                               ec, Expr, ec.ReturnType, loc);
-                                       if (Expr == null)
-                                               return false;
+                                       if (ec.InferReturnType) {
+                                               ec.ReturnType = Expr.Type;
+                                       } else {
+                                               Expr = Convert.ImplicitConversionRequired (
+                                                       ec, Expr, ec.ReturnType, loc);
+                                               if (Expr == null)
+                                                       return false;
+                                       }
                                }
                        }
 
@@ -628,7 +754,7 @@ namespace Mono.CSharp {
                        unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
                        if (unwind_protect)
                                ec.NeedReturnLabel ();
-                       ec.CurrentBranching.CurrentUsageVector.Return ();
+                       ec.CurrentBranching.CurrentUsageVector.Goto ();
                        return errors == Report.Errors;
                }
                
@@ -646,6 +772,13 @@ namespace Mono.CSharp {
                        else
                                ec.ig.Emit (OpCodes.Ret);
                }
+
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       Return target = (Return) t;
+
+                       target.Expr = Expr.Clone (clonectx);
+               }
        }
 
        public class Goto : Statement {
@@ -781,7 +914,7 @@ namespace Mono.CSharp {
                        }
 
                        if (!ec.Switch.GotDefault){
-                               Report.Error (159, loc, "No such label `default:' within the scope of the goto statement");
+                               FlowBranchingBlock.Error_UnknownLabel (loc, "default");
                                return;
                        }
                        ec.ig.Emit (OpCodes.Br, ec.Switch.DefaultTarget);
@@ -840,7 +973,8 @@ namespace Mono.CSharp {
                        sl = (SwitchLabel) ec.Switch.Elements [val];
 
                        if (sl == null){
-                               Report.Error (159, loc, "No such label `case {0}:' within the scope of the goto statement", c.GetValue () == null ? "null" : val.ToString ());
+                               FlowBranchingBlock.Error_UnknownLabel (loc, "case " + 
+                                       (c.GetValue () == null ? "null" : val.ToString ()));
                                return false;
                        }
 
@@ -852,6 +986,14 @@ namespace Mono.CSharp {
                {
                        ec.ig.Emit (OpCodes.Br, sl.GetILLabelCode (ec));
                }
+
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       GotoCase target = (GotoCase) t;
+
+                       target.expr = expr.Clone (clonectx);
+                       target.sl = sl.Clone (clonectx);
+               }
        }
        
        public class Throw : Statement {
@@ -865,7 +1007,7 @@ namespace Mono.CSharp {
 
                public override bool Resolve (EmitContext ec)
                {
-                       ec.CurrentBranching.CurrentUsageVector.Throw ();
+                       ec.CurrentBranching.CurrentUsageVector.Goto ();
 
                        if (expr != null){
                                expr = expr.Resolve (ec);
@@ -915,6 +1057,13 @@ namespace Mono.CSharp {
                                ec.ig.Emit (OpCodes.Throw);
                        }
                }
+
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       Throw target = (Throw) t;
+
+                       target.expr = expr.Clone (clonectx);
+               }
        }
 
        public class Break : Statement {
@@ -986,10 +1135,15 @@ namespace Mono.CSharp {
                public abstract void EmitAddressOf (EmitContext ec);
        }
 
+       public interface IKnownVariable {
+               Block Block { get; }
+               Location Location { get; }
+       }
+
        //
        // The information about a user-perceived local variable
        //
-       public class LocalInfo {
+       public class LocalInfo : IKnownVariable {
                public Expression Type;
 
                public Type VariableType;
@@ -1024,6 +1178,7 @@ namespace Mono.CSharp {
 
                Flags flags;
                ReadOnlyContext ro_context;
+               LocalBuilder builder;
                
                public LocalInfo (Expression type, string name, Block block, Location l)
                {
@@ -1035,7 +1190,7 @@ 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;
                }
@@ -1047,7 +1202,6 @@ namespace Mono.CSharp {
                                var = theblock.ScopeInfo.GetCapturedVariable (this);
 
                        if (var == null) {
-                               LocalBuilder builder;
                                if (Pinned)
                                        //
                                        // This is needed to compile on both .NET 1.x and .NET 2.x
@@ -1061,7 +1215,13 @@ namespace Mono.CSharp {
                        }
                }
 
-               public bool IsThisAssigned (EmitContext ec, Location loc)
+               public void EmitSymbolInfo (EmitContext ec, string name)
+               {
+                       if (builder != null)
+                               ec.DefineLocalVariable (name, builder);
+               }
+
+               public bool IsThisAssigned (EmitContext ec)
                {
                        if (VariableInfo == null)
                                throw new Exception ();
@@ -1069,7 +1229,7 @@ namespace Mono.CSharp {
                        if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo))
                                return true;
 
-                       return VariableInfo.TypeInfo.IsFullyInitialized (ec.CurrentBranching, VariableInfo, loc);
+                       return VariableInfo.TypeInfo.IsFullyInitialized (ec.CurrentBranching, VariableInfo, ec.loc);
                }
 
                public bool IsAssigned (EmitContext ec)
@@ -1083,20 +1243,23 @@ namespace Mono.CSharp {
                public bool Resolve (EmitContext ec)
                {
                        if (VariableType == null) {
-                               TypeExpr texpr = Type.ResolveAsTypeTerminal (ec, false);
+                               TypeExpr texpr = Type.ResolveAsContextualType (ec, false);
                                if (texpr == null)
                                        return false;
                                
                                VariableType = texpr.Type;
                        }
 
+                       if (TypeManager.IsGenericParameter (VariableType))
+                               return true;
+
                        if (VariableType == TypeManager.void_type) {
                                Expression.Error_VoidInvalidInTheContext (Location);
                                return false;
                        }
 
                        if (VariableType.IsAbstract && VariableType.IsSealed) {
-                               FieldMember.Error_VariableOfStaticClass (Location, Name, VariableType);
+                               FieldBase.Error_VariableOfStaticClass (Location, Name, VariableType);
                                return false;
                        }
 
@@ -1107,42 +1270,23 @@ namespace Mono.CSharp {
                }
 
                public bool IsCaptured {
-                       get {
-                               return (flags & Flags.Captured) != 0;
-                       }
-
-                       set {
-                               flags |= Flags.Captured;
-                       }
+                       get { return (flags & Flags.Captured) != 0; }
+                       set { flags |= Flags.Captured; }
                }
 
                public bool IsConstant {
-                       get {
-                               return (flags & Flags.IsConstant) != 0;
-                       }
-                       set {
-                               flags |= Flags.IsConstant;
-                       }
+                       get { return (flags & Flags.IsConstant) != 0; }
+                       set { flags |= Flags.IsConstant; }
                }
 
                public bool AddressTaken {
-                       get {
-                               return (flags & Flags.AddressTaken) != 0;
-                       }
-
-                       set {
-                               flags |= Flags.AddressTaken;
-                       }
+                       get { return (flags & Flags.AddressTaken) != 0; }
+                       set { flags |= Flags.AddressTaken; }
                }
 
                public bool CompilerGenerated {
-                       get {
-                               return (flags & Flags.CompilerGenerated) != 0;
-                       }
-
-                       set {
-                               flags |= Flags.CompilerGenerated;
-                       }
+                       get { return (flags & Flags.CompilerGenerated) != 0; }
+                       set { flags |= Flags.CompilerGenerated; }
                }
 
                public override string ToString ()
@@ -1152,18 +1296,12 @@ namespace Mono.CSharp {
                }
 
                public bool Used {
-                       get {
-                               return (flags & Flags.Used) != 0;
-                       }
-                       set {
-                               flags = value ? (flags | Flags.Used) : (unchecked (flags & ~Flags.Used));
-                       }
+                       get { return (flags & Flags.Used) != 0; }
+                       set { flags = value ? (flags | Flags.Used) : (unchecked (flags & ~Flags.Used)); }
                }
 
                public bool ReadOnly {
-                       get {
-                               return (flags & Flags.ReadOnly) != 0;
-                       }
+                       get { return (flags & Flags.ReadOnly) != 0; }
                }
 
                public void SetReadOnlyContext (ReadOnlyContext context)
@@ -1193,21 +1331,21 @@ namespace Mono.CSharp {
                // allocated in a pinned slot with DeclareLocal.
                //
                public bool Pinned {
-                       get {
-                               return (flags & Flags.Pinned) != 0;
-                       }
-                       set {
-                               flags = value ? (flags | Flags.Pinned) : (flags & ~Flags.Pinned);
-                       }
+                       get { return (flags & Flags.Pinned) != 0; }
+                       set { flags = value ? (flags | Flags.Pinned) : (flags & ~Flags.Pinned); }
                }
 
                public bool IsThis {
-                       get {
-                               return (flags & Flags.IsThis) != 0;
-                       }
-                       set {
-                               flags = value ? (flags | Flags.IsThis) : (flags & ~Flags.IsThis);
-                       }
+                       get { return (flags & Flags.IsThis) != 0; }
+                       set { flags = value ? (flags | Flags.IsThis) : (flags & ~Flags.IsThis); }
+               }
+
+               Block IKnownVariable.Block {
+                       get { return Block; }
+               }
+
+               Location IKnownVariable.Location {
+                       get { return Location; }
                }
 
                protected class LocalVariable : Variable
@@ -1253,8 +1391,14 @@ namespace Mono.CSharp {
                                ec.ig.Emit (OpCodes.Ldloca, builder);
                        }
                }
+
+               public LocalInfo Clone (CloneContext clonectx)
+               {
+                       // Only this kind is created by the parser.
+                       return new LocalInfo (Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location);
+               }
        }
-               
+
        /// <summary>
        ///   Block represents a C# block.
        /// </summary>
@@ -1274,28 +1418,22 @@ namespace Mono.CSharp {
                public readonly Location  StartLocation;
                public Location EndLocation = Location.Null;
 
-               public readonly ToplevelBlock Toplevel;
+               public ExplicitBlock Explicit;
+               public ToplevelBlock Toplevel;
 
                [Flags]
-               public enum Flags : ushort {
-                       Implicit  = 1,
-                       Unchecked = 2,
-                       BlockUsed = 4,
-                       VariablesInitialized = 8,
-                       HasRet = 16,
-                       IsDestructor = 32,
-                       IsToplevel = 64,
-                       Unsafe = 128,
-                       HasVarargs = 256, // Used in ToplevelBlock
-                       IsIterator = 512
-
+               public enum Flags : byte {
+                       Unchecked = 1,
+                       BlockUsed = 2,
+                       VariablesInitialized = 4,
+                       HasRet = 8,
+                       IsDestructor = 16,
+                       Unsafe = 32,
+                       HasVarargs = 64, // Used in ToplevelBlock
+                       IsIterator = 128
                }
                protected Flags flags;
 
-               public bool Implicit {
-                       get { return (flags & Flags.Implicit) != 0; }
-               }
-
                public bool Unchecked {
                        get { return (flags & Flags.Unchecked) != 0; }
                        set { flags |= Flags.Unchecked; }
@@ -1310,6 +1448,7 @@ namespace Mono.CSharp {
                // The statements in this block
                //
                protected ArrayList statements;
+               protected int current_statement;
                int num_statements;
 
                //
@@ -1367,8 +1506,13 @@ namespace Mono.CSharp {
 
                public Block (Block parent, Flags flags, Location start, Location end)
                {
-                       if (parent != null)
+                       if (parent != null) {
                                parent.AddChild (this);
+
+                               // the appropriate constructors will fixup these fields
+                               Toplevel = parent.Toplevel;
+                               Explicit = parent.Explicit;
+                       }
                        
                        this.Parent = parent;
                        this.flags = flags;
@@ -1377,23 +1521,12 @@ namespace Mono.CSharp {
                        this.loc = start;
                        this_id = id++;
                        statements = new ArrayList ();
-
-                       if ((flags & Flags.IsToplevel) != 0)
-                               Toplevel = (ToplevelBlock) this;
-                       else
-                               Toplevel = parent.Toplevel;
-
-                       if (parent != null && Implicit) {
-                               if (parent.known_variables == null)
-                                       parent.known_variables = new Hashtable ();
-                               // share with parent
-                               known_variables = parent.known_variables;
-                       }
                }
 
                public Block CreateSwitchBlock (Location start)
                {
-                       Block new_block = new Block (this, start, start);
+                       // FIXME: should this be implicit?
+                       Block new_block = new ExplicitBlock (this, start, start);
                        new_block.switch_block = this;
                        return new_block;
                }
@@ -1426,7 +1559,7 @@ namespace Mono.CSharp {
                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);
+                                     "by the same name in a contained scope", name);
                }
 
                /// <summary>
@@ -1447,13 +1580,14 @@ 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);
+                               LabeledStatement s = cur.DoLookupLabel (name);
+                               if (s != null) {
+                                       Report.SymbolRelatedToPreviousError (s.loc, s.Name);
+                                       Report.Error (140, target.loc, "The label `{0}' is a duplicate", name);
                                        return false;
                                }
 
-                               if (!Implicit)
+                               if (this == Explicit)
                                        break;
 
                                cur = cur.Parent;
@@ -1471,6 +1605,7 @@ namespace Mono.CSharp {
                                                if (s == null)
                                                        continue;
 
+                                               Report.SymbolRelatedToPreviousError (s.loc, s.Name);
                                                Error_158 (name, target.loc);
                                                return false;
                                        }
@@ -1498,7 +1633,7 @@ namespace Mono.CSharp {
                                return null;
 
                        foreach (Block child in children) {
-                               if (!child.Implicit)
+                               if (Explicit != child.Explicit)
                                        continue;
 
                                s = child.LookupLabel (name);
@@ -1521,59 +1656,22 @@ namespace Mono.CSharp {
                        return null;
                }
 
-               Hashtable known_variables;
-
-               // <summary>
-               //   Marks a variable with name @name as being used in this or a child block.
-               //   If a variable name has been used in a child block, it's illegal to
-               //   declare a variable with the same name in the current block.
-               // </summary>
-               void AddKnownVariable (string name, LocalInfo info)
-               {
-                       if (known_variables == null)
-                               known_variables = new Hashtable ();
-
-                       known_variables [name] = info;
-               }
-
-               LocalInfo GetKnownVariableInfo (string name, bool recurse)
-               {
-                       if (known_variables != null) {
-                               LocalInfo vi = (LocalInfo) known_variables [name];
-                               if (vi != null)
-                                       return vi;
-                       }
-
-                       if (!recurse || (children == null))
-                               return null;
-
-                       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, true);
+                       IKnownVariable kvi = b.Explicit.GetKnownVariable (name);
                        while (kvi == null) {
-                               while (b.Implicit)
-                                       b = b.Parent;
-                               b = b.Parent;
+                               b = b.Explicit.Parent;
                                if (b == null)
                                        return true;
-                               kvi = b.GetKnownVariableInfo (name, false);
+                               kvi = b.Explicit.GetKnownVariable (name);
                        }
 
                        if (kvi.Block == b)
                                return true;
 
                        // Is kvi.Block nested inside 'b'
-                       if (b.known_variables != kvi.Block.known_variables) {
+                       if (b.Explicit != kvi.Block.Explicit) {
                                //
                                // If a variable by the same name it defined in a nested block of this
                                // block, we violate the invariant meaning in a block.
@@ -1600,7 +1698,7 @@ namespace Mono.CSharp {
                        // an indirect check that depends on AddVariable doing its
                        // part in maintaining the invariant-meaning-in-block property.
                        //
-                       if (e is LocalVariableReference || (e is Constant && b.GetLocalInfo (name) != null))
+                       if (e is VariableReference || (e is Constant && b.GetLocalInfo (name) != null))
                                return true;
 
                        //
@@ -1612,109 +1710,12 @@ 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);
                        if (vi != null) {
                                Report.SymbolRelatedToPreviousError (vi.Location, name);
-                               if (known_variables == vi.Block.known_variables)
+                               if (Explicit == vi.Block.Explicit)
                                        Report.Error (128, l,
                                                "A local variable named `{0}' is already defined in this scope", name);
                                else
@@ -1722,20 +1723,31 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       if (!CheckError136 (name, null, true, true, l))
+                       ToplevelParameterInfo pi = Toplevel.GetParameterInfo (name);
+                       if (pi != null) {
+                               Report.SymbolRelatedToPreviousError (pi.Location, name);
+                               Error_AlreadyDeclared (loc, name,
+                                       pi.Block == Toplevel ? "method argument" : "parent or current");
+                       }
+
+                       IKnownVariable kvi = Explicit.GetKnownVariable (name);
+                       if (kvi != null) {
+                               Report.SymbolRelatedToPreviousError (kvi.Location, name);
+                               Error_AlreadyDeclared (l, name, "child");
                                return null;
+                       }
 
                        vi = new LocalInfo (type, name, this, l);
                        Variables.Add (name, vi);
-                       AddKnownVariable (name, vi);
+                       Explicit.AddKnownVariable (name, vi);
 
                        if ((flags & Flags.VariablesInitialized) != 0)
-                               throw new Exception ();
+                               throw new InternalErrorException ("block has already been resolved");
 
                        return vi;
                }
 
-               void Error_AlreadyDeclared (Location loc, string var, string reason)
+               protected static 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 " +
@@ -1811,6 +1823,12 @@ namespace Mono.CSharp {
                        statements.Add (s);
                        flags |= Flags.BlockUsed;
                }
+               
+               public void InsertStatementAfterCurrent (Statement statement)
+               {
+                       statements.Insert (current_statement + 1, statement);
+                       flags |= Flags.BlockUsed;
+               }
 
                public bool Used {
                        get { return (flags & Flags.BlockUsed) != 0; }
@@ -1834,39 +1852,27 @@ namespace Mono.CSharp {
                        flags |= Flags.IsDestructor;
                }
 
-               VariableMap param_map, local_map;
-
-               public VariableMap ParameterMap {
+               int assignable_slots;
+               public int AssignableSlots {
                        get {
                                if ((flags & Flags.VariablesInitialized) == 0)
                                        throw new Exception ("Variables have not been initialized yet");
-
-                               return param_map;
+                               return assignable_slots;
                        }
                }
 
-               public VariableMap LocalMap {
-                       get {
-                               if ((flags & Flags.VariablesInitialized) == 0)
-                                       throw new Exception ("Variables have not been initialized yet");
+               protected ScopeInfo scope_info;
 
-                               return local_map;
-                       }
+               public ScopeInfo ScopeInfo {
+                       get { return scope_info; }
                }
 
-               public ScopeInfo ScopeInfo;
-
                public ScopeInfo CreateScopeInfo ()
                {
-#if FIXME
-                       if (Implicit)
-                               return Parent.CreateScopeInfo ();
-#endif
+                       if (scope_info == null)
+                               scope_info = ScopeInfo.CreateScope (this);
 
-                       if (ScopeInfo == null)
-                               ScopeInfo = ScopeInfo.CreateScope (this);
-
-                       return ScopeInfo;
+                       return scope_info;
                }
 
                public ArrayList AnonymousChildren {
@@ -1881,119 +1887,89 @@ namespace Mono.CSharp {
                        anonymous_children.Add (b);
                }
 
-               /// <summary>
-               ///   Emits the variable declarations and labels.
-               /// </summary>
-               /// <remarks>
-               ///   tc: is our typecontainer (to resolve type references)
-               ///   ig: is the code generator:
-               /// </remarks>
-               public void ResolveMeta (ToplevelBlock toplevel, EmitContext ec, Parameters ip)
+               void DoResolveConstants (EmitContext ec)
                {
-                       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)) {
-                               //
-                               // Compute the VariableMap's.
-                               //
-                               // Unfortunately, we don't know the type when adding variables with
-                               // AddVariable(), so we need to compute this info here.
-                               //
-
-                               LocalInfo[] locals;
-                               if (variables != null) {
-                                       foreach (LocalInfo li in variables.Values)
-                                               li.Resolve (ec);
-
-                                       locals = new LocalInfo [variables.Count];
-                                       variables.Values.CopyTo (locals, 0);
-                               } else
-                                       locals = new LocalInfo [0];
+                       if (constants == null)
+                               return;
 
-                               if (Parent != null)
-                                       local_map = new VariableMap (Parent.LocalMap, locals);
-                               else
-                                       local_map = new VariableMap (locals);
+                       if (variables == null)
+                               throw new InternalErrorException ("cannot happen");
 
-                               param_map = new VariableMap (ip);
-                               flags |= Flags.VariablesInitialized;
+                       foreach (DictionaryEntry de in variables) {
+                               string name = (string) de.Key;
+                               LocalInfo vi = (LocalInfo) de.Value;
+                               Type variable_type = vi.VariableType;
 
-                               //
-                               // Process this block variables
-                               //
-                               if (variables != null) {
-                                       foreach (DictionaryEntry de in variables) {
-                                               string name = (string) de.Key;
-                                               LocalInfo vi = (LocalInfo) de.Value;
-                                               Type variable_type = vi.VariableType;
-
-                                               if (variable_type == null)
-                                                       continue;
+                               if (variable_type == null)
+                                       continue;
 
-                                               if (variable_type.IsPointer) {
-                                                       //
-                                                       // Am not really convinced that this test is required (Microsoft does it)
-                                                       // but the fact is that you would not be able to use the pointer variable
-                                                       // *anyways*
-                                                       //
-                                                       if (!TypeManager.VerifyUnManaged (TypeManager.GetElementType (variable_type),
-                                                                                         vi.Location))
-                                                               continue;
-                                               }
+                               Expression cv = (Expression) constants [name];
+                               if (cv == null)
+                                       continue;
 
-                                               if (constants == null)
-                                                       continue;
+                               // Don't let 'const int Foo = Foo;' succeed.
+                               // Removing the name from 'constants' ensures that we get a LocalVariableReference below,
+                               // which in turn causes the 'must be constant' error to be triggered.
+                               constants.Remove (name);
 
-                                               Expression cv = (Expression) constants [name];
-                                               if (cv == null)
-                                                       continue;
+                               if (!Const.IsConstantTypeValid (variable_type)) {
+                                       Const.Error_InvalidConstantType (variable_type, loc);
+                                       continue;
+                               }
 
-                                               // Don't let 'const int Foo = Foo;' succeed.
-                                               // Removing the name from 'constants' ensures that we get a LocalVariableReference below,
-                                               // which in turn causes the 'must be constant' error to be triggered.
-                                               constants.Remove (name);
+                               ec.CurrentBlock = this;
+                               Expression e;
+                               using (ec.With (EmitContext.Flags.ConstantCheckState, (flags & Flags.Unchecked) == 0)) {
+                                       e = cv.Resolve (ec);
+                               }
+                               if (e == null)
+                                       continue;
 
-                                               if (!Const.IsConstantTypeValid (variable_type)) {
-                                                       Const.Error_InvalidConstantType (variable_type, loc);
-                                                       continue;
-                                               }
+                               Constant ce = e as Constant;
+                               if (ce == null) {
+                                       Const.Error_ExpressionMustBeConstant (vi.Location, name);
+                                       continue;
+                               }
 
-                                               using (ec.With (EmitContext.Flags.ConstantCheckState, (flags & Flags.Unchecked) == 0)) {
-                                                       ec.CurrentBlock = this;
-                                                       Expression e = cv.Resolve (ec);
-                                                       if (e == null)
-                                                               continue;
+                               e = ce.ConvertImplicitly (variable_type);
+                               if (e == null) {
+                                       if (!variable_type.IsValueType && variable_type != TypeManager.string_type && !ce.IsDefaultValue)
+                                               Const.Error_ConstantCanBeInitializedWithNullOnly (vi.Location, vi.Name);
+                                       else
+                                               ce.Error_ValueCannotBeConverted (null, vi.Location, variable_type, false);
+                                       continue;
+                               }
 
-                                                       Constant ce = e as Constant;
-                                                       if (ce == null) {
-                                                               Const.Error_ExpressionMustBeConstant (vi.Location, name);
-                                                               continue;
-                                                       }
+                               constants.Add (name, e);
+                               vi.IsConstant = true;
+                       }
+               }
 
-                                                       e = ce.ImplicitConversionRequired (variable_type, vi.Location);
-                                                       if (e == null)
-                                                               continue;
+               protected void ResolveMeta (EmitContext ec, int offset)
+               {
+                       Report.Debug (64, "BLOCK RESOLVE META", this, Parent);
 
-                                                       if (!variable_type.IsValueType && variable_type != TypeManager.string_type && !ce.IsDefaultValue) {
-                                                               Const.Error_ConstantCanBeInitializedWithNullOnly (vi.Location, vi.Name);
-                                                               continue;
-                                                       }
+                       // 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)) {
+                               flags |= Flags.VariablesInitialized;
 
-                                                       constants.Add (name, e);
-                                                       vi.IsConstant = true;
-                                               }
+                               if (variables != null) {
+                                       foreach (LocalInfo li in variables.Values) {
+                                               if (!li.Resolve (ec))
+                                                       continue;
+                                               li.VariableInfo = new VariableInfo (li, offset);
+                                               offset += li.VariableInfo.Length;
                                        }
                                }
+                               assignable_slots = offset;
 
-                               //
-                               // Now, handle the children
-                               //
-                               if (children != null) {
-                                       foreach (Block b in children)
-                                               b.ResolveMeta (toplevel, ec, ip);
-                               }
+                               DoResolveConstants (ec);
+
+                               if (children == null)
+                                       return;
+                               foreach (Block b in children)
+                                       b.ResolveMeta (ec, offset);
                        }
                }
 
@@ -2002,7 +1978,7 @@ namespace Mono.CSharp {
                //
                public virtual void EmitMeta (EmitContext ec)
                {
-                       Report.Debug (64, "BLOCK EMIT META", this, Toplevel, ScopeInfo, ec);
+                       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,
@@ -2099,13 +2075,12 @@ namespace Mono.CSharp {
                        // 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];
+                       for (current_statement = 0; current_statement < statements.Count; current_statement++) {
+                               Statement s = (Statement) statements [current_statement];
                                // Check possible empty statement (CS0642)
                                if (RootContext.WarningLevel >= 3 &&
-                                       ix + 1 < statement_count &&
-                                               statements [ix + 1] is Block)
+                                       current_statement + 1 < statements.Count &&
+                                               statements [current_statement + 1] is Block)
                                        CheckPossibleMistakenEmptyStatement (s);
 
                                //
@@ -2134,22 +2109,25 @@ namespace Mono.CSharp {
 
                                if (!s.Resolve (ec)) {
                                        ok = false;
-                                       statements [ix] = EmptyStatement.Value;
+                                       statements [current_statement] = EmptyStatement.Value;
                                        continue;
                                }
 
                                if (unreachable && !(s is LabeledStatement) && !(s is Block))
-                                       statements [ix] = EmptyStatement.Value;
+                                       statements [current_statement] = EmptyStatement.Value;
 
-                               num_statements = ix + 1;
+                               num_statements = current_statement + 1;
 
-                               unreachable = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable;
+                               unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
                                if (unreachable && s is LabeledStatement)
                                        throw new InternalErrorException ("should not happen");
                        }
 
                        Report.Debug (4, "RESOLVE BLOCK DONE", StartLocation,
-                                     ec.CurrentBranching, statement_count, num_statements);
+                                     ec.CurrentBranching, statements.Count, num_statements);
+
+                       if (!ok)
+                               return false;
 
                        while (ec.CurrentBranching is FlowBranchingLabeled)
                                ec.EndFlowBranching ();
@@ -2160,9 +2138,7 @@ namespace Mono.CSharp {
 
                        // If we're a non-static `struct' constructor which doesn't have an
                        // initializer, then we must initialize all of the struct's fields.
-                       if ((flags & Flags.IsToplevel) != 0 && 
-                           !Toplevel.IsThisAssigned (ec) &&
-                           !vector.Reachability.AlwaysThrows)
+                       if (this == Toplevel && !Toplevel.IsThisAssigned (ec) && !vector.IsUnreachable)
                                ok = false;
 
                        if ((labels != null) && (RootContext.WarningLevel >= 2)) {
@@ -2174,7 +2150,7 @@ namespace Mono.CSharp {
 
                        Report.Debug (4, "RESOLVE BLOCK DONE #2", StartLocation, vector);
 
-                       if (vector.Reachability.IsUnreachable)
+                       if (vector.IsUnreachable)
                                flags |= Flags.HasRet;
 
                        if (ok && (errors == Report.Errors)) {
@@ -2204,15 +2180,6 @@ namespace Mono.CSharp {
                {
                        for (int ix = 0; ix < num_statements; ix++){
                                Statement s = (Statement) statements [ix];
-
-                               // Check whether we are the last statement in a
-                               // top-level block.
-
-                               if (((Parent == null) || Implicit) && (ix+1 == num_statements) && !(s is Block))
-                                       ec.IsLastStatement = true;
-                               else
-                                       ec.IsLastStatement = false;
-
                                s.Emit (ec);
                        }
                }
@@ -2224,7 +2191,7 @@ namespace Mono.CSharp {
                        ec.CurrentBlock = this;
 
                        bool emit_debug_info = (CodeGen.SymbolWriter != null);
-                       bool is_lexical_block = !Implicit && (Parent != null);
+                       bool is_lexical_block = this == Explicit && Parent != null;
 
                        if (emit_debug_info) {
                                if (is_lexical_block)
@@ -2236,30 +2203,131 @@ namespace Mono.CSharp {
                        DoEmit (ec);
                        ec.Mark (EndLocation, true); 
 
-                       if (emit_debug_info && is_lexical_block)
-                               ec.EndScope ();
+                       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;
+
+                                               vi.EmitSymbolInfo (ec, name);
+                                       }
+                               }
+                       }
 
                        ec.CurrentBlock = prev_block;
                }
 
-               //
-               // Returns true if we ar ea child of `b'.
-               //
-               public bool IsChildOf (Block b)
+               public override string ToString ()
+               {
+                       return String.Format ("{0} ({1}:{2})", GetType (),ID, StartLocation);
+               }
+
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       Block target = (Block) t;
+
+                       clonectx.AddBlockMap (this, target);
+
+                       target.Toplevel = (ToplevelBlock) clonectx.LookupBlock (Toplevel);
+                       target.Explicit = (ExplicitBlock) clonectx.LookupBlock (Explicit);
+                       if (Parent != null)
+                               target.Parent = clonectx.LookupBlock (Parent);
+                       
+                       target.statements = new ArrayList ();
+                       if (target.children != null){
+                               target.children = new ArrayList ();
+                               foreach (Block b in children){
+                                       Block newblock = (Block) b.Clone (clonectx);
+
+                                       target.children.Add (newblock);
+                               }
+                               
+                       }
+
+                       foreach (Statement s in statements)
+                               target.statements.Add (s.Clone (clonectx));
+
+                       if (variables != null){
+                               target.variables = new Hashtable ();
+
+                               foreach (DictionaryEntry de in variables){
+                                       LocalInfo newlocal = ((LocalInfo) de.Value).Clone (clonectx);
+                                       target.variables [de.Key] = newlocal;
+                                       clonectx.AddVariableMap ((LocalInfo) de.Value, newlocal);
+                               }
+                       }
+
+                       //
+                       // TODO: labels, switch_block, constants (?), anonymous_children
+                       //
+               }
+       }
+
+       public class ExplicitBlock : Block {
+               public ExplicitBlock (Block parent, Location start, Location end)
+                       : this (parent, (Flags) 0, start, end)
+               {
+               }
+
+               public ExplicitBlock (Block parent, Flags flags, Location start, Location end)
+                       : base (parent, flags, start, end)
+               {
+                       this.Explicit = this;
+               }
+
+               Hashtable known_variables;
+
+               // <summary>
+               //   Marks a variable with name @name as being used in this or a child block.
+               //   If a variable name has been used in a child block, it's illegal to
+               //   declare a variable with the same name in the current block.
+               // </summary>
+               internal void AddKnownVariable (string name, IKnownVariable info)
+               {
+                       if (known_variables == null)
+                               known_variables = new Hashtable ();
+
+                       known_variables [name] = info;
+
+                       if (Parent != null)
+                               Parent.Explicit.AddKnownVariable (name, info);
+               }
+
+               internal IKnownVariable GetKnownVariable (string name)
+               {
+                       return known_variables == null ? null : (IKnownVariable) known_variables [name];
+               }
+
+               protected override void CloneTo (CloneContext clonectx, Statement t)
                {
-                       Block current = this;
-                       
-                       do {
-                               if (current.Parent == b)
-                                       return true;
-                               current = current.Parent;
-                       } while (current != null);
-                       return false;
+                       ExplicitBlock target = (ExplicitBlock) t;
+                       target.known_variables = null;
+                       base.CloneTo (clonectx, t);
                }
+       }
 
-               public override string ToString ()
+       public class ToplevelParameterInfo : IKnownVariable {
+               public readonly ToplevelBlock Block;
+               public readonly int Index;
+               public VariableInfo VariableInfo;
+
+               Block IKnownVariable.Block {
+                       get { return Block; }
+               }
+               public Parameter Parameter {
+                       get { return Block.Parameters [Index]; }
+               }
+               public Location Location {
+                       get { return Parameter.Location; }
+               }
+
+               public ToplevelParameterInfo (ToplevelBlock block, int idx)
                {
-                       return String.Format ("{0} ({1}:{2})", GetType (),ID, StartLocation);
+                       this.Block = block;
+                       this.Index = idx;
                }
        }
 
@@ -2271,13 +2339,7 @@ namespace Mono.CSharp {
        // In particular, this was introduced when the support for Anonymous
        // Methods was implemented. 
        // 
-       public class ToplevelBlock : Block {
-               //
-               // Pointer to the host of this anonymous method, or null
-               // if we are the topmost block
-               //
-               Block container;
-               ToplevelBlock child;    
+       public class ToplevelBlock : ExplicitBlock {
                GenericMethod generic;
                FlowBranchingToplevel top_level_branching;
                AnonymousContainer anonymous_container;
@@ -2300,16 +2362,35 @@ namespace Mono.CSharp {
                        get { return parameters; }
                }
 
+               public bool CompleteContexts (EmitContext ec)
+               {
+                       Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS", this, Parent, root_scope);
+
+                       if (root_scope != null)
+                               root_scope.LinkScopes ();
+
+                       if (Parent == null && root_scope != null) {
+                               Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS #1", this, root_scope);
+
+                               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 GenericMethod GenericMethod {
                        get { return generic; }
                }
 
                public ToplevelBlock Container {
-                       get { return container != null ? container.Toplevel : null; }
-               }
-
-               public Block ContainerBlock {
-                       get { return container; }
+                       get { return Parent == null ? null : Parent.Toplevel; }
                }
 
                public AnonymousContainer AnonymousContainer {
@@ -2317,18 +2398,13 @@ namespace Mono.CSharp {
                        set { anonymous_container = value; }
                }
 
-               //
-               // Parent is only used by anonymous blocks to link back to their
-               // parents
-               //
-               public ToplevelBlock (Block container, Parameters parameters, Location start) :
-                       this (container, (Flags) 0, parameters, start)
+               public ToplevelBlock (Block parent, Parameters parameters, Location start) :
+                       this (parent, (Flags) 0, parameters, start)
                {
                }
 
-               public ToplevelBlock (Block container, Parameters parameters, GenericMethod generic,
-                                     Location start) :
-                       this (container, parameters, start)
+               public ToplevelBlock (Block parent, Parameters parameters, GenericMethod generic, Location start) :
+                       this (parent, parameters, start)
                {
                        this.generic = generic;
                }
@@ -2343,17 +2419,37 @@ namespace Mono.CSharp {
                {
                }
 
-               public ToplevelBlock (Block container, Flags flags, Parameters parameters, Location start) :
-                       base (null, flags | Flags.IsToplevel, start, Location.Null)
+               // We use 'Parent' to hook up to the containing block, but don't want to register the current block as a child.
+               // So, we use a two-stage setup -- first pass a null parent to the base constructor, and then override 'Parent'.
+               public ToplevelBlock (Block parent, Flags flags, Parameters parameters, Location start) :
+                       base (null, flags, start, Location.Null)
                {
+                       this.Toplevel = this;
+
                        this.parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters;
-                       this.container = container;
+                       this.Parent = parent;
+                       if (parent != null)
+                               parent.AddAnonymousChild (this);
+
+                       if (this.parameters.Count != 0)
+                               ProcessParameters ();
                }
 
                public ToplevelBlock (Location loc) : this (null, (Flags) 0, null, loc)
                {
                }
 
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       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);
+               }
+
                public bool CheckError158 (string name, Location loc)
                {
                        if (AnonymousChildren != null) {
@@ -2371,10 +2467,43 @@ namespace Mono.CSharp {
                        return true;
                }
 
+               ToplevelParameterInfo [] parameter_info;
+               void ProcessParameters ()
+               {
+                       int n = parameters.Count;
+                       parameter_info = new ToplevelParameterInfo [n];
+                       for (int i = 0; i < n; ++i) {
+                               parameter_info [i] = new ToplevelParameterInfo (this, i);
+
+                               string name = parameters [i].Name;
+
+                               LocalInfo vi = GetLocalInfo (name);
+                               if (vi != null) {
+                                       Report.SymbolRelatedToPreviousError (vi.Location, name);
+                                       Error_AlreadyDeclared (loc, name, "parent or current");
+                                       continue;
+                               }
+
+                               ToplevelParameterInfo pi = Parent == null ? null : Parent.Toplevel.GetParameterInfo (name);
+                               if (pi != null) {
+                                       Report.SymbolRelatedToPreviousError (pi.Location, name);
+                                       Error_AlreadyDeclared (loc, name, "parent or current");
+                                       continue;
+                               }
+
+                               AddKnownVariable (name, parameter_info [i]);
+                       }
+
+                       // mark this block as "used" so that we create local declarations in a sub-block
+                       // FIXME: This appears to uncover a lot of bugs
+                       //this.Use ();
+               }
+
                bool DoCheckError158 (string name, Location loc)
                {
                        LabeledStatement s = LookupLabel (name);
                        if (s != null) {
+                               Report.SymbolRelatedToPreviousError (s.loc, s.Name);
                                Error_158 (name, loc);
                                return false;
                        }
@@ -2387,31 +2516,25 @@ namespace Mono.CSharp {
                        if (root_scope != null)
                                return root_scope;
 
-                       if (Container != null) {
-                               Report.Debug (128, "TOPLEVEL CREATE ROOT SCOPE", this, Container,
-                                             Container.root_scope, AnonymousContainer,
-                                             Container.AnonymousContainer);
-#if FIXME
-                               root_scope = new RootScopeInfo (
-                                       this, Container.root_scope, null, StartLocation);
-#endif
-                       } else
+                       if (Container == null)
                                root_scope = new RootScopeInfo (
                                        this, host, generic, StartLocation);
 
-                       ScopeInfo = root_scope;
+                       if (scope_info != null)
+                               throw new InternalErrorException ();
+
+                       scope_info = root_scope;
                        return root_scope;
                }
 
                public void CreateIteratorHost (RootScopeInfo root)
                {
-                       Report.Debug (64, "CREATE ITERATOR HOST", this, root,
-                                     container, root_scope);
+                       Report.Debug (64, "CREATE ITERATOR HOST", this, root, Parent, root_scope);
 
-                       if ((container != null) || (root_scope != null))
+                       if (Parent != null || root_scope != null)
                                throw new InternalErrorException ();
 
-                       ScopeInfo = root_scope = root;
+                       scope_info = root_scope = root;
                }
 
                public RootScopeInfo RootScope {
@@ -2425,11 +2548,6 @@ namespace Mono.CSharp {
                        }
                }
 
-               public void EmitScopeInstance (EmitContext ec, ScopeInfo scope)
-               {
-                       ScopeInfo.EmitScopeInstance (ec, scope, this);
-               }
-
                public FlowBranchingToplevel TopLevelBranching {
                        get { return top_level_branching; }
                }
@@ -2445,14 +2563,10 @@ namespace Mono.CSharp {
                //
                public void ReParent (ToplevelBlock new_parent)
                {
-                       container = new_parent;
-                       Parent = new_parent;
-                       new_parent.child = this;
+                       if ((flags & Flags.VariablesInitialized) != 0)
+                               throw new InternalErrorException ("block has already been resolved");
 
-#if FIXME
-                       if (container != null)
-                               container.AddAnonymousChild (this);
-#endif
+                       Parent = new_parent;
                }
 
                //
@@ -2461,14 +2575,17 @@ namespace Mono.CSharp {
                //
                public ParameterReference GetParameterReference (string name, Location loc)
                {
-                       Parameter par;
-                       int idx;
+                       ToplevelParameterInfo p = GetParameterInfo (name);
+                       return p == null ? null : new ParameterReference (this, p, loc);
+               }
 
+               public ToplevelParameterInfo GetParameterInfo (string name)
+               {
+                       int idx;
                        for (ToplevelBlock t = this; t != null; t = t.Container) {
-                               Parameters pars = t.Parameters;
-                               par = pars.GetParameterByName (name, out idx);
+                               Parameter par = t.Parameters.GetParameterByName (name, out idx);
                                if (par != null)
-                                       return new ParameterReference (par, this, idx, loc);
+                                       return t.parameter_info [idx];
                        }
                        return null;
                }
@@ -2527,12 +2644,13 @@ namespace Mono.CSharp {
 
                public bool IsThisAssigned (EmitContext ec)
                {
-                       return this_variable == null || this_variable.IsThisAssigned (ec, loc);
+                       return this_variable == null || this_variable.IsThisAssigned (ec);
                }
 
                public bool ResolveMeta (EmitContext ec, Parameters ip)
                {
                        int errors = Report.Errors;
+                       int orig_count = parameters.Count;
 
                        if (top_level_branching != null)
                                return true;
@@ -2540,23 +2658,54 @@ namespace Mono.CSharp {
                        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;
-                               }
-                       }
+                       // Assert: orig_count != parameter.Count => orig_count == 0
+                       if (orig_count != 0 && orig_count != parameters.Count)
+                               throw new InternalErrorException ("parameter information mismatch");
+
+                       int offset = Parent == null ? 0 : Parent.AssignableSlots;
 
-                       ResolveMeta (this, ec, ip);
+                       for (int i = 0; i < orig_count; ++i) {
+                               Parameter.Modifier mod = parameters.ParameterModifier (i);
+
+                               if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT)
+                                       continue;
+
+                               VariableInfo vi = new VariableInfo (ip, i, offset);
+                               parameter_info [i].VariableInfo = vi;
+                               offset += vi.Length;
+                       }
 
-                       if (child != null)
-                               child.ResolveMeta (this, ec, ip);
+                       ResolveMeta (ec, offset);
 
                        top_level_branching = ec.StartFlowBranching (this);
 
                        return Report.Errors == errors;
                }
 
+               // <summary>
+               //   Check whether all `out' parameters have been assigned.
+               // </summary>
+               public void CheckOutParameters (FlowBranching.UsageVector vector, Location loc)
+               {
+                       if (vector.IsUnreachable)
+                               return;
+
+                       int n = parameter_info == null ? 0 : parameter_info.Length;
+
+                       for (int i = 0; i < n; i++) {
+                               VariableInfo var = parameter_info [i].VariableInfo;
+
+                               if (var == null)
+                                       continue;
+
+                               if (vector.IsAssigned (var, false))
+                                       continue;
+
+                               Report.Error (177, loc, "The out parameter `{0}' must be assigned to before control leaves the current method",
+                                       var.Name);
+                       }
+               }
+
                public override void EmitMeta (EmitContext ec)
                {
                        base.EmitMeta (ec);
@@ -2567,7 +2716,7 @@ namespace Mono.CSharp {
                {
                        flags |= Flags.IsIterator;
 
-                       Block block = new Block (this);
+                       Block block = new ExplicitBlock (this, StartLocation, EndLocation);
                        foreach (Statement stmt in statements)
                                block.AddStatement (stmt);
                        statements = new ArrayList ();
@@ -2690,18 +2839,26 @@ namespace Mono.CSharp {
                        return true;
                }
 
-               public void Erorr_AlreadyOccurs ()
+               public void Erorr_AlreadyOccurs (Type switchType, SwitchLabel collisionWith)
                {
                        string label;
                        if (converted == null)
                                label = "default";
                        else if (converted == NullStringCase)
                                label = "null";
+                       else if (TypeManager.IsEnumType (switchType)) 
+                               label = TypeManager.CSharpEnumValue (switchType, converted);
                        else
                                label = converted.ToString ();
-
+                       
+                       Report.SymbolRelatedToPreviousError (collisionWith.loc, null);
                        Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label);
                }
+
+               public SwitchLabel Clone (CloneContext clonectx)
+               {
+                       return new SwitchLabel (label.Clone (clonectx), loc);
+               }
        }
 
        public class SwitchSection {
@@ -2714,10 +2871,20 @@ namespace Mono.CSharp {
                        Labels = labels;
                        Block = block;
                }
+
+               public SwitchSection Clone (CloneContext clonectx)
+               {
+                       ArrayList cloned_labels = new ArrayList ();
+
+                       foreach (SwitchLabel sl in cloned_labels)
+                               cloned_labels.Add (sl.Clone (clonectx));
+                       
+                       return new SwitchSection (cloned_labels, clonectx.LookupBlock (Block));
+               }
        }
        
        public class Switch : Statement {
-               public readonly ArrayList Sections;
+               public ArrayList Sections;
                public Expression Expr;
 
                /// <summary>
@@ -2788,7 +2955,7 @@ namespace Mono.CSharp {
                //
                Expression SwitchGoverningType (EmitContext ec, Expression expr)
                {
-                       Type t = expr.Type;
+                       Type t = TypeManager.DropGenericTypeArguments (expr.Type);
 
                        if (t == TypeManager.byte_type ||
                            t == TypeManager.sbyte_type ||
@@ -2872,7 +3039,7 @@ namespace Mono.CSharp {
                                foreach (SwitchLabel sl in ss.Labels){
                                        if (sl.Label == null){
                                                if (default_section != null){
-                                                       sl.Erorr_AlreadyOccurs ();
+                                                       sl.Erorr_AlreadyOccurs (SwitchType, (SwitchLabel)default_section.Labels [0]);
                                                        error = true;
                                                }
                                                default_section = ss;
@@ -2888,7 +3055,7 @@ namespace Mono.CSharp {
                                        try {
                                                Elements.Add (key, sl);
                                        } catch (ArgumentException) {
-                                               sl.Erorr_AlreadyOccurs ();
+                                               sl.Erorr_AlreadyOccurs (SwitchType, (SwitchLabel)Elements [key]);
                                                error = true;
                                        }
                                }
@@ -3182,7 +3349,11 @@ namespace Mono.CSharp {
                        
                        if (!fFoundDefault) {
                                ig.MarkLabel (lblDefault);
+                               if (HaveUnwrap && !fFoundNull) {
+                                       ig.MarkLabel (null_target);
+                               }
                        }
+                       
                        ig.MarkLabel (lblEnd);
                }
                //
@@ -3200,6 +3371,11 @@ namespace Mono.CSharp {
                        bool pending_goto_end = false;
                        bool null_marked = false;
                        bool null_found;
+                       int section_count = Sections.Count;
+
+                       // TODO: implement switch optimization for string by using Hashtable
+                       //if (SwitchType == TypeManager.string_type && section_count > 7)
+                       //      Console.WriteLine ("Switch optimization possible " + loc);
 
                        ig.Emit (OpCodes.Ldloc, val);
                        
@@ -3209,10 +3385,9 @@ namespace Mono.CSharp {
                                ig.Emit (OpCodes.Brfalse, default_target);
                        
                        ig.Emit (OpCodes.Ldloc, val);
-                       ig.Emit (OpCodes.Call, TypeManager.string_isinterneted_string);
+                       ig.Emit (OpCodes.Call, TypeManager.string_isinterned_string);
                        ig.Emit (OpCodes.Stloc, val);
 
-                       int section_count = Sections.Count;
                        for (int section = 0; section < section_count; section++){
                                SwitchSection ss = (SwitchSection) Sections [section];
 
@@ -3320,6 +3495,11 @@ namespace Mono.CSharp {
                        // Validate switch.
                        SwitchType = new_expr.Type;
 
+                       if (RootContext.Version == LanguageVersion.ISO_1 && SwitchType == TypeManager.bool_type) {
+                               Report.FeatureIsNotISO1 (loc, "switch expression of boolean type");
+                               return false;
+                       }
+
                        if (!CheckSwitch (ec))
                                return false;
 
@@ -3368,11 +3548,10 @@ namespace Mono.CSharp {
                                ec.CurrentBranching.CreateSibling (
                                        null, FlowBranching.SiblingType.SwitchSection);
 
-                       FlowBranching.Reachability reachability = ec.EndFlowBranching ();
+                       ec.EndFlowBranching ();
                        ec.Switch = old_switch;
 
-                       Report.Debug (1, "END OF SWITCH BLOCK", loc, ec.CurrentBranching,
-                                     reachability);
+                       Report.Debug (1, "END OF SWITCH BLOCK", loc, ec.CurrentBranching);
 
                        return true;
                }
@@ -3428,6 +3607,17 @@ namespace Mono.CSharp {
                        ec.LoopEnd = old_end;
                        ec.Switch = old_switch;
                }
+
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       Switch target = (Switch) t;
+
+                       target.Expr = Expr.Clone (clonectx);
+                       target.Sections = new ArrayList ();
+                       foreach (SwitchSection ss in Sections){
+                               target.Sections.Add (ss.Clone (clonectx));
+                       }
+               }
        }
 
        public abstract class ExceptionStatement : Statement
@@ -3481,22 +3671,14 @@ namespace Mono.CSharp {
 
                        FlowBranchingException branching = ec.StartFlowBranching (this);
                        bool ok = Statement.Resolve (ec);
-                       if (!ok) {
-                               ec.KillFlowBranching ();
-                               return false;
-                       }
 
                        ResolveFinally (branching);
 
-                       FlowBranching.Reachability reachability = ec.EndFlowBranching ();
-                       if (!reachability.AlwaysReturns) {
-                               // Unfortunately, System.Reflection.Emit automatically emits
-                               // a leave to the end of the finally block.
-                               // This is a problem if `returns' is true since we may jump
-                               // to a point after the end of the method.
-                               // As a workaround, emit an explicit ret here.
-                               ec.NeedReturnLabel ();
-                       }
+                       ec.EndFlowBranching ();
+
+                       // System.Reflection.Emit automatically emits a 'leave' to the end of the finally block.
+                       // So, ensure there's some IL code after the finally block.
+                       ec.NeedReturnLabel ();
 
                        // Avoid creating libraries that reference the internal
                        // mcs NullType:
@@ -3507,7 +3689,7 @@ namespace Mono.CSharp {
                        temp = new TemporaryVariable (t, loc);
                        temp.Resolve (ec);
                        
-                       return true;
+                       return ok;
                }
                
                protected override void DoEmit (EmitContext ec)
@@ -3534,10 +3716,18 @@ namespace Mono.CSharp {
                        temp.Emit (ec);
                        ec.ig.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object);
                }
+               
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       Lock target = (Lock) t;
+
+                       target.expr = expr.Clone (clonectx);
+                       target.Statement = Statement.Clone (clonectx);
+               }
        }
 
        public class Unchecked : Statement {
-               public readonly Block Block;
+               public Block Block;
                
                public Unchecked (Block b)
                {
@@ -3556,10 +3746,17 @@ namespace Mono.CSharp {
                        using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
                                Block.Emit (ec);
                }
+
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       Unchecked target = (Unchecked) t;
+
+                       target.Block = clonectx.LookupBlock (Block);
+               }
        }
 
        public class Checked : Statement {
-               public readonly Block Block;
+               public Block Block;
                
                public Checked (Block b)
                {
@@ -3578,10 +3775,17 @@ namespace Mono.CSharp {
                        using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
                                Block.Emit (ec);
                }
+
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       Checked target = (Checked) t;
+
+                       target.Block = clonectx.LookupBlock (Block);
+               }
        }
 
        public class Unsafe : Statement {
-               public readonly Block Block;
+               public Block Block;
 
                public Unsafe (Block b)
                {
@@ -3600,6 +3804,12 @@ namespace Mono.CSharp {
                        using (ec.With (EmitContext.Flags.InUnsafe, true))
                                Block.Emit (ec);
                }
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       Unsafe target = (Unsafe) t;
+
+                       target.Block = clonectx.LookupBlock (Block);
+               }
        }
 
        // 
@@ -3722,7 +3932,7 @@ namespace Mono.CSharp {
                        foreach (Pair p in declarators){
                                LocalInfo vi = (LocalInfo) p.First;
                                Expression e = (Expression) p.Second;
-
+                               
                                vi.VariableInfo.SetAssigned (ec);
                                vi.SetReadOnlyContext (LocalInfo.ReadOnlyContext.Fixed);
 
@@ -3769,7 +3979,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;
                                        }
 
@@ -3857,16 +4067,11 @@ namespace Mono.CSharp {
                        }
 
                        ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
+                       bool ok = statement.Resolve (ec);
+                       bool flow_unreachable = ec.EndFlowBranching ();
+                       has_ret = flow_unreachable;
 
-                       if (!statement.Resolve (ec)) {
-                               ec.KillFlowBranching ();
-                               return false;
-                       }
-
-                       FlowBranching.Reachability reachability = ec.EndFlowBranching ();
-                       has_ret = reachability.IsUnreachable;
-
-                       return true;
+                       return ok;
                }
                
                protected override void DoEmit (EmitContext ec)
@@ -3887,12 +4092,23 @@ namespace Mono.CSharp {
                                data [i].EmitExit (ec);
                        }
                }
+
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       Fixed target = (Fixed) t;
+
+                       target.type = type.Clone (clonectx);
+                       target.declarators = new ArrayList ();
+                       foreach (LocalInfo var in declarators)
+                               target.declarators.Add (clonectx.LookupVariable (var));
+                       target.statement = statement.Clone (clonectx);
+               }
        }
        
        public class Catch : Statement {
                public readonly string Name;
-               public readonly Block  Block;
-               public readonly Block  VarBlock;
+               public Block  Block;
+               public Block  VarBlock;
 
                Expression type_expr;
                Type type;
@@ -3978,12 +4194,21 @@ namespace Mono.CSharp {
                                return true;
                        }
                }
+
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       Catch target = (Catch) t;
+
+                       target.type_expr = type_expr.Clone (clonectx);
+                       target.Block = clonectx.LookupBlock (Block);
+                       target.VarBlock = clonectx.LookupBlock (VarBlock);
+               }
        }
 
        public class Try : ExceptionStatement {
-               public readonly Block Fini, Block;
-               public readonly ArrayList Specific;
-               public readonly Catch General;
+               public Block Fini, Block;
+               public ArrayList Specific;
+               public Catch General;
 
                bool need_exc_block;
                
@@ -4093,20 +4318,15 @@ namespace Mono.CSharp {
                        } else
                                emit_finally = Fini != null;
 
-                       FlowBranching.Reachability reachability = ec.EndFlowBranching ();
+                       ec.EndFlowBranching ();
 
-                       FlowBranching.UsageVector f_vector = ec.CurrentBranching.CurrentUsageVector;
+                       // System.Reflection.Emit automatically emits a 'leave' to the end of the finally block.
+                       // So, ensure there's some IL code after the finally block.
+                       ec.NeedReturnLabel ();
 
-                       Report.Debug (1, "END OF TRY", ec.CurrentBranching, reachability, vector, f_vector);
+                       FlowBranching.UsageVector f_vector = ec.CurrentBranching.CurrentUsageVector;
 
-                       if (!reachability.AlwaysReturns) {
-                               // Unfortunately, System.Reflection.Emit automatically emits
-                               // a leave to the end of the finally block.  This is a problem
-                               // if `returns' is true since we may jump to a point after the
-                               // end of the method.
-                               // As a workaround, emit an explicit ret here.
-                               ec.NeedReturnLabel ();
-                       }
+                       Report.Debug (1, "END OF TRY", ec.CurrentBranching, vector, f_vector);
 
                        return ok;
                }
@@ -4142,6 +4362,22 @@ namespace Mono.CSharp {
                                return General != null || Specific.Count > 0;
                        }
                }
+
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       Try target = (Try) t;
+
+                       target.Block = clonectx.LookupBlock (Block);
+                       if (Fini != null)
+                               target.Fini = clonectx.LookupBlock (Fini);
+                       if (General != null)
+                               target.General = (Catch) General.Clone (clonectx);
+                       if (Specific != null){
+                               target.Specific = new ArrayList ();
+                               foreach (Catch c in Specific)
+                                       target.Specific.Add (c.Clone (clonectx));
+                       }
+               }
        }
 
        public class Using : ExceptionStatement {
@@ -4152,7 +4388,7 @@ namespace Mono.CSharp {
                Type expr_type;
                Expression [] resolved_vars;
                Expression [] converted_vars;
-               ExpressionStatement [] assign;
+               Expression [] assign;
                TemporaryVariable local_copy;
                
                public Using (object expression_or_block, Statement stmt, Location l)
@@ -4167,81 +4403,52 @@ namespace Mono.CSharp {
                //
                bool ResolveLocalVariableDecls (EmitContext ec)
                {
-                       int i = 0;
-
-                       TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
-                       if (texpr == null)
-                               return false;
-
-                       expr_type = texpr.Type;
-
-                       //
-                       // The type must be an IDisposable or an implicit conversion
-                       // must exist.
-                       //
-                       converted_vars = new Expression [var_list.Count];
-                       resolved_vars = new Expression [var_list.Count];
-                       assign = new ExpressionStatement [var_list.Count];
-
-                       bool need_conv = !TypeManager.ImplementsInterface (
-                               expr_type, TypeManager.idisposable_type);
+                       resolved_vars = new Expression[var_list.Count];
+                       assign = new Expression [var_list.Count];
+                       converted_vars = new Expression[var_list.Count];
 
-                       foreach (DictionaryEntry e in var_list){
+                       for (int i = 0; i < assign.Length; ++i) {
+                               DictionaryEntry e = (DictionaryEntry) var_list [i];
                                Expression var = (Expression) e.Key;
+                               Expression new_expr = (Expression) e.Value;
 
-                               var = var.ResolveLValue (ec, new EmptyExpression (), loc);
-                               if (var == null)
+                               Expression a = new Assign (var, new_expr, loc);
+                               a = a.Resolve (ec);
+                               if (a == null)
                                        return false;
 
                                resolved_vars [i] = var;
+                               assign [i] = a;
 
-                               if (!need_conv) {
-                                       i++;
+                               if (TypeManager.ImplementsInterface (a.Type, TypeManager.idisposable_type)) {
+                                       converted_vars [i] = var;
                                        continue;
                                }
 
-                               converted_vars [i] = Convert.ImplicitConversion (
-                                       ec, var, TypeManager.idisposable_type, loc);
-
-                               if (converted_vars [i] == null) {
-                                       Error_IsNotConvertibleToIDisposable ();
+                               a = Convert.ImplicitConversion (ec, a, TypeManager.idisposable_type, var.Location);
+                               if (a == null) {
+                                       Error_IsNotConvertibleToIDisposable (var);
                                        return false;
                                }
 
-                               i++;
-                       }
-
-                       i = 0;
-                       foreach (DictionaryEntry e in var_list){
-                               Expression var = resolved_vars [i];
-                               Expression new_expr = (Expression) e.Value;
-                               Expression a;
-
-                               a = new Assign (var, new_expr, loc);
-                               a = a.Resolve (ec);
-                               if (a == null)
-                                       return false;
-
-                               if (!need_conv)
-                                       converted_vars [i] = var;
-                               assign [i] = (ExpressionStatement) a;
-                               i++;
+                               converted_vars [i] = a;
                        }
 
                        return true;
                }
 
-               void Error_IsNotConvertibleToIDisposable ()
+               static void Error_IsNotConvertibleToIDisposable (Expression expr)
                {
-                       Report.Error (1674, loc, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
-                               TypeManager.CSharpName (expr_type));
+                       Report.SymbolRelatedToPreviousError (expr.Type);
+                       Report.Error (1674, expr.Location, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
+                               expr.GetSignatureForError ());
                }
 
                bool ResolveExpression (EmitContext ec)
                {
                        if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)){
                                if (Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) {
-                                       Error_IsNotConvertibleToIDisposable ();
+                                       Error_IsNotConvertibleToIDisposable (expr);
                                        return false;
                                }
                        }
@@ -4261,7 +4468,7 @@ namespace Mono.CSharp {
                        int i = 0;
 
                        for (i = 0; i < assign.Length; i++) {
-                               assign [i].EmitStatement (ec);
+                               assign [i].Emit (ec);
 
                                if (emit_finally)
                                        ig.BeginExceptionBlock ();
@@ -4414,23 +4621,15 @@ namespace Mono.CSharp {
 
                        bool ok = Statement.Resolve (ec);
 
-                       if (!ok) {
-                               ec.KillFlowBranching ();
-                               return false;
-                       }
-
                        ResolveFinally (branching);
-                       FlowBranching.Reachability reachability = ec.EndFlowBranching ();
 
-                       if (!reachability.AlwaysReturns) {
-                               // Unfortunately, System.Reflection.Emit automatically emits a leave
-                               // to the end of the finally block.  This is a problem if `returns'
-                               // is true since we may jump to a point after the end of the method.
-                               // As a workaround, emit an explicit ret here.
-                               ec.NeedReturnLabel ();
-                       }
+                       ec.EndFlowBranching ();
 
-                       return true;
+                       // System.Reflection.Emit automatically emits a 'leave' to the end of the finally block.
+                       // So, ensure there's some IL code after the finally block.
+                       ec.NeedReturnLabel ();
+
+                       return ok;
                }
                
                protected override void DoEmit (EmitContext ec)
@@ -4448,6 +4647,18 @@ namespace Mono.CSharp {
                        else if (expression_or_block is Expression)
                                EmitExpressionFinally (ec);
                }
+
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       Using target = (Using) t;
+
+                       if (expression_or_block is Expression)
+                               target.expression_or_block = ((Expression) expression_or_block).Clone (clonectx);
+                       else
+                               target.expression_or_block = ((Statement) expression_or_block).Clone (clonectx);
+                       
+                       target.Statement = Statement.Clone (clonectx);
+               }
        }
 
        /// <summary>
@@ -4481,18 +4692,11 @@ namespace Mono.CSharp {
                        if (expr == null)
                                return false;
 
-                       Constant c = expr as Constant;
-                       if (c != null && c.GetValue () == null) {
+                       if (expr.Type == TypeManager.null_type) {
                                Report.Error (186, loc, "Use of null is not valid in this context");
                                return false;
                        }
 
-                       TypeExpr texpr = type.ResolveAsTypeTerminal (ec, false);
-                       if (texpr == null)
-                               return false;
-
-                       Type var_type = texpr.Type;
-
                        if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
                                Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
                                        expr.ExprClassName);
@@ -4513,13 +4717,12 @@ namespace Mono.CSharp {
                        }
 
                        if (expr.Type.IsArray) {
-                               array = new ArrayForeach (var_type, variable, expr, statement, loc);
+                               array = new ArrayForeach (type, variable, expr, statement, loc);
                                return array.Resolve (ec);
-                       } else {
-                               collection = new CollectionForeach (
-                                       var_type, variable, expr, statement, loc);
-                               return collection.Resolve (ec);
                        }
+                       
+                       collection = new CollectionForeach (type, variable, expr, statement, loc);
+                       return collection.Resolve (ec);
                }
 
                protected override void DoEmit (EmitContext ec)
@@ -4567,7 +4770,7 @@ namespace Mono.CSharp {
                        Expression variable, expr, conv;
                        Statement statement;
                        Type array_type;
-                       Type var_type;
+                       Expression var_type;
                        TemporaryVariable[] lengths;
                        ArrayCounter[] counter;
                        int rank;
@@ -4575,7 +4778,7 @@ namespace Mono.CSharp {
                        TemporaryVariable copy;
                        Expression access;
 
-                       public ArrayForeach (Type var_type, Expression var,
+                       public ArrayForeach (Expression var_type, Expression var,
                                             Expression expr, Statement stmt, Location l)
                        {
                                this.var_type = var_type;
@@ -4611,7 +4814,17 @@ namespace Mono.CSharp {
                                if (access == null)
                                        return false;
 
-                               conv = Convert.ExplicitConversion (ec, access, var_type, loc);
+                               VarExpr ve = var_type as VarExpr;
+                               if (ve != null) {
+                                       // Infer implicitly typed local variable from foreach array type
+                                       var_type = new TypeExpression (access.Type, ve.Location);
+                               }
+
+                               var_type = var_type.ResolveAsTypeTerminal (ec, false);
+                               if (var_type == null)
+                                       return false;
+
+                               conv = Convert.ExplicitConversion (ec, access, var_type.Type, loc);
                                if (conv == null)
                                        return false;
 
@@ -4693,11 +4906,12 @@ namespace Mono.CSharp {
                        MethodGroupExpr get_enumerator;
                        PropertyExpr get_current;
                        MethodInfo move_next;
-                       Type var_type, enumerator_type;
+                       Expression var_type;
+                       Type enumerator_type;
                        bool is_disposable;
                        bool enumerator_found;
 
-                       public CollectionForeach (Type var_type, Expression var,
+                       public CollectionForeach (Expression var_type, Expression var,
                                                  Expression expr, Statement stmt, Location l)
                        {
                                this.var_type = var_type;
@@ -4865,6 +5079,19 @@ namespace Mono.CSharp {
                                        TypeManager.CSharpName (expr.Type));
                        }
 
+                       public static bool IsOverride (MethodInfo m)
+                       {
+                               m = (MethodInfo) TypeManager.DropGenericMethodArguments (m);
+
+                               if (!m.IsVirtual || ((m.Attributes & MethodAttributes.NewSlot) != 0))
+                                       return false;
+                               if (m is MethodBuilder)
+                                       return true;
+
+                               MethodInfo base_method = m.GetBaseDefinition ();
+                               return base_method != m;
+                       }
+
                        bool TryType (EmitContext ec, Type t)
                        {
                                MethodGroupExpr mg = Expression.MemberLookup (
@@ -4885,7 +5112,7 @@ namespace Mono.CSharp {
                                        if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
                                                continue;
 
-                                       if (TypeManager.IsOverride (mi))
+                                       if (IsOverride (mi))
                                                continue;
 
                                        enumerator_found = true;
@@ -4898,16 +5125,26 @@ namespace Mono.CSharp {
                                                        if (!TypeManager.IsGenericType (mi.ReturnType))
                                                                continue;
 
-                                                       Report.SymbolRelatedToPreviousError(t);
+                                                       MethodBase mb = TypeManager.DropGenericMethodArguments (mi);
+                                                       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));
+                                                                    "because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
+                                                                    TypeManager.CSharpName (t), TypeManager.CSharpSignature (mb));
+                                                       return false;
+                                               }
+
+                                               // Always prefer generics enumerators
+                                               if (!TypeManager.IsGenericType (mi.ReturnType)) {
+                                                       if (TypeManager.ImplementsInterface (mi.DeclaringType, result.DeclaringType) ||
+                                                           TypeManager.ImplementsInterface (result.DeclaringType, mi.DeclaringType))
+                                                               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));
                                                        return false;
                                                }
-                                               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;
@@ -4955,24 +5192,10 @@ namespace Mono.CSharp {
                                //
                                // Now try to find the method in the interfaces
                                //
-                               while (t != null){
-                                       Type [] ifaces = t.GetInterfaces ();
-
-                                       foreach (Type i in ifaces){
-                                               if (TryType (ec, i))
-                                                       return true;
-                                       }
-                               
-                                       //
-                                       // Since TypeBuilder.GetInterfaces only returns the interface
-                                       // types for this type, we have to keep looping, but once
-                                       // we hit a non-TypeBuilder (ie, a Type), then we know we are
-                                       // done, because it returns all the types
-                                       //
-                                       if ((t is TypeBuilder))
-                                               t = t.BaseType;
-                                       else
-                                               break;
+                               Type [] ifaces = TypeManager.GetInterfaces (t);
+                               foreach (Type i in ifaces){
+                                       if (TryType (ec, i))
+                                               return true;
                                }
 
                                return false;
@@ -4988,6 +5211,16 @@ namespace Mono.CSharp {
                                        return false;
                                }
 
+                               VarExpr ve = var_type as VarExpr;
+                               if (ve != null) {
+                                       // Infer implicitly typed local variable from foreach enumerable type
+                                       var_type = new TypeExpression (get_current.PropertyInfo.PropertyType, 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);
 
@@ -5008,7 +5241,7 @@ namespace Mono.CSharp {
                                get_current.InstanceExpression = enumerator;
 
                                Statement block = new CollectionForeachStatement (
-                                       var_type, variable, get_current, statement, loc);
+                                       var_type.Type, variable, get_current, statement, loc);
 
                                loop = new While (move_next_expr, block, loc);
 
@@ -5133,5 +5366,15 @@ namespace Mono.CSharp {
                                statement.Emit (ec);
                        }
                }
+
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       Foreach target = (Foreach) t;
+
+                       target.type = type.Clone (clonectx);
+                       target.variable = variable.Clone (clonectx);
+                       target.expr = expr.Clone (clonectx);
+                       target.statement = statement.Clone (clonectx);
+               }
        }
 }