2008-07-04 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / statement.cs
index 9280d8d923fed8cfeb9d6d25a39e51ee33d02b85..e3159d390829546bd4d4340b79469adb24841a25 100644 (file)
@@ -6,8 +6,8 @@
 //   Martin Baulig (martin@ximian.com)
 //   Marek Safar (marek.safar@seznam.cz)
 //
-// (C) 2001, 2002, 2003 Ximian, Inc.
-// (C) 2003, 2004 Novell, Inc.
+// Copyright 2001, 2002, 2003 Ximian, Inc.
+// Copyright 2003, 2004 Novell, Inc.
 //
 
 using System;
@@ -103,6 +103,12 @@ namespace Mono.CSharp {
                        return s;
                }
 
+               public virtual Expression CreateExpressionTree (EmitContext ec)
+               {
+                       Report.Error (834, loc, "A lambda expression with statement body cannot be converted to an expresion tree");
+                       return null;
+               }
+
                public Statement PerformClone ()
                {
                        CloneContext clonectx = new CloneContext ();
@@ -110,6 +116,7 @@ namespace Mono.CSharp {
                        return Clone (clonectx);
                }
 
+               public abstract void MutateHoistedGenericType (AnonymousMethodStorey storey);
        }
 
        //
@@ -196,6 +203,10 @@ namespace Mono.CSharp {
                {
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+               }
+
                protected override void CloneTo (CloneContext clonectx, Statement target)
                {
                        // nothing needed.
@@ -209,24 +220,32 @@ namespace Mono.CSharp {
 
                bool is_true_ret;
                
-               public If (Expression expr, Statement trueStatement, Location l)
+               public If (Expression expr, Statement true_statement, Location l)
                {
                        this.expr = expr;
-                       TrueStatement = trueStatement;
+                       TrueStatement = true_statement;
                        loc = l;
                }
 
                public If (Expression expr,
-                          Statement trueStatement,
-                          Statement falseStatement,
+                          Statement true_statement,
+                          Statement false_statement,
                           Location l)
                {
                        this.expr = expr;
-                       TrueStatement = trueStatement;
-                       FalseStatement = falseStatement;
+                       TrueStatement = true_statement;
+                       FalseStatement = false_statement;
                        loc = l;
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       expr.MutateHoistedGenericType (storey);
+                       TrueStatement.MutateHoistedGenericType (storey);
+                       if (FalseStatement != null)
+                               FalseStatement.MutateHoistedGenericType (storey);
+               }
+
                public override bool Resolve (EmitContext ec)
                {
                        bool ok = true;
@@ -247,8 +266,8 @@ namespace Mono.CSharp {
                        //
                        // Dead code elimination
                        //
-                       if (expr is BoolConstant){
-                               bool take = ((BoolConstant) expr).Value;
+                       if (expr is Constant){
+                               bool take = !((Constant) expr).IsDefaultValue;
 
                                if (take){
                                        if (!TrueStatement.Resolve (ec))
@@ -296,19 +315,20 @@ namespace Mono.CSharp {
                        Label end;
 
                        //
-                       // If we're a boolean expression, Resolve() already
+                       // If we're a boolean constant, Resolve() already
                        // eliminated dead code for us.
                        //
-                       if (expr is BoolConstant){
-                               bool take = ((BoolConstant) expr).Value;
+                       Constant c = expr as Constant;
+                       if (c != null){
+                               c.EmitSideEffect (ec);
 
-                               if (take)
+                               if (!c.IsDefaultValue)
                                        TrueStatement.Emit (ec);
                                else if (FalseStatement != null)
                                        FalseStatement.Emit (ec);
 
                                return;
-                       }
+                       }                       
                        
                        expr.EmitBranchable (ec, false_target, false);
                        
@@ -347,11 +367,10 @@ namespace Mono.CSharp {
        public class Do : Statement {
                public Expression expr;
                public Statement  EmbeddedStatement;
-               bool infinite;
                
-               public Do (Statement statement, Expression boolExpr, Location l)
+               public Do (Statement statement, Expression bool_expr, Location l)
                {
-                       expr = boolExpr;
+                       expr = bool_expr;
                        EmbeddedStatement = statement;
                        loc = l;
                }
@@ -375,14 +394,11 @@ namespace Mono.CSharp {
                        expr = Expression.ResolveBoolean (ec, expr, loc);
                        if (expr == null)
                                ok = false;
-                       else if (expr is BoolConstant){
-                               bool res = ((BoolConstant) expr).Value;
-
-                               if (res)
-                                       infinite = true;
+                       else if (expr is Constant){
+                               bool infinite = !((Constant) expr).IsDefaultValue;
+                               if (infinite)
+                                       ec.CurrentBranching.CurrentUsageVector.Goto ();
                        }
-                       if (infinite)
-                               ec.CurrentBranching.CurrentUsageVector.Goto ();
 
                        ec.EndFlowBranching ();
 
@@ -406,9 +422,10 @@ namespace Mono.CSharp {
                        //
                        // Dead code elimination
                        //
-                       if (expr is BoolConstant){
-                               bool res = ((BoolConstant) expr).Value;
+                       if (expr is Constant){
+                               bool res = !((Constant) expr).IsDefaultValue;
 
+                               expr.EmitSideEffect (ec);
                                if (res)
                                        ec.ig.Emit (OpCodes.Br, loop); 
                        } else
@@ -420,6 +437,12 @@ namespace Mono.CSharp {
                        ec.LoopEnd = old_end;
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       expr.MutateHoistedGenericType (storey);
+                       EmbeddedStatement.MutateHoistedGenericType (storey);
+               }
+
                protected override void CloneTo (CloneContext clonectx, Statement t)
                {
                        Do target = (Do) t;
@@ -434,9 +457,9 @@ namespace Mono.CSharp {
                public Statement Statement;
                bool infinite, empty;
                
-               public While (Expression boolExpr, Statement statement, Location l)
+               public While (Expression bool_expr, Statement statement, Location l)
                {
-                       this.expr = boolExpr;
+                       this.expr = bool_expr;
                        Statement = statement;
                        loc = l;
                }
@@ -452,10 +475,10 @@ namespace Mono.CSharp {
                        //
                        // Inform whether we are infinite or not
                        //
-                       if (expr is BoolConstant){
-                               BoolConstant bc = (BoolConstant) expr;
+                       if (expr is Constant){
+                               bool value = !((Constant) expr).IsDefaultValue;
 
-                               if (bc.Value == false){
+                               if (value == false){
                                        if (!Statement.ResolveUnreachable (ec, true))
                                                return false;
                                        empty = true;
@@ -483,8 +506,10 @@ namespace Mono.CSharp {
                
                protected override void DoEmit (EmitContext ec)
                {
-                       if (empty)
+                       if (empty) {
+                               expr.EmitSideEffect (ec);
                                return;
+                       }
 
                        ILGenerator ig = ec.ig;
                        Label old_begin = ec.LoopBegin;
@@ -496,8 +521,10 @@ namespace Mono.CSharp {
                        //
                        // Inform whether we are infinite or not
                        //
-                       if (expr is BoolConstant){
+                       if (expr is Constant){
+                               // expr is 'true', since the 'empty' case above handles the 'false' case
                                ig.MarkLabel (ec.LoopBegin);
+                               expr.EmitSideEffect (ec);
                                Statement.Emit (ec);
                                ig.Emit (OpCodes.Br, ec.LoopBegin);
                                        
@@ -515,6 +542,7 @@ namespace Mono.CSharp {
                                Statement.Emit (ec);
                        
                                ig.MarkLabel (ec.LoopBegin);
+                               ec.Mark (loc, true);
 
                                expr.EmitBranchable (ec, while_loop, true);
                                
@@ -525,6 +553,11 @@ namespace Mono.CSharp {
                        ec.LoopEnd = old_end;
                }
 
+               public override void Emit (EmitContext ec)
+               {
+                       DoEmit (ec);
+               }
+
                protected override void CloneTo (CloneContext clonectx, Statement t)
                {
                        While target = (While) t;
@@ -532,6 +565,12 @@ namespace Mono.CSharp {
                        target.expr = expr.Clone (clonectx);
                        target.Statement = Statement.Clone (clonectx);
                }
+
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       expr.MutateHoistedGenericType (storey);
+                       Statement.MutateHoistedGenericType (storey);
+               }
        }
 
        public class For : Statement {
@@ -541,13 +580,13 @@ namespace Mono.CSharp {
                public Statement Statement;
                bool infinite, empty;
                
-               public For (Statement initStatement,
+               public For (Statement init_statement,
                            Expression test,
                            Statement increment,
                            Statement statement,
                            Location l)
                {
-                       InitStatement = initStatement;
+                       InitStatement = init_statement;
                        Test = test;
                        Increment = increment;
                        Statement = statement;
@@ -567,10 +606,10 @@ namespace Mono.CSharp {
                                Test = Expression.ResolveBoolean (ec, Test, loc);
                                if (Test == null)
                                        ok = false;
-                               else if (Test is BoolConstant){
-                                       BoolConstant bc = (BoolConstant) Test;
+                               else if (Test is Constant){
+                                       bool value = !((Constant) Test).IsDefaultValue;
 
-                                       if (bc.Value == false){
+                                       if (value == false){
                                                if (!Statement.ResolveUnreachable (ec, true))
                                                        return false;
                                                if ((Increment != null) &&
@@ -612,20 +651,22 @@ namespace Mono.CSharp {
 
                        return ok;
                }
-               
+
                protected override void DoEmit (EmitContext ec)
                {
-                       if (empty)
+                       if (InitStatement != null && InitStatement != EmptyStatement.Value)
+                               InitStatement.Emit (ec);
+
+                       if (empty) {
+                               Test.EmitSideEffect (ec);
                                return;
+                       }
 
                        ILGenerator ig = ec.ig;
                        Label old_begin = ec.LoopBegin;
                        Label old_end = ec.LoopEnd;
                        Label loop = ig.DefineLabel ();
                        Label test = ig.DefineLabel ();
-                       
-                       if (InitStatement != null && InitStatement != EmptyStatement.Value)
-                               InitStatement.Emit (ec);
 
                        ec.LoopBegin = ig.DefineLabel ();
                        ec.LoopEnd = ig.DefineLabel ();
@@ -646,13 +687,15 @@ namespace Mono.CSharp {
                        if (Test != null){
                                //
                                // The Resolve code already catches the case for
-                               // Test == BoolConstant (false) so we know that
+                               // Test == Constant (false) so we know that
                                // this is true
                                //
-                               if (Test is BoolConstant)
+                               if (Test is Constant) {
+                                       Test.EmitSideEffect (ec);
                                        ig.Emit (OpCodes.Br, loop);
-                               else
+                               } else {
                                        Test.EmitBranchable (ec, loop, true);
+                               }
                                
                        } else
                                ig.Emit (OpCodes.Br, loop);
@@ -662,6 +705,18 @@ namespace Mono.CSharp {
                        ec.LoopEnd = old_end;
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       if (InitStatement != null)
+                               InitStatement.MutateHoistedGenericType (storey);
+                       if (Test != null)
+                               Test.MutateHoistedGenericType (storey);
+                       if (Increment != null)
+                               Increment.MutateHoistedGenericType (storey);
+
+                       Statement.MutateHoistedGenericType (storey);
+               }
+
                protected override void CloneTo (CloneContext clonectx, Statement t)
                {
                        For target = (For) t;
@@ -697,6 +752,11 @@ namespace Mono.CSharp {
                        expr.EmitStatement (ec);
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       expr.MutateHoistedGenericType (storey);
+               }
+
                public override string ToString ()
                {
                        return "StatementExpression (" + expr + ")";
@@ -710,20 +770,42 @@ namespace Mono.CSharp {
                }
        }
 
+       // A 'return' or a 'yield break'
+       public abstract class ExitStatement : Statement
+       {
+               protected bool unwind_protect;
+               protected abstract bool DoResolve (EmitContext ec);
+
+               public virtual void Error_FinallyClause ()
+               {
+                       Report.Error (157, loc, "Control cannot leave the body of a finally clause");
+               }
+
+               public sealed override bool Resolve (EmitContext ec)
+               {
+                       if (!DoResolve (ec))
+                               return false;
+
+                       unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, this);
+                       if (unwind_protect)
+                               ec.NeedReturnLabel ();
+                       ec.CurrentBranching.CurrentUsageVector.Goto ();
+                       return true;
+               }
+       }
+
        /// <summary>
        ///   Implements the return statement
        /// </summary>
-       public class Return : Statement {
-               Expression Expr;
-               bool unwind_protect;
-               
+       public class Return : ExitStatement {
+               protected Expression Expr;
                public Return (Expression expr, Location l)
                {
                        Expr = expr;
                        loc = l;
                }
                
-               bool DoResolve (EmitContext ec)
+               protected override bool DoResolve (EmitContext ec)
                {
                        if (Expr == null) {
                                if (ec.ReturnType == TypeManager.void_type)
@@ -735,7 +817,7 @@ namespace Mono.CSharp {
                                return false;
                        }
 
-                       AnonymousContainer am = ec.CurrentAnonymousMethod;
+                       AnonymousExpression am = ec.CurrentAnonymousMethod;
                        if ((am != null) && am.IsIterator && ec.InIterator) {
                                Report.Error (1622, loc, "Cannot return a value from iterators. Use the yield return " +
                                                  "statement to return a value, or yield break to end the iteration");
@@ -753,6 +835,12 @@ namespace Mono.CSharp {
 
                        if (Expr.Type != ec.ReturnType) {
                                if (ec.InferReturnType) {
+                                       //
+                                       // void cannot be used in contextual return
+                                       //
+                                       if (Expr.Type == TypeManager.void_type)
+                                               return false;
+
                                        ec.ReturnType = Expr.Type;
                                } else {
                                        Expr = Convert.ImplicitConversionRequired (
@@ -761,7 +849,7 @@ namespace Mono.CSharp {
                                        if (Expr == null) {
                                                if (am != null) {
                                                        Report.Error (1662, loc,
-                                                               "Cannot convert `{0}' to delegate type `D' because some of the return types in the block are not implicitly convertible to the delegate return type",
+                                                               "Cannot convert `{0}' to delegate type `{1}' because some of the return types in the block are not implicitly convertible to the delegate return type",
                                                                am.ContainerType, am.GetSignatureForError ());
                                                }
                                                return false;
@@ -771,18 +859,6 @@ namespace Mono.CSharp {
 
                        return true;                    
                }
-
-               public override bool Resolve (EmitContext ec)
-               {
-                       if (!DoResolve (ec))
-                               return false;
-                       
-                       unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
-                       if (unwind_protect)
-                               ec.NeedReturnLabel ();
-                       ec.CurrentBranching.CurrentUsageVector.Goto ();
-                       return true;
-               }
                
                protected override void DoEmit (EmitContext ec)
                {
@@ -799,6 +875,12 @@ namespace Mono.CSharp {
                                ec.ig.Emit (OpCodes.Ret);
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       if (Expr != null)
+                               Expr.MutateHoistedGenericType (storey);
+               }
+
                protected override void CloneTo (CloneContext clonectx, Statement t)
                {
                        Return target = (Return) t;
@@ -844,6 +926,10 @@ namespace Mono.CSharp {
                        Label l = label.LabelTarget (ec);
                        ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
                }
+
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+               }
        }
 
        public class LabeledStatement : Statement {
@@ -910,6 +996,10 @@ namespace Mono.CSharp {
                        ec.ig.MarkLabel (label);
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+               }
+
                public void AddReference ()
                {
                        referenced = true;
@@ -946,6 +1036,10 @@ namespace Mono.CSharp {
                        }
                        ec.ig.Emit (OpCodes.Br, ec.Switch.DefaultTarget);
                }
+
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+               }
        }
 
        /// <summary>
@@ -1014,12 +1108,16 @@ namespace Mono.CSharp {
                        ec.ig.Emit (OpCodes.Br, sl.GetILLabelCode (ec));
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       expr.MutateHoistedGenericType (storey);
+               }
+
                protected override void CloneTo (CloneContext clonectx, Statement t)
                {
                        GotoCase target = (GotoCase) t;
 
                        target.expr = expr.Clone (clonectx);
-                       target.sl = sl.Clone (clonectx);
                }
        }
        
@@ -1036,39 +1134,27 @@ namespace Mono.CSharp {
                {
                        ec.CurrentBranching.CurrentUsageVector.Goto ();
 
-                       if (expr != null){
-                               expr = expr.Resolve (ec);
-                               if (expr == null)
-                                       return false;
-
-                               ExprClass eclass = expr.eclass;
+                       if (expr == null)
+                               return ec.CurrentBranching.CheckRethrow (loc);
 
-                               if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
-                                       eclass == ExprClass.Value || eclass == ExprClass.IndexerAccess)) {
-                                       expr.Error_UnexpectedKind (ec.DeclContainer, "value, variable, property or indexer access ", loc);
-                                       return false;
-                               }
+                       expr = expr.Resolve (ec);
+                       if (expr == null)
+                               return false;
 
-                               Type t = expr.Type;
-                               
-                               if ((t != TypeManager.exception_type) &&
-                                   !TypeManager.IsSubclassOf (t, TypeManager.exception_type) &&
-                                   !(expr is NullLiteral)) {
-                                       Error (155,
-                                               "The type caught or thrown must be derived " +
-                                               "from System.Exception");
-                                       return false;
-                               }
-                               return true;
-                       }
+                       ExprClass eclass = expr.eclass;
 
-                       if (!ec.InCatch) {
-                               Error (156, "A throw statement with no arguments is not allowed outside of a catch clause");
+                       if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
+                             eclass == ExprClass.Value || eclass == ExprClass.IndexerAccess)) {
+                               expr.Error_UnexpectedKind (ec.DeclContainer, "value, variable, property or indexer access ", loc);
                                return false;
                        }
 
-                       if (ec.InFinally) {
-                               Error (724, "A throw statement with no arguments is not allowed inside of a finally clause nested inside of the innermost catch clause");
+                       Type t = expr.Type;
+
+                       if ((t != TypeManager.exception_type) &&
+                           !TypeManager.IsSubclassOf (t, TypeManager.exception_type) &&
+                           !(expr is NullLiteral)) {
+                               Error (155, "The type caught or thrown must be derived from System.Exception");
                                return false;
                        }
                        return true;
@@ -1085,11 +1171,18 @@ namespace Mono.CSharp {
                        }
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       if (expr != null)
+                               expr.MutateHoistedGenericType (storey);
+               }
+
                protected override void CloneTo (CloneContext clonectx, Statement t)
                {
                        Throw target = (Throw) t;
 
-                       target.expr = expr.Clone (clonectx);
+                       if (expr != null)
+                               target.expr = expr.Clone (clonectx);
                }
        }
 
@@ -1114,6 +1207,10 @@ namespace Mono.CSharp {
                {
                        ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopEnd);
                }
+
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+               }
                
                protected override void CloneTo (CloneContext clonectx, Statement t)
                {
@@ -1143,33 +1240,21 @@ namespace Mono.CSharp {
                        ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin);
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+               }
+
                protected override void CloneTo (CloneContext clonectx, Statement t)
                {
                        // nothing needed.
                }
        }
 
-       public abstract class Variable
+       public interface ILocalVariable
        {
-               public abstract Type Type {
-                       get;
-               }
-
-               public abstract bool HasInstance {
-                       get;
-               }
-
-               public abstract bool NeedsTemporary {
-                       get;
-               }
-
-               public abstract void EmitInstance (EmitContext ec);
-
-               public abstract void Emit (EmitContext ec);
-
-               public abstract void EmitAssign (EmitContext ec);
-
-               public abstract void EmitAddressOf (EmitContext ec);
+               void Emit (EmitContext ec);
+               void EmitAssign (EmitContext ec);
+               void EmitAddressOf (EmitContext ec);
        }
 
        public interface IKnownVariable {
@@ -1180,8 +1265,8 @@ namespace Mono.CSharp {
        //
        // The information about a user-perceived local variable
        //
-       public class LocalInfo : IKnownVariable {
-               public Expression Type;
+       public class LocalInfo : IKnownVariable, ILocalVariable {
+               public readonly Expression Type;
 
                public Type VariableType;
                public readonly string Name;
@@ -1189,11 +1274,7 @@ namespace Mono.CSharp {
                public readonly Block Block;
 
                public VariableInfo VariableInfo;
-
-               Variable var;
-               public Variable Variable {
-                       get { return var; }
-               }
+               public HoistedVariable HoistedVariableReference;
 
                [Flags]
                enum Flags : byte {
@@ -1201,7 +1282,6 @@ namespace Mono.CSharp {
                        ReadOnly = 2,
                        Pinned = 4,
                        IsThis = 8,
-                       Captured = 16,
                        AddressTaken = 32,
                        CompilerGenerated = 64,
                        IsConstant = 128
@@ -1234,11 +1314,10 @@ namespace Mono.CSharp {
 
                public void ResolveVariable (EmitContext ec)
                {
-                       Block theblock = Block;
-                       if (theblock.ScopeInfo != null)
-                               var = theblock.ScopeInfo.GetCapturedVariable (this);
+                       if (HoistedVariableReference != null)
+                               return;
 
-                       if (var == null) {
+                       if (builder == null) {
                                if (Pinned)
                                        //
                                        // This is needed to compile on both .NET 1.x and .NET 2.x
@@ -1247,15 +1326,28 @@ namespace Mono.CSharp {
                                        builder = TypeManager.DeclareLocalPinned (ec.ig, VariableType);
                                else
                                        builder = ec.ig.DeclareLocal (VariableType);
-
-                               var = new LocalVariable (this, builder);
                        }
                }
 
+               public void Emit (EmitContext ec)
+               {
+                       ec.ig.Emit (OpCodes.Ldloc, builder);
+               }
+
+               public void EmitAssign (EmitContext ec)
+               {
+                       ec.ig.Emit (OpCodes.Stloc, builder);
+               }
+
+               public void EmitAddressOf (EmitContext ec)
+               {
+                       ec.ig.Emit (OpCodes.Ldloca, builder);
+               }
+
                public void EmitSymbolInfo (EmitContext ec, string name)
                {
                        if (builder != null)
-                               ec.DefineLocalVariable (name, builder);
+                               ec.DefineLocalVariable (Name, builder);
                }
 
                public bool IsThisAssigned (EmitContext ec)
@@ -1279,13 +1371,14 @@ namespace Mono.CSharp {
 
                public bool Resolve (EmitContext ec)
                {
-                       if (VariableType == null) {
-                               TypeExpr texpr = Type.ResolveAsContextualType (ec, false);
-                               if (texpr == null)
-                                       return false;
+                       if (VariableType != null)
+                               return true;
+
+                       TypeExpr texpr = Type.ResolveAsContextualType (ec, false);
+                       if (texpr == null)
+                               return false;
                                
-                               VariableType = texpr.Type;
-                       }
+                       VariableType = texpr.Type;
 
                        if (TypeManager.IsGenericParameter (VariableType))
                                return true;
@@ -1306,11 +1399,6 @@ namespace Mono.CSharp {
                        return true;
                }
 
-               public bool IsCaptured {
-                       get { return (flags & Flags.Captured) != 0; }
-                       set { flags |= Flags.Captured; }
-               }
-
                public bool IsConstant {
                        get { return (flags & Flags.IsConstant) != 0; }
                        set { flags |= Flags.IsConstant; }
@@ -1385,50 +1473,6 @@ namespace Mono.CSharp {
                        get { return Location; }
                }
 
-               protected class LocalVariable : Variable
-               {
-                       public readonly LocalInfo LocalInfo;
-                       LocalBuilder builder;
-
-                       public LocalVariable (LocalInfo local, LocalBuilder builder)
-                       {
-                               this.LocalInfo = local;
-                               this.builder = builder;
-                       }
-
-                       public override Type Type {
-                               get { return LocalInfo.VariableType; }
-                       }
-
-                       public override bool HasInstance {
-                               get { return false; }
-                       }
-
-                       public override bool NeedsTemporary {
-                               get { return false; }
-                       }
-
-                       public override void EmitInstance (EmitContext ec)
-                       {
-                               // Do nothing.
-                       }
-
-                       public override void Emit (EmitContext ec)
-                       {
-                               ec.ig.Emit (OpCodes.Ldloc, builder);
-                       }
-
-                       public override void EmitAssign (EmitContext ec)
-                       {
-                               ec.ig.Emit (OpCodes.Stloc, builder);
-                       }
-
-                       public override void EmitAddressOf (EmitContext ec)
-                       {
-                               ec.ig.Emit (OpCodes.Ldloca, builder);
-                       }
-               }
-
                public LocalInfo Clone (CloneContext clonectx)
                {
                        //
@@ -1466,7 +1510,7 @@ namespace Mono.CSharp {
                public Location EndLocation = Location.Null;
 
                public ExplicitBlock Explicit;
-               public ToplevelBlock Toplevel;
+               public ToplevelBlock Toplevel; // TODO: Use Explicit
 
                [Flags]
                public enum Flags : byte {
@@ -1475,9 +1519,7 @@ namespace Mono.CSharp {
                        VariablesInitialized = 4,
                        HasRet = 8,
                        IsDestructor = 16,
-                       Unsafe = 32,
-                       HasVarargs = 64, // Used in ToplevelBlock
-                       IsIterator = 128
+                       Unsafe = 32
                }
                protected Flags flags;
 
@@ -1495,7 +1537,6 @@ namespace Mono.CSharp {
                // The statements in this block
                //
                protected ArrayList statements;
-               int num_statements;
 
                //
                // An array of Blocks.  We keep track of children just
@@ -1509,7 +1550,7 @@ namespace Mono.CSharp {
                //
                // Labels.  (label, block) pairs.
                //
-               Hashtable labels;
+               protected HybridDictionary labels;
 
                //
                // Keeps track of (name, type) pairs
@@ -1518,7 +1559,7 @@ namespace Mono.CSharp {
 
                //
                // Keeps track of constants
-               Hashtable constants;
+               HybridDictionary constants;
 
                //
                // Temporary variables.
@@ -1530,7 +1571,7 @@ namespace Mono.CSharp {
                //
                Block switch_block;
 
-               ExpressionStatement scope_init;
+               ArrayList scope_initializers;
 
                ArrayList anonymous_children;
 
@@ -1539,7 +1580,6 @@ namespace Mono.CSharp {
                int this_id;
 
                int assignable_slots;
-               protected ScopeInfo scope_info;
                bool unreachable_shown;
                bool unreachable;
                
@@ -1571,7 +1611,7 @@ namespace Mono.CSharp {
                        this.EndLocation = end;
                        this.loc = start;
                        this_id = id++;
-                       statements = new ArrayList ();
+                       statements = new ArrayList (4);
                }
 
                public Block CreateSwitchBlock (Location start)
@@ -1597,7 +1637,7 @@ namespace Mono.CSharp {
                void AddChild (Block b)
                {
                        if (children == null)
-                               children = new ArrayList ();
+                               children = new ArrayList (1);
                        
                        children.Add (b);
                }
@@ -1668,7 +1708,7 @@ namespace Mono.CSharp {
                        Toplevel.CheckError158 (name, target.loc);
 
                        if (labels == null)
-                               labels = new Hashtable ();
+                               labels = new HybridDictionary();
 
                        labels.Add (name, target);
                        return true;
@@ -1767,8 +1807,7 @@ namespace Mono.CSharp {
                        if (vi != null) {
                                Report.SymbolRelatedToPreviousError (vi.Location, name);
                                if (Explicit == vi.Block.Explicit)
-                                       Report.Error (128, l,
-                                               "A local variable named `{0}' is already defined in this scope", name);
+                                       Error_AlreadyDeclared (l, name, null);
                                else
                                        Error_AlreadyDeclared (l, name, "parent");
                                return null;
@@ -1779,7 +1818,18 @@ namespace Mono.CSharp {
                                Report.SymbolRelatedToPreviousError (pi.Location, name);
                                Error_AlreadyDeclared (loc, name,
                                        pi.Block == Toplevel ? "method argument" : "parent or current");
+                               return null;
                        }
+                       
+                       if (Toplevel.GenericMethod != null) {
+                               foreach (TypeParameter tp in Toplevel.GenericMethod.CurrentTypeParameters) {
+                                       if (tp.Name == name) {
+                                               Report.SymbolRelatedToPreviousError (tp);
+                                               Error_AlreadyDeclaredTypeParameter (loc, name);
+                                               return null;
+                                       }
+                               }
+                       }                       
 
                        IKnownVariable kvi = Explicit.GetKnownVariable (name);
                        if (kvi != null) {
@@ -1789,30 +1839,51 @@ namespace Mono.CSharp {
                        }
 
                        vi = new LocalInfo (type, name, this, l);
-                       Variables.Add (name, vi);
-                       Explicit.AddKnownVariable (name, vi);
+                       AddVariable (vi);
 
                        if ((flags & Flags.VariablesInitialized) != 0)
                                throw new InternalErrorException ("block has already been resolved");
 
                        return vi;
                }
+               
+               protected virtual void AddVariable (LocalInfo li)
+               {
+                       Variables.Add (li.Name, li);
+                       Explicit.AddKnownVariable (li.Name, li);
+               }
 
-               protected static void Error_AlreadyDeclared (Location loc, string var, string reason)
+               protected virtual void Error_AlreadyDeclared (Location loc, string var, string reason)
                {
+                       if (reason == null) {
+                               Error_AlreadyDeclared (loc, var);
+                               return;
+                       }
+                       
                        Report.Error (136, loc, "A local variable named `{0}' cannot be declared " +
                                      "in this scope because it would give a different meaning " +
                                      "to `{0}', which is already used in a `{1}' scope " +
                                      "to denote something else", var, reason);
                }
 
+               protected virtual void Error_AlreadyDeclared (Location loc, string name)
+               {
+                       Report.Error (128, loc,
+                               "A local variable named `{0}' is already defined in this scope", name);
+               }
+                                       
+               protected virtual void Error_AlreadyDeclaredTypeParameter (Location loc, string name)
+               {
+                       GenericMethod.Error_ParameterNameCollision (loc, name, "local variable");
+               }                                       
+
                public bool AddConstant (Expression type, string name, Expression value, Location l)
                {
                        if (AddVariable (type, name, l) == null)
                                return false;
                        
                        if (constants == null)
-                               constants = new Hashtable ();
+                               constants = new HybridDictionary();
 
                        constants.Add (name, value);
 
@@ -1868,6 +1939,18 @@ namespace Mono.CSharp {
                        }
                        return null;
                }
+
+               //
+               // It should be used by expressions which require to
+               // register a statement during resolve process.
+               //
+               public void AddScopeStatement (StatementExpression s)
+               {
+                       if (scope_initializers == null)
+                               scope_initializers = new ArrayList ();
+
+                       scope_initializers.Add (s);
+               }
                
                public void AddStatement (Statement s)
                {
@@ -1905,18 +1988,6 @@ namespace Mono.CSharp {
                        }
                }
 
-               public ScopeInfo ScopeInfo {
-                       get { return scope_info; }
-               }
-
-               public ScopeInfo CreateScopeInfo ()
-               {
-                       if (scope_info == null)
-                               scope_info = ScopeInfo.CreateScope (this);
-
-                       return scope_info;
-               }
-
                public ArrayList AnonymousChildren {
                        get { return anonymous_children; }
                }
@@ -1942,8 +2013,12 @@ namespace Mono.CSharp {
                                LocalInfo vi = (LocalInfo) de.Value;
                                Type variable_type = vi.VariableType;
 
-                               if (variable_type == null)
+                               if (variable_type == null) {
+                                       if (vi.Type is VarExpr)
+                                               Report.Error (822, vi.Type.Location, "An implicitly typed local variable cannot be a constant");
+
                                        continue;
+                               }
 
                                Expression cv = (Expression) constants [name];
                                if (cv == null)
@@ -2020,48 +2095,38 @@ namespace Mono.CSharp {
                //
                public virtual void EmitMeta (EmitContext 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,
-                                             ec, scope_init);
-                       }
-
                        if (variables != null){
                                foreach (LocalInfo vi in variables.Values)
                                        vi.ResolveVariable (ec);
                        }
 
                        if (temporary_variables != null) {
-                               foreach (LocalInfo vi in temporary_variables)
-                                       vi.ResolveVariable (ec);
+                               for (int i = 0; i < temporary_variables.Count; i++)
+                                       ((LocalInfo)temporary_variables[i]).ResolveVariable(ec);
                        }
 
-                       if (children != null){
-                               foreach (Block b in children)
-                                       b.EmitMeta (ec);
+                       if (children != null) {
+                               for (int i = 0; i < children.Count; i++)
+                                       ((Block)children[i]).EmitMeta(ec);
                        }
                }
 
-               void UsageWarning (FlowBranching.UsageVector vector)
+               void UsageWarning ()
                {
-                       string name;
-
-                       if ((variables != null) && (Report.WarningLevel >= 3)) {
-                               foreach (DictionaryEntry de in variables){
-                                       LocalInfo vi = (LocalInfo) de.Value;
+                       if (variables == null || Report.WarningLevel < 3)
+                               return;
 
-                                       if (vi.Used)
-                                               continue;
+                       foreach (DictionaryEntry de in variables) {
+                               LocalInfo vi = (LocalInfo) de.Value;
 
-                                       name = (string) de.Key;
+                               if (!vi.Used) {
+                                       string name = (string) de.Key;
 
                                        // vi.VariableInfo can be null for 'catch' variables
-                                       if (vi.VariableInfo != null && vector.IsAssigned (vi.VariableInfo, true)){
+                                       if (vi.VariableInfo != null && vi.VariableInfo.IsEverAssigned)
                                                Report.Warning (219, 3, vi.Location, "The variable `{0}' is assigned but its value is never used", name);
-                                       } else {
+                                       else
                                                Report.Warning (168, 3, vi.Location, "The variable `{0}' is declared but never used", name);
-                                       }
                                }
                        }
                }
@@ -2085,10 +2150,12 @@ namespace Mono.CSharp {
                                body = ((Foreach) s).Statement;
                        else if (s is While)
                                body = ((While) s).Statement;
-                       else if (s is Using)
-                               body = ((Using) s).Statement;
                        else if (s is Fixed)
                                body = ((Fixed) s).Statement;
+                       else if (s is Using)
+                               body = ((Using) s).EmbeddedStatement;
+                       else if (s is UsingTemporary)
+                               body = ((UsingTemporary) s).Statement;
                        else
                                return;
 
@@ -2148,10 +2215,10 @@ namespace Mono.CSharp {
                                //
 
                                if (!s.Resolve (ec)) {
+                                       ok = false;
                                        if (ec.IsInProbingMode)
-                                               return false;
+                                               break;
 
-                                       ok = false;
                                        statements [ix] = EmptyStatement.Value;
                                        continue;
                                }
@@ -2159,46 +2226,37 @@ namespace Mono.CSharp {
                                if (unreachable && !(s is LabeledStatement) && !(s is Block))
                                        statements [ix] = EmptyStatement.Value;
 
-                               num_statements = ix + 1;
-
                                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);
-
-                       if (!ok)
-                               return false;
+                                     ec.CurrentBranching, statement_count);
 
                        while (ec.CurrentBranching is FlowBranchingLabeled)
                                ec.EndFlowBranching ();
 
-                       FlowBranching.UsageVector vector = ec.DoEndFlowBranching ();
+                       bool flow_unreachable = ec.EndFlowBranching ();
 
                        ec.CurrentBlock = prev_block;
 
+                       if (flow_unreachable)
+                               flags |= Flags.HasRet;
+
                        // 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 (this == Toplevel && !Toplevel.IsThisAssigned (ec) && !vector.IsUnreachable)
+                       if (this == Toplevel && !Toplevel.IsThisAssigned (ec) && !flow_unreachable)
                                ok = false;
 
                        if ((labels != null) && (Report.WarningLevel >= 2)) {
                                foreach (LabeledStatement label in labels.Values)
                                        if (!label.HasBeenReferenced)
-                                               Report.Warning (164, 2, label.loc,
-                                                               "This label has not been referenced");
+                                               Report.Warning (164, 2, label.loc, "This label has not been referenced");
                        }
 
-                       Report.Debug (4, "RESOLVE BLOCK DONE #2", StartLocation, vector);
-
-                       if (vector.IsUnreachable)
-                               flags |= Flags.HasRet;
-
-                       if (ok && (errors == Report.Errors)) {
-                               UsageWarning (vector);
-                       }
+                       if (ok && errors == Report.Errors)
+                               UsageWarning ();
 
                        return ok;
                }
@@ -2220,7 +2278,7 @@ namespace Mono.CSharp {
                
                protected override void DoEmit (EmitContext ec)
                {
-                       for (int ix = 0; ix < num_statements; ix++){
+                       for (int ix = 0; ix < statements.Count; ix++){
                                Statement s = (Statement) statements [ix];
                                s.Emit (ec);
                        }
@@ -2229,37 +2287,58 @@ namespace Mono.CSharp {
                public override void Emit (EmitContext ec)
                {
                        Block prev_block = ec.CurrentBlock;
-
                        ec.CurrentBlock = this;
 
-                       bool emit_debug_info = (CodeGen.SymbolWriter != null);
-                       bool is_lexical_block = this == Explicit && Parent != null;
+                       if (scope_initializers != null) {
+                               SymbolWriter.OpenCompilerGeneratedBlock (ec.ig);
 
-                       if (emit_debug_info) {
-                               if (is_lexical_block)
-                                       ec.BeginScope ();
+                               bool omit_debug_info = ec.OmitDebuggingInfo;
+                               ec.OmitDebuggingInfo = true;
+                               foreach (StatementExpression s in scope_initializers)
+                                       s.Emit (ec);
+                               ec.OmitDebuggingInfo = omit_debug_info;
+
+                               SymbolWriter.CloseCompilerGeneratedBlock (ec.ig);
                        }
+
                        ec.Mark (StartLocation, true);
-                       if (scope_init != null)
-                               scope_init.EmitStatement (ec);
                        DoEmit (ec);
-                       ec.Mark (EndLocation, true); 
-
-                       if (emit_debug_info) {
-                               if (is_lexical_block)
-                                       ec.EndScope ();
 
-                               if (variables != null) {
-                                       foreach (DictionaryEntry de in variables) {
-                                               string name = (string) de.Key;
-                                               LocalInfo vi = (LocalInfo) de.Value;
+                       ec.CurrentBlock = prev_block;
+               }
 
-                                               vi.EmitSymbolInfo (ec, name);
-                                       }
+               protected virtual void EmitSymbolInfo (EmitContext ec)
+               {
+                       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;
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       MutateVariables (storey);
+
+                       foreach (Statement s in statements)
+                               s.MutateHoistedGenericType (storey);
+               }
+
+               void MutateVariables (AnonymousMethodStorey storey)
+               {
+                       if (variables != null) {
+                               foreach (LocalInfo vi in variables.Values) {
+                                       vi.VariableType = storey.MutateType (vi.VariableType);
+                               }
+                       }
+
+                       if (temporary_variables != null) {
+                               foreach (LocalInfo vi in temporary_variables)
+                                       vi.VariableType = storey.MutateType (vi.VariableType);
+                       }
                }
 
                public override string ToString ()
@@ -2306,6 +2385,9 @@ namespace Mono.CSharp {
        }
 
        public class ExplicitBlock : Block {
+               HybridDictionary known_variables;
+               protected AnonymousMethodStorey am_storey;
+
                public ExplicitBlock (Block parent, Location start, Location end)
                        : this (parent, (Flags) 0, start, end)
                {
@@ -2317,8 +2399,6 @@ namespace Mono.CSharp {
                        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
@@ -2327,7 +2407,7 @@ namespace Mono.CSharp {
                internal void AddKnownVariable (string name, IKnownVariable info)
                {
                        if (known_variables == null)
-                               known_variables = new Hashtable ();
+                               known_variables = new HybridDictionary();
 
                        known_variables [name] = info;
 
@@ -2335,11 +2415,125 @@ namespace Mono.CSharp {
                                Parent.Explicit.AddKnownVariable (name, info);
                }
 
+               public AnonymousMethodStorey AnonymousMethodStorey {
+                       get { return am_storey; }
+               }
+
+               //
+               // Creates anonymous method storey in current block
+               //
+               public AnonymousMethodStorey CreateAnonymousMethodStorey (EmitContext ec)
+               {
+                       //
+                       // When referencing a variable in iterator storey from children anonymous method
+                       //
+                       if (Toplevel.am_storey is IteratorStorey) {
+                               ec.CurrentAnonymousMethod.AddStoreyReference (Toplevel.am_storey);
+                               return Toplevel.am_storey;
+                       }
+
+                       //
+                       // An iterator has only 1 storey block
+                       //
+                       if (ec.CurrentIterator != null)
+                           return ec.CurrentIterator.Storey;
+
+                       if (am_storey == null) {
+                               MemberBase mc = ec.ResolveContext as MemberBase;
+                               GenericMethod gm = mc == null ? null : mc.GenericMethod;
+
+                               //
+                               // Create anonymous method storey for this block
+                               //
+                               am_storey = new AnonymousMethodStorey (this, ec.TypeContainer, mc, gm, "AnonStorey");
+                       }
+
+                       //
+                       // Creates a link between this block and the anonymous method
+                       //
+                       // An anonymous method can reference variables from any outer block, but they are
+                       // hoisted in their own ExplicitBlock. When more than one block is referenced we
+                       // need to create another link between those variable storeys
+                       //
+                       ec.CurrentAnonymousMethod.AddStoreyReference (am_storey);
+                       return am_storey;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       if (am_storey != null)
+                               am_storey.EmitHoistedVariables (ec);
+
+                       bool emit_debug_info = SymbolWriter.HasSymbolWriter;
+                       bool is_lexical_block = Parent != null && !(am_storey is IteratorStorey);
+                       if (emit_debug_info && is_lexical_block)
+                               ec.BeginScope ();
+
+                       base.Emit (ec);
+
+                       if (emit_debug_info) {
+                               EmitSymbolInfo (ec);
+                               if (is_lexical_block)
+                                       ec.EndScope ();
+                       }
+               }
+
+               public override void EmitMeta (EmitContext ec)
+               {
+                       base.EmitMeta (ec);
+
+                       //
+                       // It has to be done when all storey references are resolved
+                       //
+                       if (am_storey != null && am_storey.HasHoistedVariables)
+                               am_storey.DefineMembers ();
+               }
+
+               protected override void EmitSymbolInfo (EmitContext ec)
+               {
+                       if (am_storey != null)
+                               SymbolWriter.DefineScopeVariable (am_storey.ID);
+
+                       base.EmitSymbolInfo (ec);
+               }
+
                internal IKnownVariable GetKnownVariable (string name)
                {
                        return known_variables == null ? null : (IKnownVariable) known_variables [name];
                }
 
+               public void PropagateStoreyReference (AnonymousMethodStorey s)
+               {
+                       if (Parent != null && am_storey != s) {
+                               if (am_storey != null)
+                                       am_storey.AddParentStoreyReference (s);
+
+                               Parent.Explicit.PropagateStoreyReference (s);
+                       }
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       bool ok = base.Resolve (ec);
+
+                       //
+                       // Define an anonymous method storey when this block has hoisted variables
+                       // otherwise the storey can be discarded
+                       //
+                       if (am_storey != null) {
+                               if (am_storey.HasHoistedVariables) {
+                                       am_storey.DefineType ();
+                                       am_storey.DefineMembers ();
+                                       am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey);
+                               } else {
+                                       am_storey.Undo ();
+                                       am_storey = null;
+                               }
+                       }
+
+                       return ok;
+               }
+
                protected override void CloneTo (CloneContext clonectx, Statement t)
                {
                        ExplicitBlock target = (ExplicitBlock) t;
@@ -2381,19 +2575,11 @@ namespace Mono.CSharp {
        public class ToplevelBlock : ExplicitBlock {
                GenericMethod generic;
                FlowBranchingToplevel top_level_branching;
-               AnonymousContainer anonymous_container;
-               RootScopeInfo root_scope;
                Parameters parameters;
                ToplevelParameterInfo[] parameter_info;
+               LocalInfo this_variable;
 
-               public bool HasVarargs {
-                       get { return (flags & Flags.HasVarargs) != 0; }
-                       set { flags |= Flags.HasVarargs; }
-               }
-
-               public bool IsIterator {
-                       get { return (flags & Flags.IsIterator) != 0; }
-               }
+               public HoistedVariable HoistedThisVariable;
 
                //
                // The parameters for the block.
@@ -2402,29 +2588,6 @@ 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; }
                }
@@ -2433,11 +2596,6 @@ namespace Mono.CSharp {
                        get { return Parent == null ? null : Parent.Toplevel; }
                }
 
-               public AnonymousContainer AnonymousContainer {
-                       get { return anonymous_container; }
-                       set { anonymous_container = value; }
-               }
-
                public ToplevelBlock (Block parent, Parameters parameters, Location start) :
                        this (parent, (Flags) 0, parameters, start)
                {
@@ -2454,7 +2612,7 @@ namespace Mono.CSharp {
                {
                }
 
-               public ToplevelBlock (Flags flags, Parameters parameters, Location start) :
+               ToplevelBlock (Flags flags, Parameters parameters, Location start) :
                        this (null, flags, parameters, start)
                {
                }
@@ -2558,64 +2716,38 @@ namespace Mono.CSharp {
                        return true;
                }
 
-               public RootScopeInfo CreateRootScope (TypeContainer host)
+               public override Expression CreateExpressionTree (EmitContext ec)
                {
-                       if (root_scope != null)
-                               return root_scope;
-
-                       if (Container == null)
-                               root_scope = new RootScopeInfo (
-                                       this, host, generic, StartLocation);
-
-                       if (scope_info != null)
-                               throw new InternalErrorException ();
-
-                       scope_info = root_scope;
-                       return root_scope;
+                       return ((Statement) statements [0]).CreateExpressionTree (ec);
                }
 
-               public void CreateIteratorHost (RootScopeInfo root)
+               //
+               // Reformats this block to be top-level iterator block
+               //
+               public IteratorStorey ChangeToIterator (Iterator iterator, ToplevelBlock source)
                {
-                       Report.Debug (64, "CREATE ITERATOR HOST", this, root, Parent, root_scope);
+                       // Create block with original statements
+                       ExplicitBlock iter_block = new ExplicitBlock (this, flags, StartLocation, EndLocation);
 
-                       if (Parent != null || root_scope != null)
-                               throw new InternalErrorException ();
+                       // TODO: Change to iter_block.statements = statements;
+                       foreach (Statement stmt in source.statements)
+                               iter_block.AddStatement (stmt);
+                       labels = source.labels;
+                       
+                       AddStatement (new IteratorStatement (iterator, iter_block));
 
-                       scope_info = root_scope = root;
-               }
+                       source.statements = new ArrayList (1);
+                       source.AddStatement (new Return (iterator, iterator.Location));
 
-               public RootScopeInfo RootScope {
-                       get {
-                               if (root_scope != null)
-                                       return root_scope;
-                               else if (Container != null)
-                                       return Container.RootScope;
-                               else
-                                       return null;
-                       }
+                       IteratorStorey iterator_storey = new IteratorStorey (iterator);
+                       source.am_storey = iterator_storey;
+                       return iterator_storey;
                }
 
                public FlowBranchingToplevel TopLevelBranching {
                        get { return top_level_branching; }
                }
 
-               //
-               // This is used if anonymous methods are used inside an iterator
-               // (see 2test-22.cs for an example).
-               //
-               // The AnonymousMethod is created while parsing - at a time when we don't
-               // know yet that we're inside an iterator, so it's `Container' is initially
-               // null.  Later on, when resolving the iterator, we need to move the
-               // anonymous method into that iterator.
-               //
-               public void ReParent (ToplevelBlock new_parent)
-               {
-                       if ((flags & Flags.VariablesInitialized) != 0)
-                               throw new InternalErrorException ("block has already been resolved");
-
-                       Parent = new_parent;
-               }
-
                //
                // Returns a `ParameterReference' for the given name, or null if there
                // is no such parameter
@@ -2637,29 +2769,6 @@ namespace Mono.CSharp {
                        return null;
                }
 
-               //
-               // Whether the parameter named `name' is local to this block, 
-               // or false, if the parameter belongs to an encompassing block.
-               //
-               public bool IsLocalParameter (string name)
-               {
-                       return Parameters.GetParameterByName (name) != null;
-               }
-               
-               //
-               // Whether the `name' is a parameter reference
-               //
-               public bool IsParameterReference (string name)
-               {
-                       for (ToplevelBlock t = this; t != null; t = t.Container) {
-                               if (t.IsLocalParameter (name))
-                                       return true;
-                       }
-                       return false;
-               }
-
-               LocalInfo this_variable = null;
-
                // <summary>
                //   Returns the "this" instance variable of this block.
                //   See AddThisVariable() for more information.
@@ -2668,7 +2777,6 @@ namespace Mono.CSharp {
                        get { return this_variable; }
                }
 
-
                // <summary>
                //   This is used by non-static `struct' constructors which do not have an
                //   initializer - in this case, the constructor must initialize all of the
@@ -2755,48 +2863,19 @@ namespace Mono.CSharp {
 
                public override void EmitMeta (EmitContext ec)
                {
-                       base.EmitMeta (ec);
-                       parameters.ResolveVariable (this);
-               }
-
-               public void MakeIterator (Iterator iterator)
-               {
-                       flags |= Flags.IsIterator;
-
-                       Block block = new ExplicitBlock (this, StartLocation, EndLocation);
-                       foreach (Statement stmt in statements)
-                               block.AddStatement (stmt);
-                       statements.Clear ();
-                       statements.Add (new MoveNextStatement (iterator, block));
-               }
-
-               protected class MoveNextStatement : Statement {
-                       Iterator iterator;
-                       Block block;
-
-                       public MoveNextStatement (Iterator iterator, Block block)
-                       {
-                               this.iterator = iterator;
-                               this.block = block;
-                               this.loc = iterator.Location;
-                       }
-
-                       public override bool Resolve (EmitContext ec)
-                       {
-                               return block.Resolve (ec);
-                       }
+                       parameters.ResolveVariable ();
 
-                       protected override void DoEmit (EmitContext ec)
-                       {
-                               iterator.EmitMoveNext (ec, block);
-                       }
+                       // Avoid declaring an IL variable for this_variable since it is not accessed
+                       // from the generated IL
+                       if (this_variable != null)
+                               Variables.Remove ("this");
+                       base.EmitMeta (ec);
                }
 
-               public override string ToString ()
+               public override void Emit (EmitContext ec)
                {
-                       return String.Format ("{0} ({1}:{2}{3}:{4})", GetType (), ID, StartLocation,
-                                             root_scope, anonymous_container != null ?
-                                             anonymous_container.Scope : null);
+                       base.Emit (ec);
+                       ec.Mark (EndLocation, true);
                }
        }
        
@@ -2877,7 +2956,7 @@ namespace Mono.CSharp {
                                converted = NullStringCase;
                                return true;
                        }
-
+                       
                        c = c.ImplicitConversionRequired (required_type, loc);
                        if (c == null)
                                return false;
@@ -2886,19 +2965,19 @@ namespace Mono.CSharp {
                        return true;
                }
 
-               public void Erorr_AlreadyOccurs (Type switchType, SwitchLabel collisionWith)
+               public void Error_AlreadyOccurs (Type switch_type, SwitchLabel collision_with)
                {
                        string label;
                        if (converted == null)
                                label = "default";
                        else if (converted == NullStringCase)
                                label = "null";
-                       else if (TypeManager.IsEnumType (switchType)) 
-                               label = TypeManager.CSharpEnumValue (switchType, converted);
+                       else if (TypeManager.IsEnumType (switch_type)) 
+                               label = TypeManager.CSharpEnumValue (switch_type, converted);
                        else
                                label = converted.ToString ();
                        
-                       Report.SymbolRelatedToPreviousError (collisionWith.loc, null);
+                       Report.SymbolRelatedToPreviousError (collision_with.loc, null);
                        Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label);
                }
 
@@ -3002,7 +3081,7 @@ namespace Mono.CSharp {
                //
                Expression SwitchGoverningType (EmitContext ec, Expression expr)
                {
-                       Type t = TypeManager.DropGenericTypeArguments (expr.Type);
+                       Type t = expr.Type;
 
                        if (t == TypeManager.byte_type ||
                            t == TypeManager.sbyte_type ||
@@ -3015,7 +3094,7 @@ namespace Mono.CSharp {
                            t == TypeManager.char_type ||
                            t == TypeManager.string_type ||
                            t == TypeManager.bool_type ||
-                           t.IsSubclassOf (TypeManager.enum_type))
+                           TypeManager.IsEnumType (t))
                                return expr;
 
                        if (allowed_types == null){
@@ -3086,7 +3165,7 @@ namespace Mono.CSharp {
                                foreach (SwitchLabel sl in ss.Labels){
                                        if (sl.Label == null){
                                                if (default_section != null){
-                                                       sl.Erorr_AlreadyOccurs (SwitchType, (SwitchLabel)default_section.Labels [0]);
+                                                       sl.Error_AlreadyOccurs (SwitchType, (SwitchLabel)default_section.Labels [0]);
                                                        error = true;
                                                }
                                                default_section = ss;
@@ -3102,7 +3181,7 @@ namespace Mono.CSharp {
                                        try {
                                                Elements.Add (key, sl);
                                        } catch (ArgumentException) {
-                                               sl.Erorr_AlreadyOccurs (SwitchType, (SwitchLabel)Elements [key]);
+                                               sl.Error_AlreadyOccurs (SwitchType, (SwitchLabel)Elements [key]);
                                                error = true;
                                        }
                                }
@@ -3161,22 +3240,22 @@ namespace Mono.CSharp {
                // structure used to hold blocks of keys while calculating table switch
                class KeyBlock : IComparable
                {
-                       public KeyBlock (long _nFirst)
+                       public KeyBlock (long _first)
                        {
-                               nFirst = nLast = _nFirst;
+                               first = last = _first;
                        }
-                       public long nFirst;
-                       public long nLast;
-                       public ArrayList rgKeys = null;
+                       public long first;
+                       public long last;
+                       public ArrayList element_keys = null;
                        // how many items are in the bucket
                        public int Size = 1;
                        public int Length
                        {
-                               get { return (int) (nLast - nFirst + 1); }
+                               get { return (int) (last - first + 1); }
                        }
-                       public static long TotalLength (KeyBlock kbFirst, KeyBlock kbLast)
+                       public static long TotalLength (KeyBlock kb_first, KeyBlock kb_last)
                        {
-                               return kbLast.nLast - kbFirst.nFirst + 1;
+                               return kb_last.last - kb_first.first + 1;
                        }
                        public int CompareTo (object obj)
                        {
@@ -3184,7 +3263,7 @@ namespace Mono.CSharp {
                                int nLength = Length;
                                int nLengthOther = kb.Length;
                                if (nLengthOther == nLength)
-                                       return (int) (kb.nFirst - nFirst);
+                                       return (int) (kb.first - first);
                                return nLength - nLengthOther;
                        }
                }
@@ -3201,89 +3280,89 @@ namespace Mono.CSharp {
                /// <returns></returns>
                void TableSwitchEmit (EmitContext ec, LocalBuilder val)
                {
-                       int cElements = Elements.Count;
-                       object [] rgKeys = new object [cElements];
-                       Elements.Keys.CopyTo (rgKeys, 0);
-                       Array.Sort (rgKeys);
+                       int element_count = Elements.Count;
+                       object [] element_keys = new object [element_count];
+                       Elements.Keys.CopyTo (element_keys, 0);
+                       Array.Sort (element_keys);
 
                        // initialize the block list with one element per key
-                       ArrayList rgKeyBlocks = new ArrayList ();
-                       foreach (object key in rgKeys)
-                               rgKeyBlocks.Add (new KeyBlock (System.Convert.ToInt64 (key)));
+                       ArrayList key_blocks = new ArrayList ();
+                       foreach (object key in element_keys)
+                               key_blocks.Add (new KeyBlock (System.Convert.ToInt64 (key)));
 
-                       KeyBlock kbCurr;
+                       KeyBlock current_kb;
                        // iteratively merge the blocks while they are at least half full
                        // there's probably a really cool way to do this with a tree...
-                       while (rgKeyBlocks.Count > 1)
+                       while (key_blocks.Count > 1)
                        {
-                               ArrayList rgKeyBlocksNew = new ArrayList ();
-                               kbCurr = (KeyBlock) rgKeyBlocks [0];
-                               for (int ikb = 1; ikb < rgKeyBlocks.Count; ikb++)
+                               ArrayList key_blocks_new = new ArrayList ();
+                               current_kb = (KeyBlock) key_blocks [0];
+                               for (int ikb = 1; ikb < key_blocks.Count; ikb++)
                                {
-                                       KeyBlock kb = (KeyBlock) rgKeyBlocks [ikb];
-                                       if ((kbCurr.Size + kb.Size) * 2 >=  KeyBlock.TotalLength (kbCurr, kb))
+                                       KeyBlock kb = (KeyBlock) key_blocks [ikb];
+                                       if ((current_kb.Size + kb.Size) * 2 >=  KeyBlock.TotalLength (current_kb, kb))
                                        {
                                                // merge blocks
-                                               kbCurr.nLast = kb.nLast;
-                                               kbCurr.Size += kb.Size;
+                                               current_kb.last = kb.last;
+                                               current_kb.Size += kb.Size;
                                        }
                                        else
                                        {
                                                // start a new block
-                                               rgKeyBlocksNew.Add (kbCurr);
-                                               kbCurr = kb;
+                                               key_blocks_new.Add (current_kb);
+                                               current_kb = kb;
                                        }
                                }
-                               rgKeyBlocksNew.Add (kbCurr);
-                               if (rgKeyBlocks.Count == rgKeyBlocksNew.Count)
+                               key_blocks_new.Add (current_kb);
+                               if (key_blocks.Count == key_blocks_new.Count)
                                        break;
-                               rgKeyBlocks = rgKeyBlocksNew;
+                               key_blocks = key_blocks_new;
                        }
 
                        // initialize the key lists
-                       foreach (KeyBlock kb in rgKeyBlocks)
-                               kb.rgKeys = new ArrayList ();
+                       foreach (KeyBlock kb in key_blocks)
+                               kb.element_keys = new ArrayList ();
 
                        // fill the key lists
                        int iBlockCurr = 0;
-                       if (rgKeyBlocks.Count > 0) {
-                               kbCurr = (KeyBlock) rgKeyBlocks [0];
-                               foreach (object key in rgKeys)
+                       if (key_blocks.Count > 0) {
+                               current_kb = (KeyBlock) key_blocks [0];
+                               foreach (object key in element_keys)
                                {
-                                       bool fNextBlock = (key is UInt64) ? (ulong) key > (ulong) kbCurr.nLast :
-                                               System.Convert.ToInt64 (key) > kbCurr.nLast;
-                                       if (fNextBlock)
-                                               kbCurr = (KeyBlock) rgKeyBlocks [++iBlockCurr];
-                                       kbCurr.rgKeys.Add (key);
+                                       bool next_block = (key is UInt64) ? (ulong) key > (ulong) current_kb.last :
+                                               System.Convert.ToInt64 (key) > current_kb.last;
+                                       if (next_block)
+                                               current_kb = (KeyBlock) key_blocks [++iBlockCurr];
+                                       current_kb.element_keys.Add (key);
                                }
                        }
 
                        // sort the blocks so we can tackle the largest ones first
-                       rgKeyBlocks.Sort ();
+                       key_blocks.Sort ();
 
                        // okay now we can start...
                        ILGenerator ig = ec.ig;
-                       Label lblEnd = ig.DefineLabel ();       // at the end ;-)
-                       Label lblDefault = ig.DefineLabel ();
+                       Label lbl_end = ig.DefineLabel ();      // at the end ;-)
+                       Label lbl_default = ig.DefineLabel ();
 
-                       Type typeKeys = null;
-                       if (rgKeys.Length > 0)
-                               typeKeys = rgKeys [0].GetType ();       // used for conversions
+                       Type type_keys = null;
+                       if (element_keys.Length > 0)
+                               type_keys = element_keys [0].GetType ();        // used for conversions
 
                        Type compare_type;
                        
                        if (TypeManager.IsEnumType (SwitchType))
-                               compare_type = TypeManager.EnumToUnderlying (SwitchType);
+                               compare_type = TypeManager.GetEnumUnderlyingType (SwitchType);
                        else
                                compare_type = SwitchType;
                        
-                       for (int iBlock = rgKeyBlocks.Count - 1; iBlock >= 0; --iBlock)
+                       for (int iBlock = key_blocks.Count - 1; iBlock >= 0; --iBlock)
                        {
-                               KeyBlock kb = ((KeyBlock) rgKeyBlocks [iBlock]);
-                               lblDefault = (iBlock == 0) ? DefaultTarget : ig.DefineLabel ();
+                               KeyBlock kb = ((KeyBlock) key_blocks [iBlock]);
+                               lbl_default = (iBlock == 0) ? DefaultTarget : ig.DefineLabel ();
                                if (kb.Length <= 2)
                                {
-                                       foreach (object key in kb.rgKeys)
+                                       foreach (object key in kb.element_keys)
                                        {
                                                ig.Emit (OpCodes.Ldloc, val);
                                                EmitObjectInteger (ig, key);
@@ -3302,17 +3381,17 @@ namespace Mono.CSharp {
 
                                                // check block range (could be > 2^31)
                                                ig.Emit (OpCodes.Ldloc, val);
-                                               EmitObjectInteger (ig, System.Convert.ChangeType (kb.nFirst, typeKeys));
-                                               ig.Emit (OpCodes.Blt, lblDefault);
+                                               EmitObjectInteger (ig, System.Convert.ChangeType (kb.first, type_keys));
+                                               ig.Emit (OpCodes.Blt, lbl_default);
                                                ig.Emit (OpCodes.Ldloc, val);
-                                               EmitObjectInteger (ig, System.Convert.ChangeType (kb.nLast, typeKeys));
-                                               ig.Emit (OpCodes.Bgt, lblDefault);
+                                               EmitObjectInteger (ig, System.Convert.ChangeType (kb.last, type_keys));
+                                               ig.Emit (OpCodes.Bgt, lbl_default);
 
                                                // normalize range
                                                ig.Emit (OpCodes.Ldloc, val);
-                                               if (kb.nFirst != 0)
+                                               if (kb.first != 0)
                                                {
-                                                       EmitObjectInteger (ig, System.Convert.ChangeType (kb.nFirst, typeKeys));
+                                                       EmitObjectInteger (ig, System.Convert.ChangeType (kb.first, type_keys));
                                                        ig.Emit (OpCodes.Sub);
                                                }
                                                ig.Emit (OpCodes.Conv_I4);      // assumes < 2^31 labels!
@@ -3321,15 +3400,15 @@ namespace Mono.CSharp {
                                        {
                                                // normalize range
                                                ig.Emit (OpCodes.Ldloc, val);
-                                               int nFirst = (int) kb.nFirst;
-                                               if (nFirst > 0)
+                                               int first = (int) kb.first;
+                                               if (first > 0)
                                                {
-                                                       IntConstant.EmitInt (ig, nFirst);
+                                                       IntConstant.EmitInt (ig, first);
                                                        ig.Emit (OpCodes.Sub);
                                                }
-                                               else if (nFirst < 0)
+                                               else if (first < 0)
                                                {
-                                                       IntConstant.EmitInt (ig, -nFirst);
+                                                       IntConstant.EmitInt (ig, -first);
                                                        ig.Emit (OpCodes.Add);
                                                }
                                        }
@@ -3337,26 +3416,26 @@ namespace Mono.CSharp {
                                        // first, build the list of labels for the switch
                                        int iKey = 0;
                                        int cJumps = kb.Length;
-                                       Label [] rgLabels = new Label [cJumps];
+                                       Label [] switch_labels = new Label [cJumps];
                                        for (int iJump = 0; iJump < cJumps; iJump++)
                                        {
-                                               object key = kb.rgKeys [iKey];
-                                               if (System.Convert.ToInt64 (key) == kb.nFirst + iJump)
+                                               object key = kb.element_keys [iKey];
+                                               if (System.Convert.ToInt64 (key) == kb.first + iJump)
                                                {
                                                        SwitchLabel sl = (SwitchLabel) Elements [key];
-                                                       rgLabels [iJump] = sl.GetILLabel (ec);
+                                                       switch_labels [iJump] = sl.GetILLabel (ec);
                                                        iKey++;
                                                }
                                                else
-                                                       rgLabels [iJump] = lblDefault;
+                                                       switch_labels [iJump] = lbl_default;
                                        }
                                        // emit the switch opcode
-                                       ig.Emit (OpCodes.Switch, rgLabels);
+                                       ig.Emit (OpCodes.Switch, switch_labels);
                                }
 
                                // mark the default for this block
                                if (iBlock != 0)
-                                       ig.MarkLabel (lblDefault);
+                                       ig.MarkLabel (lbl_default);
                        }
 
                        // TODO: find the default case and emit it here,
@@ -3364,16 +3443,16 @@ namespace Mono.CSharp {
                        //       make sure to mark other labels in the default section
 
                        // the last default just goes to the end
-                       ig.Emit (OpCodes.Br, lblDefault);
+                       ig.Emit (OpCodes.Br, lbl_default);
 
                        // now emit the code for the sections
-                       bool fFoundDefault = false;
-                       bool fFoundNull = false;
+                       bool found_default = false;
+                       bool found_null = false;
                        foreach (SwitchSection ss in Sections)
                        {
                                foreach (SwitchLabel sl in ss.Labels)
                                        if (sl.Converted == SwitchLabel.NullStringCase)
-                                               fFoundNull = true;
+                                               found_null = true;
                        }
 
                        foreach (SwitchSection ss in Sections)
@@ -3385,23 +3464,23 @@ namespace Mono.CSharp {
                                        if (sl.Converted == SwitchLabel.NullStringCase)
                                                ig.MarkLabel (null_target);
                                        else if (sl.Label == null) {
-                                               ig.MarkLabel (lblDefault);
-                                               fFoundDefault = true;
-                                               if (!fFoundNull)
+                                               ig.MarkLabel (lbl_default);
+                                               found_default = true;
+                                               if (!found_null)
                                                        ig.MarkLabel (null_target);
                                        }
                                }
                                ss.Block.Emit (ec);
                        }
                        
-                       if (!fFoundDefault) {
-                               ig.MarkLabel (lblDefault);
-                               if (HaveUnwrap && !fFoundNull) {
+                       if (!found_default) {
+                               ig.MarkLabel (lbl_default);
+                               if (HaveUnwrap && !found_null) {
                                        ig.MarkLabel (null_target);
                                }
                        }
                        
-                       ig.MarkLabel (lblEnd);
+                       ig.MarkLabel (lbl_end);
                }
                //
                // This simple emit switch works, but does not take advantage of the
@@ -3516,6 +3595,12 @@ namespace Mono.CSharp {
                        return null;
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       foreach (SwitchSection ss in Sections)
+                               ss.Block.MutateHoistedGenericType (storey);
+               }
+
                public override bool Resolve (EmitContext ec)
                {
                        Expr = Expr.Resolve (ec);
@@ -3543,7 +3628,7 @@ namespace Mono.CSharp {
                        SwitchType = new_expr.Type;
 
                        if (RootContext.Version == LanguageVersion.ISO_1 && SwitchType == TypeManager.bool_type) {
-                               Report.FeatureIsNotISO1 (loc, "switch expression of boolean type");
+                               Report.FeatureIsNotAvailable (loc, "switch expression of boolean type");
                                return false;
                        }
 
@@ -3571,6 +3656,7 @@ namespace Mono.CSharp {
                        }
 
                        bool first = true;
+                       bool ok = true;
                        foreach (SwitchSection ss in Sections){
                                if (!first)
                                        ec.CurrentBranching.CreateSibling (
@@ -3583,11 +3669,12 @@ namespace Mono.CSharp {
                                        // one single section - mark all the others as
                                        // unreachable.
                                        ec.CurrentBranching.CurrentUsageVector.Goto ();
-                                       if (!ss.Block.ResolveUnreachable (ec, true))
-                                               return false;
+                                       if (!ss.Block.ResolveUnreachable (ec, true)) {
+                                               ok = false;
+                                       }
                                } else {
                                        if (!ss.Block.Resolve (ec))
-                                               return false;
+                                               ok = false;
                                }
                        }
 
@@ -3600,7 +3687,12 @@ namespace Mono.CSharp {
 
                        Report.Debug (1, "END OF SWITCH BLOCK", loc, ec.CurrentBranching);
 
-                       return true;
+                       if (TypeManager.string_isinterned_string == null) {
+                               TypeManager.string_isinterned_string = TypeManager.GetPredefinedMethod (TypeManager.string_type,
+                                       "IsInterned", loc, TypeManager.string_type);
+                       }
+
+                       return ok;
                }
                
                protected override void DoEmit (EmitContext ec)
@@ -3667,27 +3759,184 @@ namespace Mono.CSharp {
                }
        }
 
-       public abstract class ExceptionStatement : Statement
+       // A place where execution can restart in an iterator
+       public abstract class ResumableStatement : Statement
+       {
+               bool prepared;
+               protected Label resume_point;
+
+               public Label PrepareForEmit (EmitContext ec)
+               {
+                       if (!prepared) {
+                               prepared = true;
+                               resume_point = ec.ig.DefineLabel ();
+                       }
+                       return resume_point;
+               }
+
+               public virtual Label PrepareForDispose (EmitContext ec, Label end)
+               {
+                       return end;
+               }
+               public virtual void EmitForDispose (EmitContext ec, Iterator iterator, Label end, bool have_dispatcher)
+               {
+               }
+       }
+
+       // Base class for statements that are implemented in terms of try...finally
+       public abstract class ExceptionStatement : ResumableStatement
        {
-               public abstract void EmitFinally (EmitContext ec);
+               bool code_follows;
+
+               protected abstract void EmitPreTryBody (EmitContext ec);
+               protected abstract void EmitTryBody (EmitContext ec);
+               protected abstract void EmitFinallyBody (EmitContext ec);
+
+               protected sealed override void DoEmit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+
+                       EmitPreTryBody (ec);
+
+                       if (resume_points != null) {
+                               IntConstant.EmitInt (ig, (int) Iterator.State.Running);
+                               ig.Emit (OpCodes.Stloc, ec.CurrentIterator.CurrentPC);
+                       }
 
-               protected bool emit_finally = true;
-               ArrayList parent_vectors;
+                       ig.BeginExceptionBlock ();
 
-               protected void DoEmitFinally (EmitContext ec)
+                       if (resume_points != null) {
+                               ig.MarkLabel (resume_point);
+
+                               // For normal control flow, we want to fall-through the Switch
+                               // So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above
+                               ig.Emit (OpCodes.Ldloc, ec.CurrentIterator.CurrentPC);
+                               IntConstant.EmitInt (ig, first_resume_pc);
+                               ig.Emit (OpCodes.Sub);
+
+                               Label [] labels = new Label [resume_points.Count];
+                               for (int i = 0; i < resume_points.Count; ++i)
+                                       labels [i] = ((ResumableStatement) resume_points [i]).PrepareForEmit (ec);
+                               ig.Emit (OpCodes.Switch, labels);
+                       }
+
+                       EmitTryBody (ec);
+
+                       ig.BeginFinallyBlock ();
+
+                       Label start_finally = ec.ig.DefineLabel ();
+                       if (resume_points != null) {
+                               ig.Emit (OpCodes.Ldloc, ec.CurrentIterator.SkipFinally);
+                               ig.Emit (OpCodes.Brfalse_S, start_finally);
+                               ig.Emit (OpCodes.Endfinally);
+                       }
+
+                       ig.MarkLabel (start_finally);
+                       EmitFinallyBody (ec);
+
+                       ig.EndExceptionBlock ();
+               }
+
+               public void SomeCodeFollows ()
+               {
+                       code_follows = true;
+               }
+
+               protected void ResolveReachability (EmitContext ec)
+               {
+                       // System.Reflection.Emit automatically emits a 'leave' at the end of a try clause
+                       // So, ensure there's some IL code after this statement.
+                       if (!code_follows && resume_points == null && ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
+                               ec.NeedReturnLabel ();
+
+               }
+
+               ArrayList resume_points;
+               int first_resume_pc;
+               public void AddResumePoint (ResumableStatement stmt, Location loc, int pc)
+               {
+                       if (resume_points == null) {
+                               resume_points = new ArrayList ();
+                               first_resume_pc = pc;
+                       }
+
+                       if (pc != first_resume_pc + resume_points.Count)
+                               throw new InternalErrorException ("missed an intervening AddResumePoint?");
+
+                       resume_points.Add (stmt);
+               }
+
+               Label dispose_try_block;
+               bool prepared_for_dispose, emitted_dispose;
+               public override Label PrepareForDispose (EmitContext ec, Label end)
                {
-                       if (emit_finally)
-                               ec.ig.BeginFinallyBlock ();
-                       else if (ec.InIterator)
-                               ec.CurrentIterator.MarkFinally (ec, parent_vectors);
-                       EmitFinally (ec);
+                       if (!prepared_for_dispose) {
+                               prepared_for_dispose = true;
+                               dispose_try_block = ec.ig.DefineLabel ();
+                       }
+                       return dispose_try_block;
                }
 
-               protected void ResolveFinally (FlowBranchingException branching)
+               public override void EmitForDispose (EmitContext ec, Iterator iterator, Label end, bool have_dispatcher)
                {
-                       emit_finally = branching.EmitFinally;
-                       if (!emit_finally)
-                               branching.Parent.StealFinallyClauses (ref parent_vectors);
+                       if (emitted_dispose)
+                               return;
+
+                       emitted_dispose = true;
+
+                       ILGenerator ig = ec.ig;
+
+                       Label end_of_try = ig.DefineLabel ();
+
+                       // Ensure that the only way we can get into this code is through a dispatcher
+                       if (have_dispatcher)
+                               ig.Emit (OpCodes.Br, end);
+
+                       ig.BeginExceptionBlock ();
+
+                       ig.MarkLabel (dispose_try_block);
+
+                       Label [] labels = null;
+                       for (int i = 0; i < resume_points.Count; ++i) {
+                               ResumableStatement s = (ResumableStatement) resume_points [i];
+                               Label ret = s.PrepareForDispose (ec, end_of_try);
+                               if (ret.Equals (end_of_try) && labels == null)
+                                       continue;
+                               if (labels == null) {
+                                       labels = new Label [resume_points.Count];
+                                       for (int j = 0; j < i; ++j)
+                                               labels [j] = end_of_try;
+                               }
+                               labels [i] = ret;
+                       }
+
+                       if (labels != null) {
+                               int j;
+                               for (j = 1; j < labels.Length; ++j)
+                                       if (!labels [0].Equals (labels [j]))
+                                               break;
+                               bool emit_dispatcher = j < labels.Length;
+
+                               if (emit_dispatcher) {
+                                       //SymbolWriter.StartIteratorDispatcher (ec.ig);
+                                       ig.Emit (OpCodes.Ldloc, iterator.CurrentPC);
+                                       IntConstant.EmitInt (ig, first_resume_pc);
+                                       ig.Emit (OpCodes.Sub);
+                                       ig.Emit (OpCodes.Switch, labels);
+                                       //SymbolWriter.EndIteratorDispatcher (ec.ig);
+                               }
+
+                               foreach (ResumableStatement s in resume_points)
+                                       s.EmitForDispose (ec, iterator, end_of_try, emit_dispatcher);
+                       }
+
+                       ig.MarkLabel (end_of_try);
+
+                       ig.BeginFinallyBlock ();
+
+                       EmitFinallyBody (ec);
+
+                       ig.EndExceptionBlock ();
                }
        }
 
@@ -3716,16 +3965,11 @@ namespace Mono.CSharp {
                                return false;
                        }
 
-                       FlowBranchingException branching = ec.StartFlowBranching (this);
+                       ec.StartFlowBranching (this);
                        bool ok = Statement.Resolve (ec);
-
-                       ResolveFinally (branching);
-
                        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 ();
+                       ResolveReachability (ec);
 
                        // Avoid creating libraries that reference the internal
                        // mcs NullType:
@@ -3735,34 +3979,44 @@ namespace Mono.CSharp {
                        
                        temp = new TemporaryVariable (t, loc);
                        temp.Resolve (ec);
+
+                       if (TypeManager.void_monitor_enter_object == null || TypeManager.void_monitor_exit_object == null) {
+                               Type monitor_type = TypeManager.CoreLookupType ("System.Threading", "Monitor", Kind.Class, true);
+                               TypeManager.void_monitor_enter_object = TypeManager.GetPredefinedMethod (
+                                       monitor_type, "Enter", loc, TypeManager.object_type);
+                               TypeManager.void_monitor_exit_object = TypeManager.GetPredefinedMethod (
+                                       monitor_type, "Exit", loc, TypeManager.object_type);
+                       }
                        
                        return ok;
                }
                
-               protected override void DoEmit (EmitContext ec)
+               protected override void EmitPreTryBody (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
 
-                       temp.Store (ec, expr);
+                       temp.EmitAssign (ec, expr);
                        temp.Emit (ec);
                        ig.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
+               }
 
-                       // try
-                       if (emit_finally)
-                               ig.BeginExceptionBlock ();
+               protected override void EmitTryBody (EmitContext ec)
+               {
                        Statement.Emit (ec);
-                       
-                       // finally
-                       DoEmitFinally (ec);
-                       if (emit_finally)
-                               ig.EndExceptionBlock ();
                }
 
-               public override void EmitFinally (EmitContext ec)
+               protected override void EmitFinallyBody (EmitContext ec)
                {
                        temp.Emit (ec);
                        ec.ig.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object);
                }
+
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       expr.MutateHoistedGenericType (storey);
+                       temp.MutateHoistedGenericType (storey);
+                       Statement.MutateHoistedGenericType (storey);
+               }
                
                protected override void CloneTo (CloneContext clonectx, Statement t)
                {
@@ -3794,6 +4048,11 @@ namespace Mono.CSharp {
                                Block.Emit (ec);
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       Block.MutateHoistedGenericType (storey);
+               }
+
                protected override void CloneTo (CloneContext clonectx, Statement t)
                {
                        Unchecked target = (Unchecked) t;
@@ -3823,6 +4082,11 @@ namespace Mono.CSharp {
                                Block.Emit (ec);
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       Block.MutateHoistedGenericType (storey);
+               }
+
                protected override void CloneTo (CloneContext clonectx, Statement t)
                {
                        Checked target = (Checked) t;
@@ -3851,6 +4115,12 @@ namespace Mono.CSharp {
                        using (ec.With (EmitContext.Flags.InUnsafe, true))
                                Block.Emit (ec);
                }
+
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       Block.MutateHoistedGenericType (storey);
+               }
+
                protected override void CloneTo (CloneContext clonectx, Statement t)
                {
                        Unsafe target = (Unsafe) t;
@@ -3896,18 +4166,60 @@ namespace Mono.CSharp {
                                // Store pointer in pinned location
                                //
                                converted.Emit (ec);
-                               vi.Variable.EmitAssign (ec);
+                               vi.EmitAssign (ec);
                        }
 
                        public override void EmitExit (EmitContext ec)
                        {
                                ec.ig.Emit (OpCodes.Ldc_I4_0);
                                ec.ig.Emit (OpCodes.Conv_U);
-                               vi.Variable.EmitAssign (ec);
+                               vi.EmitAssign (ec);
                        }
                }
 
                class StringEmitter : Emitter {
+                       class StringPtr : Expression
+                       {
+                               LocalBuilder b;
+
+                               public StringPtr (LocalBuilder b, Location l)
+                               {
+                                       this.b = b;
+                                       eclass = ExprClass.Value;
+                                       type = TypeManager.char_ptr_type;
+                                       loc = l;
+                               }
+
+                               public override Expression CreateExpressionTree (EmitContext ec)
+                               {
+                                       throw new NotSupportedException ("ET");
+                               }
+
+                               public override Expression DoResolve (EmitContext ec)
+                               {
+                                       // This should never be invoked, we are born in fully
+                                       // initialized state.
+
+                                       return this;
+                               }
+
+                               public override void Emit (EmitContext ec)
+                               {
+                                       if (TypeManager.int_get_offset_to_string_data == null) {
+                                               // TODO: Move to resolve !!
+                                               TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedMethod (
+                                                       TypeManager.runtime_helpers_type, "get_OffsetToStringData", loc, Type.EmptyTypes);
+                                       }
+
+                                       ILGenerator ig = ec.ig;
+
+                                       ig.Emit (OpCodes.Ldloc, b);
+                                       ig.Emit (OpCodes.Conv_I);
+                                       ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
+                                       ig.Emit (OpCodes.Add);
+                               }
+                       }
+
                        LocalBuilder pinned_string;
                        Location loc;
 
@@ -3933,7 +4245,7 @@ namespace Mono.CSharp {
                                        return;
 
                                converted.Emit (ec);
-                               vi.Variable.EmitAssign (ec);
+                               vi.EmitAssign (ec);
                        }
 
                        public override void EmitExit (EmitContext ec)
@@ -3962,9 +4274,13 @@ namespace Mono.CSharp {
                                return false;
                        }
                        
-                       TypeExpr texpr = type.ResolveAsTypeTerminal (ec, false);
-                       if (texpr == null)
+                       TypeExpr texpr = type.ResolveAsContextualType (ec, false);
+                       if (texpr == null) {
+                               if (type is VarExpr)
+                                       Report.Error (821, type.Location, "A fixed statement cannot use an implicitly typed local variable");
+
                                return false;
+                       }
 
                        expr_type = texpr.Type;
 
@@ -4064,6 +4380,17 @@ namespace Mono.CSharp {
                                                ec, array_ptr, vi.VariableType, loc);
                                        if (converted == null)
                                                return false;
+                                       
+                                       //
+                                       // fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0])
+                                       //
+                                       converted = new Conditional (new Binary (Binary.Operator.LogicalOr,
+                                               new Binary (Binary.Operator.Equality, e, new NullLiteral (loc)),
+                                               new Binary (Binary.Operator.Equality, new MemberAccess (e, "Length"), new IntConstant (0, loc))),
+                                                       NullPointer.Null,
+                                                       converted);
+
+                                       converted = converted.Resolve (ec);                                     
 
                                        data [i] = new ExpressionEmitter (converted, vi);
                                        i++;
@@ -4128,14 +4455,26 @@ namespace Mono.CSharp {
                        }
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       // Fixed statement cannot be used inside anonymous methods or lambdas
+                       throw new NotSupportedException ();
+               }
+
                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.declarators = new ArrayList (declarators.Count);
+                       foreach (Pair p in declarators) {
+                               LocalInfo vi = (LocalInfo) p.First;
+                               Expression e = (Expression) p.Second;
+
+                               target.declarators.Add (
+                                       new Pair (clonectx.LookupVariable (vi), e.Clone (clonectx)));                           
+                       }
+                       
                        target.statement = statement.Clone (clonectx);
                }
        }
@@ -4169,7 +4508,7 @@ namespace Mono.CSharp {
                        }
                }
 
-               protected override void DoEmit(EmitContext ec)
+               protected override void DoEmit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
 
@@ -4182,19 +4521,21 @@ namespace Mono.CSharp {
                                VarBlock.Emit (ec);
 
                        if (Name != null) {
-                               LocalInfo vi = Block.GetLocalInfo (Name);
-                               if (vi == null)
-                                       throw new Exception ("Variable does not exist in this block");
-
-                               if (vi.Variable.NeedsTemporary) {
-                                       LocalBuilder e = ig.DeclareLocal (vi.VariableType);
-                                       ig.Emit (OpCodes.Stloc, e);
+                               // TODO: Move to resolve
+                               LocalVariableReference lvr = new LocalVariableReference (Block, Name, loc);
+                               lvr.Resolve (ec);
+
+                               Expression source;
+                               if (lvr.IsHoisted) {
+                                       LocalTemporary lt = new LocalTemporary (lvr.Type);
+                                       lt.Store (ec);
+                                       source = lt;
+                               } else {
+                                       // Variable is at the top of the stack
+                                       source = EmptyExpression.Null;
+                               }
 
-                                       vi.Variable.EmitInstance (ec);
-                                       ig.Emit (OpCodes.Ldloc, e);
-                                       vi.Variable.EmitAssign (ec);
-                               } else
-                                       vi.Variable.EmitAssign (ec);
+                               lvr.EmitAssign (ec, source, false, false);
                        } else
                                ig.Emit (OpCodes.Pop);
 
@@ -4211,7 +4552,7 @@ namespace Mono.CSharp {
 
                                        type = te.Type;
 
-                                       if (type != TypeManager.exception_type && !type.IsSubclassOf (TypeManager.exception_type)){
+                                       if (type != TypeManager.exception_type && !TypeManager.IsSubclassOf (type, TypeManager.exception_type)){
                                                Error (155, "The type caught or thrown must be derived from System.Exception");
                                                return false;
                                        }
@@ -4230,6 +4571,15 @@ namespace Mono.CSharp {
                        }
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       if (type != null)
+                               type = storey.MutateType (type);
+                       if (VarBlock != null)
+                               VarBlock.MutateHoistedGenericType (storey);
+                       Block.MutateHoistedGenericType (storey);
+               }
+
                protected override void CloneTo (CloneContext clonectx, Statement t)
                {
                        Catch target = (Catch) t;
@@ -4242,51 +4592,110 @@ namespace Mono.CSharp {
                }
        }
 
-       public class Try : ExceptionStatement {
-               public Block Fini, Block;
+       public class TryFinally : ExceptionStatement {
+               Statement stmt;
+               Block fini;
+
+               public TryFinally (Statement stmt, Block fini, Location l)
+               {
+                       this.stmt = stmt;
+                       this.fini = fini;
+                       loc = l;
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       bool ok = true;
+
+                       ec.StartFlowBranching (this);
+
+                       if (!stmt.Resolve (ec))
+                               ok = false;
+
+                       if (ok)
+                               ec.CurrentBranching.CreateSibling (fini, FlowBranching.SiblingType.Finally);
+                       using (ec.With (EmitContext.Flags.InFinally, true)) {
+                               if (!fini.Resolve (ec))
+                                       ok = false;
+                       }
+
+                       ec.EndFlowBranching ();
+
+                       ResolveReachability (ec);
+
+                       return ok;
+               }
+
+               protected override void EmitPreTryBody (EmitContext ec)
+               {
+               }
+
+               protected override void EmitTryBody (EmitContext ec)
+               {
+                       stmt.Emit (ec);
+               }
+
+               protected override void EmitFinallyBody (EmitContext ec)
+               {
+                       fini.Emit (ec);
+               }
+
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       stmt.MutateHoistedGenericType (storey);
+                       fini.MutateHoistedGenericType (storey);
+               }
+
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       TryFinally target = (TryFinally) t;
+
+                       target.stmt = (Statement) stmt.Clone (clonectx);
+                       if (fini != null)
+                               target.fini = clonectx.LookupBlock (fini);
+               }
+       }
+
+       public class TryCatch : Statement {
+               public Block Block;
                public ArrayList Specific;
                public Catch General;
+               bool inside_try_finally, code_follows;
 
-               bool need_exc_block;
-               
-               //
-               // specific, general and fini might all be null.
-               //
-               public Try (Block block, ArrayList specific, Catch general, Block fini, Location l)
+               public TryCatch (Block block, ArrayList catch_clauses, Location l, bool inside_try_finally)
                {
-                       if (specific == null && general == null){
-                               Console.WriteLine ("CIR.Try: Either specific or general have to be non-null");
-                       }
-                       
                        this.Block = block;
-                       this.Specific = specific;
-                       this.General = general;
-                       this.Fini = fini;
+                       this.Specific = catch_clauses;
+                       this.General = null;
+                       this.inside_try_finally = inside_try_finally;
+
+                       for (int i = 0; i < catch_clauses.Count; ++i) {
+                               Catch c = (Catch) catch_clauses [i];
+                               if (c.IsGeneral) {
+                                       if (i != catch_clauses.Count - 1)
+                                               Report.Error (1017, c.loc, "Try statement already has an empty catch block");
+                                       this.General = c;
+                                       catch_clauses.RemoveAt (i);
+                                       i--;
+                               }
+                       }
+
                        loc = l;
                }
 
                public override bool Resolve (EmitContext ec)
                {
                        bool ok = true;
-                       
-                       FlowBranchingException branching = ec.StartFlowBranching (this);
 
-                       Report.Debug (1, "START OF TRY BLOCK", Block.StartLocation);
+                       ec.StartFlowBranching (this);
 
                        if (!Block.Resolve (ec))
                                ok = false;
 
-                       FlowBranching.UsageVector vector = ec.CurrentBranching.CurrentUsageVector;
-
-                       Report.Debug (1, "START OF CATCH BLOCKS", vector);
-
-                       Type[] prevCatches = new Type [Specific.Count];
+                       Type[] prev_catches = new Type [Specific.Count];
                        int last_index = 0;
                        foreach (Catch c in Specific){
-                               ec.CurrentBranching.CreateSibling (
-                                       c.Block, FlowBranching.SiblingType.Catch);
-
-                               Report.Debug (1, "STARTED SIBLING FOR CATCH", ec.CurrentBranching);
+                               ec.CurrentBranching.CreateSibling (c.Block, FlowBranching.SiblingType.Catch);
 
                                if (c.Name != null) {
                                        LocalInfo vi = c.Block.GetLocalInfo (c.Name);
@@ -4297,23 +4706,20 @@ namespace Mono.CSharp {
                                }
 
                                if (!c.Resolve (ec))
-                                       return false;
+                                       ok = false;
 
-                               Type resolvedType = c.CatchType;
+                               Type resolved_type = c.CatchType;
                                for (int ii = 0; ii < last_index; ++ii) {
-                                       if (resolvedType == prevCatches [ii] || resolvedType.IsSubclassOf (prevCatches [ii])) {
-                                               Report.Error (160, c.loc, "A previous catch clause already catches all exceptions of this or a super type `{0}'", prevCatches [ii].FullName);
-                                               return false;
+                                       if (resolved_type == prev_catches [ii] || TypeManager.IsSubclassOf (resolved_type, prev_catches [ii])) {
+                                               Report.Error (160, c.loc, "A previous catch clause already catches all exceptions of this or a super type `{0}'", prev_catches [ii].FullName);
+                                               ok = false;
                                        }
                                }
 
-                               prevCatches [last_index++] = resolvedType;
-                               need_exc_block = true;
+                               prev_catches [last_index++] = resolved_type;
                        }
 
-                       Report.Debug (1, "END OF CATCH BLOCKS", ec.CurrentBranching);
-
-                       if (General != null){
+                       if (General != null) {
                                if (CodeGen.Assembly.WrapNonExceptionThrows) {
                                        foreach (Catch c in Specific){
                                                if (c.CatchType == TypeManager.exception_type) {
@@ -4322,58 +4728,34 @@ namespace Mono.CSharp {
                                        }
                                }
 
-                               ec.CurrentBranching.CreateSibling (
-                                       General.Block, FlowBranching.SiblingType.Catch);
-
-                               Report.Debug (1, "STARTED SIBLING FOR GENERAL", ec.CurrentBranching);
+                               ec.CurrentBranching.CreateSibling (General.Block, FlowBranching.SiblingType.Catch);
 
                                if (!General.Resolve (ec))
                                        ok = false;
-
-                               need_exc_block = true;
                        }
 
-                       Report.Debug (1, "END OF GENERAL CATCH BLOCKS", ec.CurrentBranching);
-
-                       if (Fini != null) {
-                               if (ok)
-                                       ec.CurrentBranching.CreateSibling (Fini, FlowBranching.SiblingType.Finally);
-
-                               Report.Debug (1, "STARTED SIBLING FOR FINALLY", ec.CurrentBranching, vector);
-                               using (ec.With (EmitContext.Flags.InFinally, true)) {
-                                       if (!Fini.Resolve (ec))
-                                               ok = false;
-                               }
-
-                               if (!ec.InIterator)
-                                       need_exc_block = true;
-                       }
-
-                       if (ec.InIterator) {
-                               ResolveFinally (branching);
-                               need_exc_block |= emit_finally;
-                       } else
-                               emit_finally = Fini != null;
-
                        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 ();
-
-                       FlowBranching.UsageVector f_vector = ec.CurrentBranching.CurrentUsageVector;
-
-                       Report.Debug (1, "END OF TRY", ec.CurrentBranching, vector, f_vector);
+                       // System.Reflection.Emit automatically emits a 'leave' at the end of a try/catch clause
+                       // So, ensure there's some IL code after this statement
+                       if (!inside_try_finally && !code_follows && ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
+                               ec.NeedReturnLabel ();
 
                        return ok;
                }
+
+               public void SomeCodeFollows ()
+               {
+                       code_follows = true;
+               }
                
                protected override void DoEmit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
 
-                       if (need_exc_block)
+                       if (!inside_try_finally)
                                ig.BeginExceptionBlock ();
+
                        Block.Emit (ec);
 
                        foreach (Catch c in Specific)
@@ -4382,31 +4764,27 @@ namespace Mono.CSharp {
                        if (General != null)
                                General.Emit (ec);
 
-                       DoEmitFinally (ec);
-                       if (need_exc_block)
+                       if (!inside_try_finally)
                                ig.EndExceptionBlock ();
                }
 
-               public override void EmitFinally (EmitContext ec)
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
                {
-                       if (Fini != null)
-                               Fini.Emit (ec);
-               }
+                       Block.MutateHoistedGenericType (storey);
 
-               public bool HasCatch
-               {
-                       get {
-                               return General != null || Specific.Count > 0;
+                       if (General != null)
+                               General.MutateHoistedGenericType (storey);
+                       if (Specific != null) {
+                               foreach (Catch c in Specific)
+                                       c.MutateHoistedGenericType (storey);
                        }
                }
 
                protected override void CloneTo (CloneContext clonectx, Statement t)
                {
-                       Try target = (Try) t;
+                       TryCatch target = (TryCatch) 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){
@@ -4417,206 +4795,200 @@ namespace Mono.CSharp {
                }
        }
 
-       public class Using : ExceptionStatement {
-               object expression_or_block;
+       public class UsingTemporary : ExceptionStatement {
+               TemporaryVariable local_copy;
                public Statement Statement;
-               ArrayList var_list;
                Expression expr;
                Type expr_type;
-               Expression [] resolved_vars;
-               Expression [] converted_vars;
-               Expression [] assign;
-               TemporaryVariable local_copy;
-               
-               public Using (object expression_or_block, Statement stmt, Location l)
+
+               public UsingTemporary (Expression expr, Statement stmt, Location l)
                {
-                       this.expression_or_block = expression_or_block;
+                       this.expr = expr;
                        Statement = stmt;
                        loc = l;
                }
 
-               //
-               // Resolves for the case of using using a local variable declaration.
-               //
-               bool ResolveLocalVariableDecls (EmitContext ec)
+               public override bool Resolve (EmitContext ec)
                {
-                       resolved_vars = new Expression[var_list.Count];
-                       assign = new Expression [var_list.Count];
-                       converted_vars = new Expression[var_list.Count];
+                       expr = expr.Resolve (ec);
+                       if (expr == null)
+                               return false;
 
-                       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;
+                       expr_type = expr.Type;
 
-                               Expression a = new Assign (var, new_expr, loc);
-                               a = a.Resolve (ec);
-                               if (a == null)
+                       if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)) {
+                               if (Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) {
+                                       Using.Error_IsNotConvertibleToIDisposable (expr);
                                        return false;
+                               }
+                       }
 
-                               resolved_vars [i] = var;
-                               assign [i] = a;
+                       local_copy = new TemporaryVariable (expr_type, loc);
+                       local_copy.Resolve (ec);
 
-                               if (TypeManager.ImplementsInterface (a.Type, TypeManager.idisposable_type)) {
-                                       converted_vars [i] = var;
-                                       continue;
-                               }
+                       ec.StartFlowBranching (this);
 
-                               a = Convert.ImplicitConversionStandard (ec, a, TypeManager.idisposable_type, var.Location);
-                               if (a == null) {
-                                       Error_IsNotConvertibleToIDisposable (var);
-                                       return false;
-                               }
+                       bool ok = Statement.Resolve (ec);
+
+                       ec.EndFlowBranching ();
+
+                       ResolveReachability (ec);
 
-                               converted_vars [i] = a;
+                       if (TypeManager.void_dispose_void == null) {
+                               TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
+                                       TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes);
                        }
 
-                       return true;
+                       return ok;
                }
 
-               static void Error_IsNotConvertibleToIDisposable (Expression expr)
+               protected override void EmitPreTryBody (EmitContext ec)
                {
-                       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 ());
+                       local_copy.EmitAssign (ec, expr);
                }
 
-               bool ResolveExpression (EmitContext ec)
+               protected override void EmitTryBody (EmitContext ec)
                {
-                       if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)){
-                               if (Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) {
-                                       Error_IsNotConvertibleToIDisposable (expr);
-                                       return false;
-                               }
-                       }
-
-                       local_copy = new TemporaryVariable (expr_type, loc);
-                       local_copy.Resolve (ec);
-
-                       return true;
+                       Statement.Emit (ec);
                }
-               
-               //
-               // Emits the code for the case of using using a local variable declaration.
-               //
-               void EmitLocalVariableDecls (EmitContext ec)
+
+               protected override void EmitFinallyBody (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
-                       int i = 0;
+                       if (!expr_type.IsValueType) {
+                               Label skip = ig.DefineLabel ();
+                               local_copy.Emit (ec);
+                               ig.Emit (OpCodes.Brfalse, skip);
+                               local_copy.Emit (ec);
+                               ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
+                               ig.MarkLabel (skip);
+                               return;
+                       }
 
-                       for (i = 0; i < assign.Length; i++) {
-                               ExpressionStatement es = assign [i] as ExpressionStatement;
+                       Expression ml = Expression.MemberLookup (
+                               ec.ContainerType, TypeManager.idisposable_type, expr_type,
+                               "Dispose", Location.Null);
 
-                               if (es != null)
-                                       es.EmitStatement (ec);
-                               else {
-                                       assign [i].Emit (ec);
-                                       ig.Emit (OpCodes.Pop);
+                       if (!(ml is MethodGroupExpr)) {
+                               local_copy.Emit (ec);
+                               ig.Emit (OpCodes.Box, expr_type);
+                               ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
+                               return;
+                       }
+
+                       MethodInfo mi = null;
+
+                       foreach (MethodInfo mk in ((MethodGroupExpr) ml).Methods) {
+                               if (TypeManager.GetParameterData (mk).Count == 0) {
+                                       mi = mk;
+                                       break;
                                }
+                       }
 
-                               if (emit_finally)
-                                       ig.BeginExceptionBlock ();
+                       if (mi == null) {
+                               Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters.");
+                               return;
                        }
-                       Statement.Emit (ec);
 
-                       var_list.Reverse ();
+                       local_copy.AddressOf (ec, AddressOp.Load);
+                       ig.Emit (OpCodes.Call, mi);
+               }
 
-                       DoEmitFinally (ec);
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       expr_type = storey.MutateType (expr_type);
+                       local_copy.MutateHoistedGenericType (storey);
+                       Statement.MutateHoistedGenericType (storey);
                }
 
-               void EmitLocalVariableDeclFinally (EmitContext ec)
+               protected override void CloneTo (CloneContext clonectx, Statement t)
                {
-                       ILGenerator ig = ec.ig;
+                       UsingTemporary target = (UsingTemporary) t;
 
-                       int i = assign.Length;
-                       for (int ii = 0; ii < var_list.Count; ++ii){
-                               Expression var = resolved_vars [--i];
-                               Label skip = ig.DefineLabel ();
+                       target.expr = expr.Clone (clonectx);
+                       target.Statement = Statement.Clone (clonectx);
+               }
+       }
 
-                               if (emit_finally)
-                                       ig.BeginFinallyBlock ();
-                               
-                               if (!var.Type.IsValueType) {
-                                       var.Emit (ec);
-                                       ig.Emit (OpCodes.Brfalse, skip);
-                                       converted_vars [i].Emit (ec);
-                                       ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
-                               } else {
-                                       Expression ml = Expression.MemberLookup(ec.ContainerType, TypeManager.idisposable_type, var.Type, "Dispose", Mono.CSharp.Location.Null);
+       public class Using : ExceptionStatement {
+               Statement stmt;
+               public Statement EmbeddedStatement {
+                       get { return stmt is Using ? ((Using) stmt).EmbeddedStatement : stmt; }
+               }
 
-                                       if (!(ml is MethodGroupExpr)) {
-                                               var.Emit (ec);
-                                               ig.Emit (OpCodes.Box, var.Type);
-                                               ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
-                                       } else {
-                                               MethodInfo mi = null;
+               Expression var;
+               Expression init;
 
-                                               foreach (MethodInfo mk in ((MethodGroupExpr) ml).Methods) {
-                                                       if (TypeManager.GetParameterData (mk).Count == 0) {
-                                                               mi = mk;
-                                                               break;
-                                                       }
-                                               }
+               Expression converted_var;
+               ExpressionStatement assign;
 
-                                               if (mi == null) {
-                                                       Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters.");
-                                                       return;
-                                               }
+               public Using (Expression var, Expression init, Statement stmt, Location l)
+               {
+                       this.var = var;
+                       this.init = init;
+                       this.stmt = stmt;
+                       loc = l;
+               }
 
-                                               IMemoryLocation mloc = (IMemoryLocation) var;
+               bool ResolveVariable (EmitContext ec)
+               {
+                       ExpressionStatement a = new SimpleAssign (var, init, loc);
+                       a = a.ResolveStatement (ec);
+                       if (a == null)
+                               return false;
 
-                                               mloc.AddressOf (ec, AddressOp.Load);
-                                               ig.Emit (OpCodes.Call, mi);
-                                       }
-                               }
+                       assign = a;
 
-                               ig.MarkLabel (skip);
+                       if (TypeManager.ImplementsInterface (a.Type, TypeManager.idisposable_type)) {
+                               converted_var = var;
+                               return true;
+                       }
 
-                               if (emit_finally) {
-                                       ig.EndExceptionBlock ();
-                                       if (i > 0)
-                                               ig.BeginFinallyBlock ();
-                               }
+                       Expression e = Convert.ImplicitConversionStandard (ec, a, TypeManager.idisposable_type, var.Location);
+                       if (e == null) {
+                               Error_IsNotConvertibleToIDisposable (var);
+                               return false;
                        }
+
+                       converted_var = e;
+
+                       return true;
                }
 
-               void EmitExpression (EmitContext ec)
+               static public void Error_IsNotConvertibleToIDisposable (Expression expr)
                {
-                       //
-                       // Make a copy of the expression and operate on that.
-                       //
-                       ILGenerator ig = ec.ig;
-
-                       local_copy.Store (ec, expr);
+                       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 ());
+               }
 
-                       if (emit_finally)
-                               ig.BeginExceptionBlock ();
+               protected override void EmitPreTryBody (EmitContext ec)
+               {
+                       assign.EmitStatement (ec);
+               }
 
-                       Statement.Emit (ec);
-                       
-                       DoEmitFinally (ec);
-                       if (emit_finally)
-                               ig.EndExceptionBlock ();
+               protected override void EmitTryBody (EmitContext ec)
+               {
+                       stmt.Emit (ec);
                }
 
-               void EmitExpressionFinally (EmitContext ec)
+               protected override void EmitFinallyBody (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
-                       if (!expr_type.IsValueType) {
+
+                       if (!var.Type.IsValueType) {
                                Label skip = ig.DefineLabel ();
-                               local_copy.Emit (ec);
+                               var.Emit (ec);
                                ig.Emit (OpCodes.Brfalse, skip);
-                               local_copy.Emit (ec);
+                               converted_var.Emit (ec);
                                ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
                                ig.MarkLabel (skip);
                        } else {
-                               Expression ml = Expression.MemberLookup (
-                                       ec.ContainerType, TypeManager.idisposable_type, expr_type,
-                                       "Dispose", Location.Null);
+                               Expression ml = Expression.MemberLookup(ec.ContainerType, TypeManager.idisposable_type, var.Type, "Dispose", Mono.CSharp.Location.Null);
 
                                if (!(ml is MethodGroupExpr)) {
-                                       local_copy.Emit (ec);
-                                       ig.Emit (OpCodes.Box, expr_type);
+                                       var.Emit (ec);
+                                       ig.Emit (OpCodes.Box, var.Type);
                                        ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
                                } else {
                                        MethodInfo mi = null;
@@ -4633,75 +5005,49 @@ namespace Mono.CSharp {
                                                return;
                                        }
 
-                                       local_copy.AddressOf (ec, AddressOp.Load);
+                                       IMemoryLocation mloc = (IMemoryLocation) var;
+
+                                       mloc.AddressOf (ec, AddressOp.Load);
                                        ig.Emit (OpCodes.Call, mi);
                                }
                        }
                }
-               
+
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       assign.MutateHoistedGenericType (storey);
+                       var.MutateHoistedGenericType (storey);
+                       stmt.MutateHoistedGenericType (storey);
+               }
+
                public override bool Resolve (EmitContext ec)
                {
-                       if (expression_or_block is DictionaryEntry){
-                               expr = (Expression) ((DictionaryEntry) expression_or_block).Key;
-                               var_list = (ArrayList)((DictionaryEntry)expression_or_block).Value;
+                       if (!ResolveVariable (ec))
+                               return false;
 
-                               if (!ResolveLocalVariableDecls (ec))
-                                       return false;
+                       ec.StartFlowBranching (this);
 
-                       } else if (expression_or_block is Expression){
-                               expr = (Expression) expression_or_block;
+                       bool ok = stmt.Resolve (ec);
 
-                               expr = expr.Resolve (ec);
-                               if (expr == null)
-                                       return false;
+                       ec.EndFlowBranching ();
 
-                               expr_type = expr.Type;
+                       ResolveReachability (ec);
 
-                               if (!ResolveExpression (ec))
-                                       return false;
+                       if (TypeManager.void_dispose_void == null) {
+                               TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
+                                       TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes);
                        }
 
-                       FlowBranchingException branching = ec.StartFlowBranching (this);
-
-                       bool ok = Statement.Resolve (ec);
-
-                       ResolveFinally (branching);
-
-                       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 ();
-
                        return ok;
                }
-               
-               protected override void DoEmit (EmitContext ec)
-               {
-                       if (expression_or_block is DictionaryEntry)
-                               EmitLocalVariableDecls (ec);
-                       else if (expression_or_block is Expression)
-                               EmitExpression (ec);
-               }
-
-               public override void EmitFinally (EmitContext ec)
-               {
-                       if (expression_or_block is DictionaryEntry)
-                               EmitLocalVariableDeclFinally (ec);
-                       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);
+                       target.var = var.Clone (clonectx);
+                       target.init = init.Clone (clonectx);
+                       target.stmt = stmt.Clone (clonectx);
                }
        }
 
@@ -4713,8 +5059,6 @@ namespace Mono.CSharp {
                Expression variable;
                Expression expr;
                Statement statement;
-               ArrayForeach array;
-               CollectionForeach collection;
                
                public Foreach (Expression type, LocalVariableReference var, Expression expr,
                                Statement stmt, Location l)
@@ -4736,7 +5080,7 @@ namespace Mono.CSharp {
                        if (expr == null)
                                return false;
 
-                       if (expr.Type == TypeManager.null_type) {
+                       if (expr.IsNull) {
                                Report.Error (186, loc, "Use of null is not valid in this context");
                                return false;
                        }
@@ -4747,26 +5091,13 @@ namespace Mono.CSharp {
                                return false;
                        }
 
-                       //
-                       // We need an instance variable.  Not sure this is the best
-                       // way of doing this.
-                       //
-                       // FIXME: When we implement propertyaccess, will those turn
-                       // out to return values in ExprClass?  I think they should.
-                       //
-                       if (!(expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.Value ||
-                             expr.eclass == ExprClass.PropertyAccess || expr.eclass == ExprClass.IndexerAccess)){
-                               collection.Error_Enumerator ();
-                               return false;
-                       }
-
                        if (expr.Type.IsArray) {
-                               array = new ArrayForeach (type, variable, expr, statement, loc);
-                               return array.Resolve (ec);
+                               statement = new ArrayForeach (type, variable, expr, statement, loc);
+                       } else {
+                               statement = new CollectionForeach (type, variable, expr, statement, loc);
                        }
                        
-                       collection = new CollectionForeach (type, variable, expr, statement, loc);
-                       return collection.Resolve (ec);
+                       return statement.Resolve (ec);
                }
 
                protected override void DoEmit (EmitContext ec)
@@ -4777,10 +5108,7 @@ namespace Mono.CSharp {
                        ec.LoopBegin = ig.DefineLabel ();
                        ec.LoopEnd = ig.DefineLabel ();
 
-                       if (collection != null)
-                               collection.Emit (ec);
-                       else
-                               array.Emit (ec);
+                       statement.Emit (ec);
                        
                        ec.LoopBegin = old_begin;
                        ec.LoopEnd = old_end;
@@ -4788,24 +5116,22 @@ namespace Mono.CSharp {
 
                protected class ArrayCounter : TemporaryVariable
                {
+                       StatementExpression increment;
+
                        public ArrayCounter (Location loc)
                                : base (TypeManager.int32_type, loc)
-                       { }
+                       {
+                       }
 
-                       public void Initialize (EmitContext ec)
+                       public void ResolveIncrement (EmitContext ec)
                        {
-                               EmitThis (ec);
-                               ec.ig.Emit (OpCodes.Ldc_I4_0);
-                               EmitStore (ec);
+                               increment = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, this, loc));
+                               increment.Resolve (ec);
                        }
 
-                       public void Increment (EmitContext ec)
+                       public void EmitIncrement (EmitContext ec)
                        {
-                               EmitThis (ec);
-                               Emit (ec);
-                               ec.ig.Emit (OpCodes.Ldc_I4_1);
-                               ec.ig.Emit (OpCodes.Add);
-                               EmitStore (ec);
+                               increment.Emit (ec);
                        }
                }
 
@@ -4821,6 +5147,7 @@ namespace Mono.CSharp {
 
                        TemporaryVariable copy;
                        Expression access;
+                       Expression[] length_exprs;
 
                        public ArrayForeach (Expression var_type, Expression var,
                                             Expression expr, Statement stmt, Location l)
@@ -4842,15 +5169,24 @@ namespace Mono.CSharp {
 
                                counter = new ArrayCounter [rank];
                                lengths = new TemporaryVariable [rank];
+                               length_exprs = new Expression [rank];
 
-                               ArrayList list = new ArrayList ();
+                               ArrayList list = new ArrayList (rank);
                                for (int i = 0; i < rank; i++) {
                                        counter [i] = new ArrayCounter (loc);
-                                       counter [i].Resolve (ec);
+                                       counter [i].ResolveIncrement (ec);                                      
 
                                        lengths [i] = new TemporaryVariable (TypeManager.int32_type, loc);
                                        lengths [i].Resolve (ec);
 
+                                       if (rank == 1) {
+                                               length_exprs [i] = new MemberAccess (copy, "Length").Resolve (ec);
+                                       } else {
+                                               ArrayList args = new ArrayList (1);
+                                               args.Add (new Argument (new IntConstant (i, loc)));
+                                               length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec);
+                                       }
+
                                        list.Add (counter [i]);
                                }
 
@@ -4898,7 +5234,7 @@ namespace Mono.CSharp {
                        {
                                ILGenerator ig = ec.ig;
 
-                               copy.Store (ec, expr);
+                               copy.EmitAssign (ec, expr);
 
                                Label[] test = new Label [rank];
                                Label[] loop = new Label [rank];
@@ -4907,13 +5243,12 @@ namespace Mono.CSharp {
                                        test [i] = ig.DefineLabel ();
                                        loop [i] = ig.DefineLabel ();
 
-                                       lengths [i].EmitThis (ec);
-                                       ((ArrayAccess) access).EmitGetLength (ec, i);
-                                       lengths [i].EmitStore (ec);
+                                       lengths [i].EmitAssign (ec, length_exprs [i]);
                                }
 
+                               IntConstant zero = new IntConstant (0, loc);
                                for (int i = 0; i < rank; i++) {
-                                       counter [i].Initialize (ec);
+                                       counter [i].EmitAssign (ec, zero);
 
                                        ig.Emit (OpCodes.Br, test [i]);
                                        ig.MarkLabel (loop [i]);
@@ -4926,7 +5261,7 @@ namespace Mono.CSharp {
                                ig.MarkLabel (ec.LoopBegin);
 
                                for (int i = rank - 1; i >= 0; i--){
-                                       counter [i].Increment (ec);
+                                       counter [i].EmitIncrement (ec);
 
                                        ig.MarkLabel (test [i]);
                                        counter [i].Emit (ec);
@@ -4936,9 +5271,22 @@ namespace Mono.CSharp {
 
                                ig.MarkLabel (ec.LoopEnd);
                        }
+
+                       public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+                       {
+                               copy.MutateHoistedGenericType (storey);
+                               conv.MutateHoistedGenericType (storey);
+                               variable.MutateHoistedGenericType (storey);
+                               statement.MutateHoistedGenericType (storey);
+
+                               for (int i = 0; i < rank; i++) {
+                                       counter [i].MutateHoistedGenericType (storey);
+                                       lengths [i].MutateHoistedGenericType (storey);
+                               }
+                       }
                }
 
-               protected class CollectionForeach : ExceptionStatement
+               protected class CollectionForeach : Statement
                {
                        Expression variable, expr;
                        Statement statement;
@@ -4946,13 +5294,13 @@ namespace Mono.CSharp {
                        TemporaryVariable enumerator;
                        Expression init;
                        Statement loop;
+                       Statement wrapper;
 
                        MethodGroupExpr get_enumerator;
                        PropertyExpr get_current;
                        MethodInfo move_next;
                        Expression var_type;
                        Type enumerator_type;
-                       bool is_disposable;
                        bool enumerator_found;
 
                        public CollectionForeach (Expression var_type, Expression var,
@@ -5000,6 +5348,16 @@ namespace Mono.CSharp {
                                        // way I could do this without a goto
                                        //
 
+                                       if (TypeManager.bool_movenext_void == null) {
+                                               TypeManager.bool_movenext_void = TypeManager.GetPredefinedMethod (
+                                                       TypeManager.ienumerator_type, "MoveNext", loc, Type.EmptyTypes);
+                                       }
+
+                                       if (TypeManager.ienumerator_getcurrent == null) {
+                                               TypeManager.ienumerator_getcurrent = TypeManager.GetPredefinedProperty (
+                                                       TypeManager.ienumerator_type, "Current", loc, TypeManager.object_type);
+                                       }
+
 #if GMCS_SOURCE
                                        //
                                        // Prefer a generic enumerator over a non-generic one.
@@ -5038,9 +5396,6 @@ namespace Mono.CSharp {
                                }
 
                                enumerator_type = return_type;
-                               is_disposable = !enumerator_type.IsSealed ||
-                                       TypeManager.ImplementsInterface (
-                                               enumerator_type, TypeManager.idisposable_type);
 
                                return true;
                        }
@@ -5112,7 +5467,7 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       public void Error_Enumerator ()
+                       void Error_Enumerator ()
                        {
                                if (enumerator_found) {
                                        return;
@@ -5248,13 +5603,15 @@ namespace Mono.CSharp {
                        public override bool Resolve (EmitContext ec)
                        {
                                enumerator_type = TypeManager.ienumerator_type;
-                               is_disposable = true;
 
                                if (!ProbeCollectionType (ec, expr.Type)) {
                                        Error_Enumerator ();
                                        return false;
                                }
 
+                               bool is_disposable = !enumerator_type.IsSealed ||
+                                       TypeManager.ImplementsInterface (enumerator_type, TypeManager.idisposable_type);
+
                                VarExpr ve = var_type as VarExpr;
                                if (ve != null) {
                                        // Infer implicitly typed local variable from foreach enumerable type
@@ -5289,58 +5646,114 @@ namespace Mono.CSharp {
 
                                loop = new While (move_next_expr, block, loc);
 
-                               bool ok = true;
+                               wrapper = is_disposable ?
+                                       (Statement) new DisposableWrapper (this) :
+                                       (Statement) new NonDisposableWrapper (this);
+                               return wrapper.Resolve (ec);
+                       }
 
-                               FlowBranchingException branching = null;
-                               if (is_disposable)
-                                       branching = ec.StartFlowBranching (this);
+                       protected override void DoEmit (EmitContext ec)
+                       {
+                               wrapper.Emit (ec);
+                       }
 
-                               if (!loop.Resolve (ec))
-                                       ok = false;
+                       class NonDisposableWrapper : Statement {
+                               CollectionForeach parent;
 
-                               if (is_disposable) {
-                                       ResolveFinally (branching);
-                                       ec.EndFlowBranching ();
-                               } else
-                                       emit_finally = true;
+                               internal NonDisposableWrapper (CollectionForeach parent)
+                               {
+                                       this.parent = parent;
+                               }
 
-                               return ok;
+                               public override bool Resolve (EmitContext ec)
+                               {
+                                       return parent.ResolveLoop (ec);
+                               }
+
+                               protected override void DoEmit (EmitContext ec)
+                               {
+                                       parent.EmitLoopInit (ec);
+                                       parent.EmitLoopBody (ec);
+                               }
+
+                               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+                               {
+                                       throw new NotSupportedException ();
+                               }
                        }
 
-                       protected override void DoEmit (EmitContext ec)
-                       {
-                               ILGenerator ig = ec.ig;
+                       class DisposableWrapper : ExceptionStatement {
+                               CollectionForeach parent;
 
-                               enumerator.Store (ec, init);
+                               internal DisposableWrapper (CollectionForeach parent)
+                               {
+                                       this.parent = parent;
+                               }
 
-                               //
-                               // Protect the code in a try/finalize block, so that
-                               // if the beast implement IDisposable, we get rid of it
-                               //
-                               if (is_disposable && emit_finally)
-                                       ig.BeginExceptionBlock ();
-                       
-                               loop.Emit (ec);
+                               public override bool Resolve (EmitContext ec)
+                               {
+                                       bool ok = true;
 
-                               //
-                               // Now the finally block
-                               //
-                               if (is_disposable) {
-                                       DoEmitFinally (ec);
-                                       if (emit_finally)
-                                               ig.EndExceptionBlock ();
+                                       ec.StartFlowBranching (this);
+
+                                       if (!parent.ResolveLoop (ec))
+                                               ok = false;
+
+                                       ec.EndFlowBranching ();
+
+                                       ResolveReachability (ec);
+
+                                       if (TypeManager.void_dispose_void == null) {
+                                               TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
+                                                       TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes);
+                                       }
+                                       return ok;
+                               }
+
+                               protected override void EmitPreTryBody (EmitContext ec)
+                               {
+                                       parent.EmitLoopInit (ec);
+                               }
+
+                               protected override void EmitTryBody (EmitContext ec)
+                               {
+                                       parent.EmitLoopBody (ec);
                                }
+
+                               protected override void EmitFinallyBody (EmitContext ec)
+                               {
+                                       parent.EmitFinallyBody (ec);
+                               }
+
+                               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+                               {
+                                       throw new NotSupportedException ();
+                               }
+                       }
+
+                       bool ResolveLoop (EmitContext ec)
+                       {
+                               return loop.Resolve (ec);
                        }
 
+                       void EmitLoopInit (EmitContext ec)
+                       {
+                               enumerator.EmitAssign (ec, init);
+                       }
 
-                       public override void EmitFinally (EmitContext ec)
+                       void EmitLoopBody (EmitContext ec)
+                       {
+                               loop.Emit (ec);
+                       }
+
+                       void EmitFinallyBody (EmitContext ec)
                        {
                                ILGenerator ig = ec.ig;
 
                                if (enumerator_type.IsValueType) {
                                        MethodInfo mi = FetchMethodDispose (enumerator_type);
                                        if (mi != null) {
-                                               enumerator.EmitLoadAddress (ec);
+                                               enumerator.AddressOf (ec, AddressOp.Load);
                                                ig.Emit (OpCodes.Call, mi);
                                        } else {
                                                enumerator.Emit (ec);
@@ -5354,16 +5767,22 @@ namespace Mono.CSharp {
                                        ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
                                        ig.Emit (OpCodes.Dup);
                                        ig.Emit (OpCodes.Brtrue_S, call_dispose);
-                                       ig.Emit (OpCodes.Pop);
 
-                                       Label end_finally = ig.DefineLabel ();
-                                       ig.Emit (OpCodes.Br, end_finally);
+                                       // 'endfinally' empties the evaluation stack, and can appear anywhere inside a finally block
+                                       // (Partition III, Section 3.35)
+                                       ig.Emit (OpCodes.Endfinally);
 
                                        ig.MarkLabel (call_dispose);
                                        ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
-                                       ig.MarkLabel (end_finally);
                                }
                        }
+
+                       public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+                       {
+                               enumerator_type = storey.MutateType (enumerator_type);
+                               init.MutateHoistedGenericType (storey);
+                               loop.MutateHoistedGenericType (storey);
+                       }
                }
 
                protected class CollectionForeachStatement : Statement
@@ -5394,7 +5813,7 @@ namespace Mono.CSharp {
                                if (conv == null)
                                        return false;
 
-                               assign = new Assign (variable, conv, loc);
+                               assign = new SimpleAssign (variable, conv, loc);
                                if (assign.Resolve (ec) == null)
                                        return false;
 
@@ -5409,6 +5828,12 @@ namespace Mono.CSharp {
                                assign.EmitStatement (ec);
                                statement.Emit (ec);
                        }
+
+                       public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+                       {
+                               assign.MutateHoistedGenericType (storey);
+                               statement.MutateHoistedGenericType (storey);
+                       }
                }
 
                protected override void CloneTo (CloneContext clonectx, Statement t)
@@ -5420,5 +5845,10 @@ namespace Mono.CSharp {
                        target.expr = expr.Clone (clonectx);
                        target.statement = statement.Clone (clonectx);
                }
+
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       statement.MutateHoistedGenericType (storey);
+               }
        }
 }