Resolve switch block without fake sections blocks. Fixes #10781
[mono.git] / mcs / mcs / statement.cs
index ff12a7d9dae696ee03bde3a9c2c0fa8d754b8c05..401b6a877fe3cda21a72f5330e403c37fb473dc1 100644 (file)
@@ -49,13 +49,21 @@ namespace Mono.CSharp {
                        // in unreachable code, for instance.
                        //
 
-                       if (warn)
+                       bool unreachable = false;
+                       if (warn && !ec.UnreachableReported) {
+                               ec.UnreachableReported = true;
+                               unreachable = true;
                                ec.Report.Warning (162, 2, loc, "Unreachable code detected");
+                       }
 
                        ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
                        bool ok = Resolve (ec);
                        ec.KillFlowBranching ();
 
+                       if (unreachable) {
+                               ec.UnreachableReported = false;
+                       }
+
                        return ok;
                }
                                
@@ -68,6 +76,10 @@ namespace Mono.CSharp {
                {
                        ec.Mark (loc);
                        DoEmit (ec);
+
+                       if (ec.StatementEpilogue != null) {
+                               ec.EmitEpilogue ();
+                       }
                }
 
                //
@@ -277,11 +289,16 @@ namespace Mono.CSharp {
                public Expression expr;
                public Statement  EmbeddedStatement;
 
-               public Do (Statement statement, BooleanExpression bool_expr, Location l)
+               public Do (Statement statement, BooleanExpression bool_expr, Location doLocation, Location whileLocation)
                {
                        expr = bool_expr;
                        EmbeddedStatement = statement;
-                       loc = l;
+                       loc = doLocation;
+                       WhileLocation = whileLocation;
+               }
+
+               public Location WhileLocation {
+                       get; private set;
                }
 
                public override bool Resolve (BlockContext ec)
@@ -328,7 +345,7 @@ namespace Mono.CSharp {
                        ec.MarkLabel (ec.LoopBegin);
 
                        // Mark start of while condition
-                       ec.Mark (expr.Location);
+                       ec.Mark (WhileLocation);
 
                        //
                        // Dead code elimination
@@ -457,7 +474,7 @@ namespace Mono.CSharp {
                        
                                ec.MarkLabel (ec.LoopBegin);
 
-                               ec.Mark (expr.Location);
+                               ec.Mark (loc);
                                expr.EmitBranchable (ec, while_loop, true);
                                
                                ec.MarkLabel (ec.LoopEnd);
@@ -780,12 +797,10 @@ namespace Mono.CSharp {
 
                public sealed override bool Resolve (BlockContext ec)
                {
-                       if (!DoResolve (ec))
-                               return false;
-
+                       var res = DoResolve (ec);
                        unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, this);
                        ec.CurrentBranching.CurrentUsageVector.Goto ();
-                       return true;
+                       return res;
                }
        }
 
@@ -838,7 +853,7 @@ namespace Mono.CSharp {
 
                                if (ec.CurrentIterator != null) {
                                        Error_ReturnFromIterator (ec);
-                               } else {
+                               } else if (ec.ReturnType != InternalType.ErrorType) {
                                        ec.Report.Error (126, loc,
                                                "An object of a type convertible to `{0}' is required for the return statement",
                                                ec.ReturnType.GetSignatureForError ());
@@ -856,6 +871,8 @@ namespace Mono.CSharp {
                                        ec.Report.Error (127, loc,
                                                "`{0}': A return keyword must not be followed by any expression when method returns void",
                                                ec.GetSignatureForError ());
+
+                                       return false;
                                }
                        } else {
                                if (am.IsIterator) {
@@ -874,12 +891,20 @@ namespace Mono.CSharp {
                                                        return true;
                                                }
 
+                                               if (async_type.Kind == MemberKind.Void) {
+                                                       ec.Report.Error (127, loc,
+                                                               "`{0}': A return keyword must not be followed by any expression when method returns void",
+                                                               ec.GetSignatureForError ());
+
+                                                       return false;
+                                               }
+
                                                if (!async_type.IsGenericTask) {
                                                        if (this is ContextualReturn)
                                                                return true;
 
                                                        ec.Report.Error (1997, loc,
-                                                               "`{0}': A return keyword must not be followed by an expression when async method returns Task. Consider using Task<T>",
+                                                               "`{0}': A return keyword must not be followed by an expression when async method returns `Task'. Consider using `Task<T>' return type",
                                                                ec.GetSignatureForError ());
                                                        return false;
                                                }
@@ -887,9 +912,24 @@ namespace Mono.CSharp {
                                                //
                                                // The return type is actually Task<T> type argument
                                                //
-                                               block_return_type = async_type.TypeArguments[0];
+                                               if (expr.Type == async_type) {
+                                                       ec.Report.Error (4016, loc,
+                                                               "`{0}': The return expression type of async method must be `{1}' rather than `Task<{1}>'",
+                                                               ec.GetSignatureForError (), async_type.TypeArguments[0].GetSignatureForError ());
+                                               } else {
+                                                       block_return_type = async_type.TypeArguments[0];
+                                               }
                                        }
                                } else {
+                                       // Same error code as .NET but better error message
+                                       if (block_return_type.Kind == MemberKind.Void) {
+                                               ec.Report.Error (127, loc,
+                                                       "`{0}': A return keyword must not be followed by any expression when delegate returns void",
+                                                       am.GetSignatureForError ());
+
+                                               return false;
+                                       }
+
                                        var l = am as AnonymousMethodBody;
                                        if (l != null && l.ReturnTypeInference != null && expr != null) {
                                                l.ReturnTypeInference.AddCommonTypeBound (expr.Type);
@@ -901,7 +941,7 @@ namespace Mono.CSharp {
                        if (expr == null)
                                return false;
 
-                       if (expr.Type != block_return_type) {
+                       if (expr.Type != block_return_type && expr.Type != InternalType.ErrorType) {
                                expr = Convert.ImplicitConversionRequired (ec, expr, block_return_type, loc);
 
                                if (expr == null) {
@@ -930,12 +970,15 @@ namespace Mono.CSharp {
                                        if (async_return != null) {
                                                async_return.EmitAssign (ec);
 
-                                               ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, async_body.BodyEnd);
+                                               ec.EmitEpilogue ();
                                        }
 
+                                       ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, async_body.BodyEnd);
                                        return;
                                }
 
+                               ec.EmitEpilogue ();
+
                                if (unwind_protect || ec.EmitAccurateDebugInfo)
                                        ec.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
                        }
@@ -1128,7 +1171,7 @@ namespace Mono.CSharp {
                                return false;
                        }
 
-                       if (!ec.Switch.GotDefault) {
+                       if (ec.Switch.DefaultLabel == null) {
                                FlowBranchingBlock.Error_UnknownLabel (loc, "default", ec.Report);
                                return false;
                        }
@@ -1138,7 +1181,7 @@ namespace Mono.CSharp {
 
                protected override void DoEmit (EmitContext ec)
                {
-                       ec.Emit (OpCodes.Br, ec.Switch.DefaultLabel);
+                       ec.Emit (OpCodes.Br, ec.Switch.DefaultLabel.GetILLabel (ec));
                }
                
                public override object Accept (StructuralVisitor visitor)
@@ -1190,9 +1233,9 @@ namespace Mono.CSharp {
                                res = c;
                        } else {
                                TypeSpec type = ec.Switch.SwitchType;
-                               res = c.TryReduce (ec, type, c.Location);
+                               res = c.Reduce (ec, type);
                                if (res == null) {
-                                       c.Error_ValueCannotBeConverted (ec, loc, type, true);
+                                       c.Error_ValueCannotBeConverted (ec, type, true);
                                        return false;
                                }
 
@@ -1413,6 +1456,7 @@ namespace Mono.CSharp {
                protected FullNamedExpression type_expr;
                protected LocalVariable li;
                protected List<Declarator> declarators;
+               TypeSpec type;
 
                public BlockVariableDeclaration (FullNamedExpression type, LocalVariable li)
                {
@@ -1489,8 +1533,7 @@ namespace Mono.CSharp {
 
                public bool Resolve (BlockContext bc, bool resolveDeclaratorInitializers)
                {
-                       if (li.Type == null) {
-                               TypeSpec type = null;
+                       if (type == null && !li.IsCompilerGenerated) {
                                var vexpr = type_expr as VarExpr;
 
                                //
@@ -1598,8 +1641,10 @@ namespace Mono.CSharp {
                        if (declarators != null) {
                                foreach (var d in declarators) {
                                        d.Variable.CreateBuilder (ec);
-                                       if (d.Initializer != null)
+                                       if (d.Initializer != null) {
+                                               ec.Mark (d.Variable.Location);
                                                ((ExpressionStatement) d.Initializer).EmitStatement (ec);
+                                       }
                                }
                        }
                }
@@ -1656,7 +1701,7 @@ namespace Mono.CSharp {
                                if (TypeSpec.IsReferenceType (li.Type))
                                        initializer.Error_ConstantCanBeInitializedWithNullOnly (bc, li.Type, initializer.Location, li.Name);
                                else
-                                       initializer.Error_ValueCannotBeConverted (bc, initializer.Location, li.Type, false);
+                                       initializer.Error_ValueCannotBeConverted (bc, li.Type, false);
 
                                return null;
                        }
@@ -1767,6 +1812,12 @@ namespace Mono.CSharp {
                        }
                }
 
+               public bool IsCompilerGenerated {
+                       get {
+                               return (flags & Flags.CompilerGenerated) != 0;
+                       }
+               }
+
                public bool IsConstant {
                        get {
                                return (flags & Flags.Constant) != 0;
@@ -2030,9 +2081,7 @@ namespace Mono.CSharp {
 #endif
 
 //             int assignable_slots;
-               bool unreachable_shown;
-               bool unreachable;
-               
+
                public Block (Block parent, Location start, Location end)
                        : this (parent, 0, start, end)
                {
@@ -2097,14 +2146,6 @@ namespace Mono.CSharp {
 
                #endregion
 
-               public Block CreateSwitchBlock (Location start)
-               {
-                       // FIXME: Only explicit block should be created
-                       var new_block = new Block (this, start, start);
-                       new_block.IsCompilerGenerated = true;
-                       return new_block;
-               }
-
                public void SetEndLocation (Location loc)
                {
                        EndLocation = loc;
@@ -2204,6 +2245,8 @@ namespace Mono.CSharp {
 
                        Block prev_block = ec.CurrentBlock;
                        bool ok = true;
+                       bool unreachable = ec.IsUnreachable;
+                       bool prev_unreachable = unreachable;
 
                        ec.CurrentBlock = this;
                        ec.StartFlowBranching (this);
@@ -2236,14 +2279,10 @@ namespace Mono.CSharp {
                                        if (s is EmptyStatement)
                                                continue;
 
-                                       if (!unreachable_shown && !(s is LabeledStatement)) {
+                                       if (!ec.UnreachableReported && !(s is LabeledStatement) && !(s is SwitchLabel)) {
                                                ec.Report.Warning (162, 2, s.loc, "Unreachable code detected");
-                                               unreachable_shown = true;
+                                               ec.UnreachableReported = true;
                                        }
-
-                                       Block c_block = s as Block;
-                                       if (c_block != null)
-                                               c_block.unreachable = c_block.unreachable_shown = true;
                                }
 
                                //
@@ -2256,19 +2295,25 @@ namespace Mono.CSharp {
 
                                if (!s.Resolve (ec)) {
                                        ok = false;
-                                       if (ec.IsInProbingMode)
-                                               break;
+                                       if (!ec.IsInProbingMode)
+                                               statements [ix] = new EmptyStatement (s.loc);
 
-                                       statements [ix] = new EmptyStatement (s.loc);
                                        continue;
                                }
 
-                               if (unreachable && !(s is LabeledStatement) && !(s is Block))
+                               if (unreachable && !(s is LabeledStatement) && !(s is SwitchLabel) && !(s is Block))
                                        statements [ix] = new EmptyStatement (s.loc);
 
                                unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
-                               if (unreachable && s is LabeledStatement)
-                                       throw new InternalErrorException ("should not happen");
+                               if (unreachable) {
+                                       ec.IsUnreachable = true;
+                               } else if (ec.IsUnreachable)
+                                       ec.IsUnreachable = false;
+                       }
+
+                       if (unreachable != prev_unreachable) {
+                               ec.IsUnreachable = prev_unreachable;
+                               ec.UnreachableReported = false;
                        }
 
                        while (ec.CurrentBranching is FlowBranchingLabeled)
@@ -2292,17 +2337,21 @@ namespace Mono.CSharp {
 
                public override bool ResolveUnreachable (BlockContext ec, bool warn)
                {
-                       unreachable_shown = true;
-                       unreachable = true;
-
-                       if (warn)
+                       bool unreachable = false;
+                       if (warn && !ec.UnreachableReported) {
+                               ec.UnreachableReported = true;
+                               unreachable = true;
                                ec.Report.Warning (162, 2, loc, "Unreachable code detected");
+                       }
 
                        var fb = ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
                        fb.CurrentUsageVector.IsUnreachable = true;
                        bool ok = Resolve (ec);
                        ec.KillFlowBranching ();
 
+                       if (unreachable)
+                               ec.UnreachableReported = false;
+
                        return ok;
                }
                
@@ -2392,14 +2441,22 @@ namespace Mono.CSharp {
                }
 
                public bool HasCapturedThis {
-                       set { flags = value ? flags | Flags.HasCapturedThis : flags & ~Flags.HasCapturedThis; }
+                       set {
+                               flags = value ? flags | Flags.HasCapturedThis : flags & ~Flags.HasCapturedThis;
+                       }
                        get {
                                return (flags & Flags.HasCapturedThis) != 0;
                        }
                }
 
+               //
+               // Used to indicate that the block has reference to parent
+               // block and cannot be made static when defining anonymous method
+               //
                public bool HasCapturedVariable {
-                       set { flags = value ? flags | Flags.HasCapturedVariable : flags & ~Flags.HasCapturedVariable; }
+                       set {
+                               flags = value ? flags | Flags.HasCapturedVariable : flags & ~Flags.HasCapturedVariable;
+                       }
                        get {
                                return (flags & Flags.HasCapturedVariable) != 0;
                        }
@@ -2425,21 +2482,13 @@ namespace Mono.CSharp {
                        if (ec.CurrentAnonymousMethod is StateMachineInitializer && ParametersBlock.Original == ec.CurrentAnonymousMethod.Block.Original)
                                return ec.CurrentAnonymousMethod.Storey;
 
-                       //
-                       // When referencing a variable in parent iterator/async storey
-                       // from nested anonymous method
-                       //
-                       if (ParametersBlock.am_storey is StateMachine) {
-                               return ParametersBlock.am_storey;
-                       }
-
                        if (am_storey == null) {
                                MemberBase mc = ec.MemberContext as MemberBase;
 
                                //
                                // Creates anonymous method storey for this block
                                //
-                               am_storey = new AnonymousMethodStorey (this, ec.CurrentMemberDefinition.Parent.PartialContainer, mc, ec.CurrentTypeParameters, "AnonStorey");
+                               am_storey = new AnonymousMethodStorey (this, ec.CurrentMemberDefinition.Parent.PartialContainer, mc, ec.CurrentTypeParameters, "AnonStorey", MemberKind.Class);
                        }
 
                        return am_storey;
@@ -2448,7 +2497,7 @@ namespace Mono.CSharp {
                public override void Emit (EmitContext ec)
                {
                        if (am_storey != null) {
-                               DefineAnonymousStorey (ec);
+                               DefineStoreyContainer (ec, am_storey);
                                am_storey.EmitStoreyInstantiation (ec, this);
                        }
 
@@ -2472,57 +2521,122 @@ namespace Mono.CSharp {
                        }
                }
 
-               void DefineAnonymousStorey (EmitContext ec)
+               protected void DefineStoreyContainer (EmitContext ec, AnonymousMethodStorey storey)
                {
+                       if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null) {
+                               storey.SetNestedStoryParent (ec.CurrentAnonymousMethod.Storey);
+                               storey.Mutator = ec.CurrentAnonymousMethod.Storey.Mutator;
+                       }
+
                        //
                        // Creates anonymous method storey
                        //
-                       if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null) {
+                       storey.CreateContainer ();
+                       storey.DefineContainer ();
+
+                       if (Original.Explicit.HasCapturedThis && Original.ParametersBlock.TopBlock.ThisReferencesFromChildrenBlock != null) {
+
                                //
-                               // Creates parent storey reference when hoisted this is accessible
+                               // Only first storey in path will hold this reference. All children blocks will
+                               // reference it indirectly using $ref field
                                //
-                               if (am_storey.OriginalSourceBlock.Explicit.HasCapturedThis) {
-                                       ExplicitBlock parent = am_storey.OriginalSourceBlock.Explicit.Parent.Explicit;
+                               for (Block b = Original.Explicit; b != null; b = b.Parent) {
+                                       if (b.Parent != null) {
+                                               var s = b.Parent.Explicit.AnonymousMethodStorey;
+                                               if (s != null) {
+                                                       storey.HoistedThis = s.HoistedThis;
+                                                       break;
+                                               }
+                                       }
 
-                                       //
-                                       // Hoisted this exists in top-level parent storey only
-                                       //
-                                       while (parent.am_storey == null || parent.am_storey.Parent is AnonymousMethodStorey)
-                                               parent = parent.Parent.Explicit;
+                                       if (b.Explicit == b.Explicit.ParametersBlock && b.Explicit.ParametersBlock.StateMachine != null) {
+                                               storey.HoistedThis = b.Explicit.ParametersBlock.StateMachine.HoistedThis;
 
-                                       am_storey.AddParentStoreyReference (ec, parent.am_storey);
+                                               if (storey.HoistedThis != null)
+                                                       break;
+                                       }
                                }
+                               
+                               //
+                               // We are the first storey on path and 'this' has to be hoisted
+                               //
+                               if (storey.HoistedThis == null) {
+                                       foreach (ExplicitBlock ref_block in Original.ParametersBlock.TopBlock.ThisReferencesFromChildrenBlock) {
+                                               //
+                                               // ThisReferencesFromChildrenBlock holds all reference even if they
+                                               // are not on this path. It saves some memory otherwise it'd have to
+                                               // be in every explicit block. We run this check to see if the reference
+                                               // is valid for this storey
+                                               //
+                                               Block block_on_path = ref_block;
+                                               for (; block_on_path != null && block_on_path != Original; block_on_path = block_on_path.Parent);
 
-                               am_storey.SetNestedStoryParent (ec.CurrentAnonymousMethod.Storey);
+                                               if (block_on_path == null)
+                                                       continue;
 
-                               // TODO MemberCache: Review
-                               am_storey.Mutator = ec.CurrentAnonymousMethod.Storey.Mutator;
-                       }
+                                               if (storey.HoistedThis == null) {
+                                                       storey.AddCapturedThisField (ec);
+                                               }
 
-                       am_storey.CreateContainer ();
-                       am_storey.DefineContainer ();
+                                               for (ExplicitBlock b = ref_block; b.AnonymousMethodStorey != storey; b = b.Parent.Explicit) {
+                                                       if (b.AnonymousMethodStorey != null) {
+                                                               b.AnonymousMethodStorey.AddParentStoreyReference (ec, storey);
+                                                               b.AnonymousMethodStorey.HoistedThis = storey.HoistedThis;
 
-                       var ref_blocks = am_storey.ReferencesFromChildrenBlock;
+                                                               //
+                                                               // Stop propagation inside same top block
+                                                               //
+                                                               if (b.ParametersBlock == ParametersBlock.Original)
+                                                                       break;
+
+                                                               b = b.ParametersBlock;
+                                                       }
+
+                                                       var pb = b as ParametersBlock;
+                                                       if (pb != null && pb.StateMachine != null) {
+                                                               if (pb.StateMachine == storey)
+                                                                       break;
+
+                                                               pb.StateMachine.AddParentStoreyReference (ec, storey);
+                                                       }
+                                                       
+                                                       b.HasCapturedVariable = true;
+                                               }
+                                       }
+                               }
+                       }
+
+                       var ref_blocks = storey.ReferencesFromChildrenBlock;
                        if (ref_blocks != null) {
                                foreach (ExplicitBlock ref_block in ref_blocks) {
-                                       for (ExplicitBlock b = ref_block.Explicit; b.am_storey != am_storey; b = b.Parent.Explicit) {
-                                               if (b.am_storey != null) {
-                                                       b.am_storey.AddParentStoreyReference (ec, am_storey);
+                                       for (ExplicitBlock b = ref_block; b.AnonymousMethodStorey != storey; b = b.Parent.Explicit) {
+                                               if (b.AnonymousMethodStorey != null) {
+                                                       b.AnonymousMethodStorey.AddParentStoreyReference (ec, storey);
 
+                                                       //
                                                        // Stop propagation inside same top block
-                                                       if (b.ParametersBlock.Original == ParametersBlock.Original)
+                                                       //
+                                                       if (b.ParametersBlock == ParametersBlock.Original)
                                                                break;
 
                                                        b = b.ParametersBlock;
                                                }
 
+                                               var pb = b as ParametersBlock;
+                                               if (pb != null && pb.StateMachine != null) {
+                                                       if (pb.StateMachine == storey)
+                                                               break;
+
+                                                       pb.StateMachine.AddParentStoreyReference (ec, storey);
+                                               }
+
                                                b.HasCapturedVariable = true;
                                        }
                                }
                        }
 
-                       am_storey.Define ();
-                       am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey);
+                       storey.Define ();
+                       storey.Parent.PartialContainer.AddCompilerGeneratedClass (storey);
                }
 
                public void RegisterAsyncAwait ()
@@ -2531,7 +2645,7 @@ namespace Mono.CSharp {
                        while ((block.flags & Flags.AwaitBlock) == 0) {
                                block.flags |= Flags.AwaitBlock;
 
-                               if (block.Parent == null)
+                               if (block is ParametersBlock)
                                        return;
 
                                block = block.Parent.Explicit;
@@ -2580,7 +2694,13 @@ namespace Mono.CSharp {
 
                        #region Properties
 
-                       public Block Block {
+                       public ParametersBlock Block {
+                               get {
+                                       return block;
+                               }
+                       }
+
+                       Block INamedBlockVariable.Block {
                                get {
                                        return block;
                                }
@@ -2683,6 +2803,7 @@ namespace Mono.CSharp {
                bool resolved;
                protected bool unreachable;
                protected ToplevelBlock top_block;
+               protected StateMachine state_machine;
 
                public ParametersBlock (Block parent, ParametersCompiled parameters, Location start)
                        : base (parent, 0, start, start)
@@ -2722,6 +2843,7 @@ namespace Mono.CSharp {
                        this.resolved = true;
                        this.unreachable = source.unreachable;
                        this.am_storey = source.am_storey;
+                       this.state_machine = source.state_machine;
 
                        ParametersBlock = this;
 
@@ -2729,7 +2851,7 @@ namespace Mono.CSharp {
                        // Overwrite original for comparison purposes when linking cross references
                        // between anonymous methods
                        //
-                       Original = source;
+                       Original = source.Original;
                }
 
                #region Properties
@@ -2761,6 +2883,12 @@ namespace Mono.CSharp {
                        }
                }
 
+               public StateMachine StateMachine {
+                       get {
+                               return state_machine;
+                       }
+               }
+
                public ToplevelBlock TopBlock {
                        get {
                                return top_block;
@@ -2816,6 +2944,26 @@ namespace Mono.CSharp {
                        return base.CreateExpressionTree (ec);
                }
 
+               public override void Emit (EmitContext ec)
+               {
+                       if (state_machine != null && state_machine.OriginalSourceBlock != this) {
+                               DefineStoreyContainer (ec, state_machine);
+                               state_machine.EmitStoreyInstantiation (ec, this);
+                       }
+
+                       base.Emit (ec);
+               }
+
+               public void EmitEmbedded (EmitContext ec)
+               {
+                       if (state_machine != null && state_machine.OriginalSourceBlock != this) {
+                               DefineStoreyContainer (ec, state_machine);
+                               state_machine.EmitStoreyInstantiation (ec, this);
+                       }
+
+                       base.Emit (ec);
+               }
+
                public ParameterInfo GetParameterInfo (Parameter p)
                {
                        for (int i = 0; i < parameters.Count; ++i) {
@@ -2826,7 +2974,7 @@ namespace Mono.CSharp {
                        throw new ArgumentException ("Invalid parameter");
                }
 
-               public Expression GetParameterReference (int index, Location loc)
+               public ParameterReference GetParameterReference (int index, Location loc)
                {
                        return new ParameterReference (parameter_info[index], loc);
                }
@@ -2929,7 +3077,7 @@ namespace Mono.CSharp {
                        for (int i = 0; i < orig_count; ++i) {
                                Parameter.Modifier mod = parameters.FixedParameters[i].ModFlags;
 
-                               if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT)
+                               if ((mod & Parameter.Modifier.OUT) == 0)
                                        continue;
 
                                VariableInfo vi = new VariableInfo (parameters, i, ec.FlowOffset);
@@ -2938,37 +3086,71 @@ namespace Mono.CSharp {
                        }
                }
 
-               public void WrapIntoIterator (IMethodData method, TypeDefinition host, TypeSpec iterator_type, bool is_enumerable)
+               public ToplevelBlock ConvertToIterator (IMethodData method, TypeDefinition host, TypeSpec iterator_type, bool is_enumerable)
                {
-                       ParametersBlock pb = new ParametersBlock (this, ParametersCompiled.EmptyReadOnlyParameters, Location.Null);
-                       pb.statements = statements;
-                       pb.Original = this;
+                       var iterator = new Iterator (this, method, host, iterator_type, is_enumerable);
+                       var stateMachine = new IteratorStorey (iterator);
 
-                       var iterator = new Iterator (pb, method, host, iterator_type, is_enumerable);
-                       am_storey = new IteratorStorey (iterator);
+                       state_machine = stateMachine;
+                       iterator.SetStateMachine (stateMachine);
 
-                       statements = new List<Statement> (1);
-                       AddStatement (new Return (iterator, iterator.Location));
-                       flags &= ~Flags.YieldBlock;
-                       IsCompilerGenerated = true;
+                       var tlb = new ToplevelBlock (host.Compiler, Parameters, Location.Null);
+                       tlb.Original = this;
+                       tlb.IsCompilerGenerated = true;
+                       tlb.state_machine = stateMachine;
+                       tlb.AddStatement (new Return (iterator, iterator.Location));
+                       return tlb;
                }
 
-               public void WrapIntoAsyncTask (IMemberContext context, TypeDefinition host, TypeSpec returnType)
+               public ParametersBlock ConvertToAsyncTask (IMemberContext context, TypeDefinition host, ParametersCompiled parameters, TypeSpec returnType, Location loc)
                {
-                       ParametersBlock pb = new ParametersBlock (this, ParametersCompiled.EmptyReadOnlyParameters, Location.Null);
-                       pb.statements = statements;
-                       pb.Original = this;
+                       for (int i = 0; i < parameters.Count; i++) {
+                               Parameter p = parameters[i];
+                               Parameter.Modifier mod = p.ModFlags;
+                               if ((mod & Parameter.Modifier.RefOutMask) != 0) {
+                                       host.Compiler.Report.Error (1988, p.Location,
+                                               "Async methods cannot have ref or out parameters");
+                                       return this;
+                               }
+
+                               if (p is ArglistParameter) {
+                                       host.Compiler.Report.Error (4006, p.Location,
+                                               "__arglist is not allowed in parameter list of async methods");
+                                       return this;
+                               }
+
+                               if (parameters.Types[i].IsPointer) {
+                                       host.Compiler.Report.Error (4005, p.Location,
+                                               "Async methods cannot have unsafe parameters");
+                                       return this;
+                               }
+                       }
+
+                       if (!HasAwait) {
+                               host.Compiler.Report.Warning (1998, 1, loc,
+                                       "Async block lacks `await' operator and will run synchronously");
+                       }
 
                        var block_type = host.Module.Compiler.BuiltinTypes.Void;
-                       var initializer = new AsyncInitializer (pb, host, block_type);
+                       var initializer = new AsyncInitializer (this, host, block_type);
                        initializer.Type = block_type;
 
-                       am_storey = new AsyncTaskStorey (context, initializer, returnType);
+                       var stateMachine = new AsyncTaskStorey (this, context, initializer, returnType);
 
-                       statements = new List<Statement> (1);
-                       AddStatement (new StatementExpression (initializer));
-                       flags &= ~Flags.AwaitBlock;
-                       IsCompilerGenerated = true;
+                       state_machine = stateMachine;
+                       initializer.SetStateMachine (stateMachine);
+
+                       var b = this is ToplevelBlock ?
+                               new ToplevelBlock (host.Compiler, Parameters, Location.Null) :
+                               new ParametersBlock (Parent, parameters, Location.Null) {
+                                       IsAsync = true,
+                               };
+
+                       b.Original = this;
+                       b.IsCompilerGenerated = true;
+                       b.state_machine = stateMachine;
+                       b.AddStatement (new StatementExpression (initializer));
+                       return b;
                }
        }
 
@@ -2982,11 +3164,7 @@ namespace Mono.CSharp {
                Dictionary<string, object> names;
                Dictionary<string, object> labels;
 
-               public HoistedVariable HoistedThisVariable;
-
-               public Report Report {
-                       get { return compiler.Report; }
-               }
+               List<ExplicitBlock> this_references;
 
                public ToplevelBlock (CompilerContext ctx, Location loc)
                        : this (ctx, ParametersCompiled.EmptyReadOnlyParameters, loc)
@@ -3023,6 +3201,31 @@ namespace Mono.CSharp {
                        }
                }
 
+               public Report Report {
+                       get {
+                               return compiler.Report;
+                       }
+               }
+
+               //
+               // Used by anonymous blocks to track references of `this' variable
+               //
+               public List<ExplicitBlock> ThisReferencesFromChildrenBlock {
+                       get {
+                               return this_references;
+                       }
+               }
+
+               //
+               // Returns the "this" instance variable of this block.
+               // See AddThisVariable() for more information.
+               //
+               public LocalVariable ThisVariable {
+                       get {
+                               return this_variable;
+                       }
+               }
+
                public void AddLocalName (string name, INamedBlockVariable li, bool ignoreChildrenBlocks)
                {
                        if (names == null)
@@ -3047,18 +3250,19 @@ namespace Mono.CSharp {
                        //
                        // A collision checking between local names
                        //
+                       var variable_block = li.Block.Explicit;
                        for (int i = 0; i < existing_list.Count; ++i) {
                                existing = existing_list[i];
                                Block b = existing.Block.Explicit;
 
                                // Collision at same level
-                               if (li.Block.Explicit == b) {
+                               if (variable_block == b) {
                                        li.Block.Error_AlreadyDeclared (name, li);
                                        break;
                                }
 
                                // Collision with parent
-                               Block parent = li.Block.Explicit;
+                               Block parent = variable_block;
                                while ((parent = parent.Parent) != null) {
                                        if (parent == b) {
                                                li.Block.Error_AlreadyDeclared (name, li, "parent or current");
@@ -3067,10 +3271,10 @@ namespace Mono.CSharp {
                                        }
                                }
 
-                               if (!ignoreChildrenBlocks) {
+                               if (!ignoreChildrenBlocks && variable_block.Parent != b.Parent) {
                                        // Collision with children
                                        while ((b = b.Parent) != null) {
-                                               if (li.Block.Explicit == b) {
+                                               if (variable_block == b) {
                                                        li.Block.Error_AlreadyDeclared (name, li, "child");
                                                        i = existing_list.Count;
                                                        break;
@@ -3143,6 +3347,20 @@ namespace Mono.CSharp {
                        existing_list.Add (label);
                }
 
+               public void AddThisReferenceFromChildrenBlock (ExplicitBlock block)
+               {
+                       if (this_references == null)
+                               this_references = new List<ExplicitBlock> ();
+
+                       if (!this_references.Contains (block))
+                               this_references.Add (block);
+               }
+
+               public void RemoveThisReferenceFromChildrenBlock (ExplicitBlock block)
+               {
+                       this_references.Remove (block);
+               }
+
                //
                // Creates an arguments set from all parameters, useful for method proxy calls
                //
@@ -3233,34 +3451,18 @@ namespace Mono.CSharp {
                        if (label != null) {
                                if (label.Block == b.Original)
                                        return label;
-
-                               // TODO: Temporary workaround for the switch block implicit label block
-                               if (label.Block.IsCompilerGenerated && label.Block.Parent == b.Original)
-                                       return label;
                        } else {
                                List<LabeledStatement> list = (List<LabeledStatement>) value;
                                for (int i = 0; i < list.Count; ++i) {
                                        label = list[i];
                                        if (label.Block == b.Original)
                                                return label;
-
-                                       // TODO: Temporary workaround for the switch block implicit label block
-                                       if (label.Block.IsCompilerGenerated && label.Block.Parent == b.Original)
-                                               return label;
                                }
                        }
                                
                        return null;
                }
 
-               // <summary>
-               //   Returns the "this" instance variable of this block.
-               //   See AddThisVariable() for more information.
-               // </summary>
-               public LocalVariable ThisVariable {
-                       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
@@ -3336,10 +3538,10 @@ namespace Mono.CSharp {
                }
        }
        
-       public class SwitchLabel {
+       public class SwitchLabel : Statement
+       {
                Expression label;
                Constant converted;
-               readonly Location loc;
 
                Label? il_label;
 
@@ -3379,6 +3581,8 @@ namespace Mono.CSharp {
                        }
                }
 
+               public bool SectionStart { get; set; }
+
                public Label GetILLabel (EmitContext ec)
                {
                        if (il_label == null){
@@ -3388,6 +3592,18 @@ namespace Mono.CSharp {
                        return il_label.Value;
                }
 
+               protected override void DoEmit (EmitContext ec)
+               {
+                       ec.MarkLabel (GetILLabel (ec));
+               }
+
+               public override bool Resolve (BlockContext bc)
+               {
+                       bc.CurrentBranching.CurrentUsageVector.ResetBarrier ();
+
+                       return base.Resolve (bc);
+               }
+
                //
                // Resolves the expression, reduces it to a literal if possible
                // and then converts it to the requested type.
@@ -3426,36 +3642,19 @@ namespace Mono.CSharp {
                        ec.Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label);
                }
 
-               public SwitchLabel Clone (CloneContext clonectx)
-               {
-                       if (label == null)
-                               return this;
-
-                       return new SwitchLabel (label.Clone (clonectx), loc);
-               }
-       }
-
-       public class SwitchSection {
-               public readonly List<SwitchLabel> Labels;
-               public readonly Block Block;
-               
-               public SwitchSection (List<SwitchLabel> labels, Block block)
+               protected override void CloneTo (CloneContext clonectx, Statement target)
                {
-                       Labels = labels;
-                       Block = block;
+                       var t = (SwitchLabel) target;
+                       if (label != null)
+                               t.label = label.Clone (clonectx);
                }
 
-               public SwitchSection Clone (CloneContext clonectx)
+               public override object Accept (StructuralVisitor visitor)
                {
-                       var cloned_labels = new List<SwitchLabel> ();
-
-                       foreach (SwitchLabel sl in Labels)
-                               cloned_labels.Add (sl.Clone (clonectx));
-                       
-                       return new SwitchSection (cloned_labels, clonectx.LookupBlock (Block));
+                       return visitor.Visit (this);
                }
        }
-       
+
        public class Switch : Statement
        {
                // structure used to hold blocks of keys while calculating table switch
@@ -3508,33 +3707,26 @@ namespace Mono.CSharp {
                        }
                }
 
-               sealed class LabelMarker : Statement
+               sealed class DispatchStatement : Statement
                {
-                       readonly Switch s;
-                       readonly List<SwitchLabel> labels;
+                       readonly Switch body;
 
-                       public LabelMarker (Switch s, List<SwitchLabel> labels)
+                       public DispatchStatement (Switch body)
                        {
-                               this.s = s;
-                               this.labels = labels;
+                               this.body = body;
                        }
 
                        protected override void CloneTo (CloneContext clonectx, Statement target)
                        {
+                               throw new NotImplementedException ();
                        }
 
                        protected override void DoEmit (EmitContext ec)
                        {
-                               foreach (var l in labels) {
-                                       if (l.IsDefault)
-                                               ec.MarkLabel (s.DefaultLabel);
-                                       else
-                                               ec.MarkLabel (l.GetILLabel (ec));
-                               }
+                               body.EmitDispatch (ec);
                        }
                }
 
-               public List<SwitchSection> Sections;
                public Expression Expr;
 
                //
@@ -3542,25 +3734,19 @@ namespace Mono.CSharp {
                //
                Dictionary<long, SwitchLabel> labels;
                Dictionary<string, SwitchLabel> string_labels;
+               List<SwitchLabel> case_labels;
 
                /// <summary>
                ///   The governing switch type
                /// </summary>
                public TypeSpec SwitchType;
 
-               //
-               // Computed
-               //
-               Label default_target;
-               Label null_target;
                Expression new_expr;
-               bool is_constant;
 
-               SwitchSection constant_section;
-               SwitchSection default_section;
-               SwitchLabel null_section;
+               SwitchLabel case_null;
+               SwitchLabel case_default;
 
-               Statement simple_stmt;
+               Label defaultLabel, nullLabel;
                VariableReference value;
                ExpressionStatement string_dictionary;
                FieldExpr switch_cache_field;
@@ -3571,11 +3757,10 @@ namespace Mono.CSharp {
                //
                Nullable.Unwrap unwrap;
 
-               public Switch (Expression e, ExplicitBlock block, List<SwitchSection> sects, Location l)
+               public Switch (Expression e, ExplicitBlock block, Location l)
                {
                        Expr = e;
                        this.block = block;
-                       Sections = sects;
                        loc = l;
                }
 
@@ -3585,15 +3770,9 @@ namespace Mono.CSharp {
                        }
                }
 
-               public Label DefaultLabel {
-                       get {
-                               return default_target;
-                       }
-               }
-
-               public bool GotDefault {
+               public SwitchLabel DefaultLabel {
                        get {
-                               return default_section != null;
+                               return case_default;
                        }
                }
 
@@ -3683,54 +3862,80 @@ namespace Mono.CSharp {
                // It also returns a hashtable with the keys that we will later
                // use to compute the switch tables
                //
-               bool CheckSwitch (ResolveContext ec)
+               bool ResolveLabels (ResolveContext ec, Constant value)
                {
                        bool error = false;
-                       if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String)
-                               string_labels = new Dictionary<string, SwitchLabel> (Sections.Count + 1);
-                       else
-                               labels = new Dictionary<long, SwitchLabel> (Sections.Count + 1);
-                               
-                       foreach (SwitchSection ss in Sections){
-                               foreach (SwitchLabel sl in ss.Labels){
-                                       if (sl.IsDefault){
-                                               if (default_section != null){
-                                                       sl.Error_AlreadyOccurs (ec, SwitchType, default_section.Labels [0]);
-                                                       error = true;
-                                               }
-                                               default_section = ss;
-                                               continue;
-                                       }
+                       if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
+                               string_labels = new Dictionary<string, SwitchLabel> ();
+                       } else {
+                               labels = new Dictionary<long, SwitchLabel> ();
+                       }
 
-                                       if (!sl.ResolveAndReduce (ec, SwitchType, IsNullable)) {
+                       case_labels = new List<SwitchLabel> ();
+                       int default_label_index = -1;
+                       bool constant_label_found = false;
+
+                       for (int i = 0; i < block.Statements.Count; ++i) {
+                               var s = block.Statements[i];
+
+                               var sl = s as SwitchLabel;
+                               if (sl == null) {
+                                       continue;
+                               }
+
+                               case_labels.Add (sl);
+
+                               if (sl.IsDefault) {
+                                       if (case_default != null) {
+                                               sl.Error_AlreadyOccurs (ec, SwitchType, case_default);
                                                error = true;
-                                               continue;
                                        }
-                                       
-                                       try {
-                                               if (string_labels != null) {
-                                                       string s = sl.Converted.GetValue () as string;
-                                                       if (s == null)
-                                                               null_section = sl;
-                                                       else
-                                                               string_labels.Add (s, sl);
+
+                                       default_label_index = i;
+                                       case_default = sl;
+                                       continue;
+                               }
+
+                               if (!sl.ResolveAndReduce (ec, SwitchType, IsNullable)) {
+                                       error = true;
+                                       continue;
+                               }
+
+                               try {
+                                       if (string_labels != null) {
+                                               string string_value = sl.Converted.GetValue () as string;
+                                               if (string_value == null)
+                                                       case_null = sl;
+                                               else
+                                                       string_labels.Add (string_value, sl);
+                                       } else {
+                                               if (sl.Converted is NullLiteral) {
+                                                       case_null = sl;
                                                } else {
-                                                       if (sl.Converted is NullLiteral) {
-                                                               null_section = sl;
-                                                       } else {
-                                                               labels.Add (sl.Converted.GetValueAsLong (), sl);
-                                                       }
+                                                       labels.Add (sl.Converted.GetValueAsLong (), sl);
                                                }
-                                       } catch (ArgumentException) {
-                                               if (string_labels != null)
-                                                       sl.Error_AlreadyOccurs (ec, SwitchType, string_labels[(string) sl.Converted.GetValue ()]);
-                                               else
-                                                       sl.Error_AlreadyOccurs (ec, SwitchType, labels[sl.Converted.GetValueAsLong ()]);
-
-                                               error = true;
                                        }
+                               } catch (ArgumentException) {
+                                       if (string_labels != null)
+                                               sl.Error_AlreadyOccurs (ec, SwitchType, string_labels[(string) sl.Converted.GetValue ()]);
+                                       else
+                                               sl.Error_AlreadyOccurs (ec, SwitchType, labels[sl.Converted.GetValueAsLong ()]);
+
+                                       error = true;
+                               }
+
+                               if (value != null) {
+                                       var constant_label = constant_label_found ? null : FindLabel (value);
+                                       if (constant_label == null || constant_label != sl)
+                                               block.Statements[i] = new EmptyStatement (s.loc);
+                                       else
+                                               constant_label_found = true;
                                }
                        }
+
+                       if (value != null && constant_label_found && default_label_index >= 0)
+                               block.Statements[default_label_index] = new EmptyStatement (case_default.loc);
+
                        return !error;
                }
                
@@ -3743,8 +3948,6 @@ namespace Mono.CSharp {
                //
                void EmitTableSwitch (EmitContext ec, Expression val)
                {
-                       Label lbl_default = default_target;
-
                        if (labels != null && labels.Count > 0) {
                                List<LabelsRange> ranges;
                                if (string_labels != null) {
@@ -3777,17 +3980,21 @@ namespace Mono.CSharp {
                                        ranges.Sort ();
                                }
 
+                               Label lbl_default = defaultLabel;
                                TypeSpec compare_type = SwitchType.IsEnum ? EnumSpec.GetUnderlyingType (SwitchType) : SwitchType;
 
                                for (int range_index = ranges.Count - 1; range_index >= 0; --range_index) {
                                        LabelsRange kb = ranges[range_index];
-                                       lbl_default = (range_index == 0) ? default_target : ec.DefineLabel ();
+                                       lbl_default = (range_index == 0) ? defaultLabel : ec.DefineLabel ();
 
                                        // Optimize small ranges using simple equality check
                                        if (kb.Range <= 2) {
                                                foreach (var key in kb.label_values) {
                                                        SwitchLabel sl = labels[key];
-                                                       if (sl.Converted.IsDefaultValue) {
+                                                       if (sl == case_default || sl == case_null)
+                                                               continue;
+
+                                                       if (sl.Converted.IsZeroInteger) {
                                                                val.EmitBranchable (ec, sl.GetILLabel (ec), false);
                                                        } else {
                                                                val.Emit (ec);
@@ -3858,35 +4065,8 @@ namespace Mono.CSharp {
                                if (ranges.Count > 0)
                                        ec.Emit (OpCodes.Br, lbl_default);
                        }
-
-                       // now emit the code for the sections
-                       bool found_default = false;
-
-                       foreach (SwitchSection ss in Sections) {
-                               foreach (SwitchLabel sl in ss.Labels) {
-                                       if (sl.IsDefault) {
-                                               ec.MarkLabel (lbl_default);
-                                               found_default = true;
-                                               if (null_section == null)
-                                                       ec.MarkLabel (null_target);
-                                       } else if (sl.Converted.IsNull) {
-                                               ec.MarkLabel (null_target);
-                                       }
-
-                                       ec.MarkLabel (sl.GetILLabel (ec));
-                               }
-
-                               ss.Block.Emit (ec);
-                       }
-                       
-                       if (!found_default) {
-                               ec.MarkLabel (lbl_default);
-                               if (null_section == null) {
-                                       ec.MarkLabel (null_target);
-                               }
-                       }
                }
-
+               
                SwitchLabel FindLabel (Constant value)
                {
                        SwitchLabel sl = null;
@@ -3894,16 +4074,16 @@ namespace Mono.CSharp {
                        if (string_labels != null) {
                                string s = value.GetValue () as string;
                                if (s == null) {
-                                       if (null_section != null)
-                                               sl = null_section;
-                                       else if (default_section != null)
-                                               sl = default_section.Labels[0];
+                                       if (case_null != null)
+                                               sl = case_null;
+                                       else if (case_default != null)
+                                               sl = case_default;
                                } else {
                                        string_labels.TryGetValue (s, out sl);
                                }
                        } else {
                                if (value is NullLiteral) {
-                                       sl = null_section;
+                                       sl = case_null;
                                } else {
                                        labels.TryGetValue (value.GetValueAsLong (), out sl);
                                }
@@ -3912,18 +4092,6 @@ namespace Mono.CSharp {
                        return sl;
                }
 
-               SwitchSection FindSection (SwitchLabel label)
-               {
-                       foreach (SwitchSection ss in Sections){
-                               foreach (SwitchLabel sl in ss.Labels){
-                                       if (label == sl)
-                                               return ss;
-                               }
-                       }
-
-                       return null;
-               }
-
                public override bool Resolve (BlockContext ec)
                {
                        Expr = Expr.Resolve (ec);
@@ -3955,58 +4123,45 @@ namespace Mono.CSharp {
                                return false;
                        }
 
-                       if (!CheckSwitch (ec))
-                               return false;
+                       if (block.Statements.Count == 0)
+                               return true;
 
-                       Switch old_switch = ec.Switch;
-                       ec.Switch = this;
-                       ec.Switch.SwitchType = SwitchType;
+                       var constant = new_expr as Constant;
 
-                       ec.StartFlowBranching (FlowBranching.BranchingType.Switch, loc);
+                       if (!ResolveLabels (ec, constant))
+                               return false;
 
-                       var constant = new_expr as Constant;
-                       if (constant != null) {
-                               is_constant = true;
-                               SwitchLabel label = FindLabel (constant);
-                               if (label != null)
-                                       constant_section = FindSection (label);
-
-                               if (constant_section == null)
-                                       constant_section = default_section;
-                       } else {
+                       //
+                       // Don't need extra variable for constant switch or switch with
+                       // only default case
+                       //
+                       if (constant == null && (case_labels.Count - (case_default != null ? 1 : 0)) != 0) {
                                //
-                               // Store switch expression for comparission purposes
+                               // Store switch expression for comparison purposes
                                //
                                value = new_expr as VariableReference;
-                               if (value == null)
+                               if (value == null) {
+                                       // Create temporary variable inside switch scope
+                                       var current_block = ec.CurrentBlock;
+                                       ec.CurrentBlock = Block;
                                        value = TemporaryVariableReference.Create (SwitchType, ec.CurrentBlock, loc);
+                                       value.Resolve (ec);
+                                       ec.CurrentBlock = current_block;
+                               }
                        }
 
-                       bool first = true;
-                       bool ok = true;
-                       foreach (SwitchSection ss in Sections){
-                               if (!first)
-                                       ec.CurrentBranching.CreateSibling (
-                                               null, FlowBranching.SiblingType.SwitchSection);
-                               else
-                                       first = false;
+                       Switch old_switch = ec.Switch;
+                       ec.Switch = this;
+                       ec.Switch.SwitchType = SwitchType;
 
-                               if (is_constant && (ss != constant_section)) {
-                                       // If we're a constant switch, we're only emitting
-                                       // one single section - mark all the others as
-                                       // unreachable.
-                                       ec.CurrentBranching.CurrentUsageVector.Goto ();
-                                       if (!ss.Block.ResolveUnreachable (ec, true)) {
-                                               ok = false;
-                                       }
-                               } else {
-                                       if (!ss.Block.Resolve (ec))
-                                               ok = false;
-                               }
-                       }
+                       ec.StartFlowBranching (FlowBranching.BranchingType.Switch, loc);
+
+                       ec.CurrentBranching.CurrentUsageVector.Goto ();
 
-                       if (default_section == null)
-                               ec.CurrentBranching.CreateSibling (null, FlowBranching.SiblingType.SwitchSection);
+                       var ok = block.Resolve (ec);
+
+                       if (case_default == null)
+                               ec.CurrentBranching.CurrentUsageVector.ResetBarrier ();
 
                        ec.EndFlowBranching ();
                        ec.Switch = old_switch;
@@ -4014,17 +4169,16 @@ namespace Mono.CSharp {
                        if (!ok)
                                return false;
 
-                       if (!is_constant) {
-                               if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
-                                       if (string_labels.Count < 7)
-                                               ResolveSimpleSwitch (ec);
-                                       else
-                                               ResolveStringSwitchMap (ec);
-                               } else if (labels.Count < 3 && !IsNullable) {
-                                       ResolveSimpleSwitch (ec);
-                               }
+                       if (constant == null && SwitchType.BuiltinType == BuiltinTypeSpec.Type.String && string_labels.Count > 6) {
+                               ResolveStringSwitchMap (ec);
                        }
 
+                       //
+                       // Needed to emit anonymous storey initialization before
+                       // any generated switch dispatch
+                       //
+                       block.AddScopeStatement (new DispatchStatement (this));
+
                        return true;
                }
 
@@ -4039,45 +4193,6 @@ namespace Mono.CSharp {
                        return sl;
                }
 
-               //
-               // Prepares switch using simple if/else comparison for small label count (4 + optional default)
-               //
-               void ResolveSimpleSwitch (BlockContext bc)
-               {
-                       simple_stmt = default_section != null ? default_section.Block : null;
-
-                       for (int i = Sections.Count - 1; i >= 0; --i) {
-                               var s = Sections[i];
-
-                               if (s == default_section) {
-                                       s.Block.AddScopeStatement (new LabelMarker (this, s.Labels));
-                                       continue;
-                               }
-
-                               s.Block.AddScopeStatement (new LabelMarker (this, s.Labels));
-
-                               Expression cond = null;
-                               for (int ci = 0; ci < s.Labels.Count; ++ci) {
-                                       var e = new Binary (Binary.Operator.Equality, value, s.Labels[ci].Converted, loc);
-
-                                       if (ci > 0) {
-                                               cond = new Binary (Binary.Operator.LogicalOr, cond, e, loc);
-                                       } else {
-                                               cond = e;
-                                       }
-                               }
-
-                               //
-                               // Compiler generated, hide from symbol file
-                               //
-                               simple_stmt = new If (cond, s.Block, simple_stmt, Location.Null);
-                       }
-
-                       // It's null for empty switch
-                       if (simple_stmt != null)
-                               simple_stmt.Resolve (bc);
-               }
-
                //
                // Converts string switch into string hashtable
                //
@@ -4099,43 +4214,34 @@ namespace Mono.CSharp {
                        var ctype = ec.CurrentMemberDefinition.Parent.PartialContainer;
                        Field field = new Field (ctype, string_dictionary_type,
                                Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
-                               new MemberName (CompilerGeneratedClass.MakeName (null, "f", "switch$map", ec.Module.CounterSwitchTypes++), loc), null);
+                               new MemberName (CompilerGeneratedContainer.MakeName (null, "f", "switch$map", ec.Module.CounterSwitchTypes++), loc), null);
                        if (!field.Define ())
                                return;
                        ctype.AddField (field);
 
                        var init = new List<Expression> ();
-                       int counter = 0;
+                       int counter = -1;
                        labels = new Dictionary<long, SwitchLabel> (string_labels.Count);
                        string value = null;
-                       foreach (SwitchSection section in Sections) {
-                               bool contains_label = false;
-                               foreach (SwitchLabel sl in section.Labels) {
-                                       if (sl.IsDefault || sl.Converted.IsNull)
-                                               continue;
 
-                                       if (!contains_label) {
-                                               labels.Add (counter, sl);
-                                               contains_label = true;
-                                       }
+                       foreach (SwitchLabel sl in case_labels) {
 
-                                       value = (string) sl.Converted.GetValue ();
-                                       var init_args = new List<Expression> (2);
-                                       init_args.Add (new StringLiteral (ec.BuiltinTypes, value, sl.Location));
+                               if (sl.SectionStart)
+                                       labels.Add (++counter, sl);
 
-                                       sl.Converted = new IntConstant (ec.BuiltinTypes, counter, loc);
-                                       init_args.Add (sl.Converted);
+                               if (sl == case_default || sl == case_null)
+                                       continue;
 
-                                       init.Add (new CollectionElementInitializer (init_args, loc));
-                               }
+                               value = (string) sl.Converted.GetValue ();
+                               var init_args = new List<Expression> (2);
+                               init_args.Add (new StringLiteral (ec.BuiltinTypes, value, sl.Location));
 
-                               //
-                               // Don't add empty sections
-                               //
-                               if (contains_label)
-                                       ++counter;
-                       }
+                               sl.Converted = new IntConstant (ec.BuiltinTypes, counter, loc);
+                               init_args.Add (sl.Converted);
 
+                               init.Add (new CollectionElementInitializer (init_args, loc));
+                       }
+       
                        Arguments args = new Arguments (1);
                        args.Add (new Argument (new IntConstant (ec.BuiltinTypes, init.Count, loc)));
                        Expression initializer = new NewInitialize (string_dictionary_type, args,
@@ -4152,7 +4258,7 @@ namespace Mono.CSharp {
                        //
                        // Skip initialization when value is null
                        //
-                       value.EmitBranchable (ec, null_target, false);
+                       value.EmitBranchable (ec, nullLabel, false);
 
                        //
                        // Check if string dictionary is initialized and initialize
@@ -4178,7 +4284,7 @@ namespace Mono.CSharp {
                                //
                                // A value was not found, go to default case
                                //
-                               get_item.EmitBranchable (ec, default_target, false);
+                               get_item.EmitBranchable (ec, defaultLabel, false);
                        } else {
                                Arguments get_value_args = new Arguments (1);
                                get_value_args.Add (new Argument (value));
@@ -4189,7 +4295,7 @@ namespace Mono.CSharp {
 
                                LocalTemporary get_item_object = new LocalTemporary (ec.BuiltinTypes.Object);
                                get_item_object.EmitAssign (ec, get_item, true, false);
-                               ec.Emit (OpCodes.Brfalse, default_target);
+                               ec.Emit (OpCodes.Brfalse, defaultLabel);
 
                                ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable,
                                        new Cast (new TypeExpression (ec.BuiltinTypes.Int, loc), get_item_object, loc)).Resolve (rc);
@@ -4202,49 +4308,104 @@ namespace Mono.CSharp {
                        string_switch_variable.Release (ec);
                }
 
-               protected override void DoEmit (EmitContext ec)
+               //
+               // Emits switch using simple if/else comparison for small label count (4 + optional default)
+               //
+               void EmitShortSwitch (EmitContext ec)
                {
-                       // Workaround broken flow-analysis
-                       block.HasUnreachableClosingBrace = true;
+                       MethodSpec equal_method = null;
+                       if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
+                               equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (loc);
+                       }
+
+                       if (equal_method != null) {
+                               value.EmitBranchable (ec, nullLabel, false);
+                       }
+
+                       for (int i = 0; i < case_labels.Count; ++i) {
+                               var label = case_labels [i];
+                               if (label == case_default || label == case_null)
+                                       continue;
+
+                               var constant = label.Converted;
+
+                               if (equal_method != null) {
+                                       value.Emit (ec);
+                                       constant.Emit (ec);
+
+                                       var call = new CallEmitter ();
+                                       call.EmitPredefined (ec, equal_method, new Arguments (0));
+                                       ec.Emit (OpCodes.Brtrue, label.GetILLabel (ec));
+                                       continue;
+                               }
+
+                               if (constant.IsZeroInteger && constant.Type.BuiltinType != BuiltinTypeSpec.Type.Long && constant.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
+                                       value.EmitBranchable (ec, label.GetILLabel (ec), false);
+                                       continue;
+                               }
+
+                               value.Emit (ec);
+                               constant.Emit (ec);
+                               ec.Emit (OpCodes.Beq, label.GetILLabel (ec));
+                       }
+
+                       ec.Emit (OpCodes.Br, defaultLabel);
+               }
+
+               void EmitDispatch (EmitContext ec)
+               {
+                       if (value == null) {
+                               //
+                               // Constant switch, we already done the work
+                               //
+                               return;
+                       }
 
                        //
-                       // Needed to emit anonymous storey initialization
-                       // Otherwise it does not contain any statements for now
+                       // Mark sequence point explicitly to switch
                        //
-                       block.Emit (ec);
+                       ec.Mark (block.StartLocation);
+                       block.IsCompilerGenerated = true;
 
-                       default_target = ec.DefineLabel ();
-                       null_target = ec.DefineLabel ();
-
-                       if (IsNullable) {
-                               unwrap.EmitCheck (ec);
-                               ec.Emit (OpCodes.Brfalse, null_target);
-                               value.EmitAssign (ec, new_expr, false, false);
-                       } else if (new_expr != value && !is_constant) {
-                               value.EmitAssign (ec, new_expr, false, false);
+                       if (string_dictionary != null) {
+                               DoEmitStringSwitch (ec);
+                       } else if (case_labels.Count < 4 || string_labels != null) {
+                               EmitShortSwitch (ec);
+                       } else {
+                               EmitTableSwitch (ec, value);
                        }
+               }
+
+               protected override void DoEmit (EmitContext ec)
+               {
+                       // Workaround broken flow-analysis
+                       block.HasUnreachableClosingBrace = true;
 
                        //
                        // Setup the codegen context
                        //
                        Label old_end = ec.LoopEnd;
                        Switch old_switch = ec.Switch;
-                       
+
                        ec.LoopEnd = ec.DefineLabel ();
                        ec.Switch = this;
 
-                       // Emit Code.
-                       if (is_constant) {
-                               if (constant_section != null)
-                                       constant_section.Block.Emit (ec);
-                       } else if (string_dictionary != null) {
-                               DoEmitStringSwitch (ec);
-                       } else if (simple_stmt != null) {
-                               simple_stmt.Emit (ec);
-                       } else {
-                               EmitTableSwitch (ec, value);
+                       defaultLabel = case_default == null ? ec.LoopEnd : case_default.GetILLabel (ec);
+                       nullLabel = case_null == null ? defaultLabel : case_null.GetILLabel (ec);
+
+                       if (value != null) {
+                               ec.Mark (loc);
+                               if (IsNullable) {
+                                       unwrap.EmitCheck (ec);
+                                       ec.Emit (OpCodes.Brfalse, nullLabel);
+                                       value.EmitAssign (ec, new_expr, false, false);
+                               } else if (new_expr != value) {
+                                       value.EmitAssign (ec, new_expr, false, false);
+                               }
                        }
 
+                       block.Emit (ec);
+
                        // Restore context state. 
                        ec.MarkLabel (ec.LoopEnd);
 
@@ -4260,10 +4421,7 @@ namespace Mono.CSharp {
                        Switch target = (Switch) t;
 
                        target.Expr = Expr.Clone (clonectx);
-                       target.Sections = new List<SwitchSection> ();
-                       foreach (SwitchSection ss in Sections){
-                               target.Sections.Add (ss.Clone (clonectx));
-                       }
+                       target.block = (ExplicitBlock) block.Clone (clonectx);
                }
                
                public override object Accept (StructuralVisitor visitor)
@@ -4302,6 +4460,7 @@ namespace Mono.CSharp {
                protected Statement stmt;
                Label dispose_try_block;
                bool prepared_for_dispose, emitted_dispose;
+               Method finally_host;
 
                protected TryFinallyBlock (Statement stmt, Location loc)
                        : base (loc)
@@ -4320,7 +4479,7 @@ namespace Mono.CSharp {
                #endregion
 
                protected abstract void EmitTryBody (EmitContext ec);
-               protected abstract void EmitFinallyBody (EmitContext ec);
+               public abstract void EmitFinallyBody (EmitContext ec);
 
                public override Label PrepareForDispose (EmitContext ec, Label end)
                {
@@ -4348,7 +4507,20 @@ namespace Mono.CSharp {
                        }
 
                        ec.MarkLabel (start_finally);
-                       EmitFinallyBody (ec);
+
+                       if (finally_host != null) {
+                               finally_host.Define ();
+                               finally_host.Emit ();
+
+                               // Now it's safe to add, to close it properly and emit sequence points
+                               finally_host.Parent.AddMember (finally_host);
+
+                               var ce = new CallEmitter ();
+                               ce.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
+                               ce.EmitPredefined (ec, finally_host.Spec, new Arguments (0));
+                       } else {
+                               EmitFinallyBody (ec);
+                       }
 
                        ec.EndExceptionBlock ();
                }
@@ -4392,12 +4564,10 @@ namespace Mono.CSharp {
                                bool emit_dispatcher = j < labels.Length;
 
                                if (emit_dispatcher) {
-                                       //SymbolWriter.StartIteratorDispatcher (ec.ig);
                                        ec.Emit (OpCodes.Ldloc, pc);
                                        ec.EmitInt (first_resume_pc);
                                        ec.Emit (OpCodes.Sub);
                                        ec.Emit (OpCodes.Switch, labels);
-                                       //SymbolWriter.EndIteratorDispatcher (ec.ig);
                                }
 
                                foreach (ResumableStatement s in resume_points)
@@ -4408,10 +4578,34 @@ namespace Mono.CSharp {
 
                        ec.BeginFinallyBlock ();
 
-                       EmitFinallyBody (ec);
+                       if (finally_host != null) {
+                               var ce = new CallEmitter ();
+                               ce.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
+                               ce.EmitPredefined (ec, finally_host.Spec, new Arguments (0));
+                       } else {
+                               EmitFinallyBody (ec);
+                       }
 
                        ec.EndExceptionBlock ();
                }
+
+               public override bool Resolve (BlockContext bc)
+               {
+                       //
+                       // Finally block inside iterator is called from MoveNext and
+                       // Dispose methods that means we need to lift the block into
+                       // newly created host method to emit the body only once. The
+                       // original block then simply calls the newly generated method.
+                       //
+                       if (bc.CurrentIterator != null && !bc.IsInProbingMode) {
+                               var b = stmt as Block;
+                               if (b != null && b.Explicit.HasYield) {
+                                       finally_host = bc.CurrentIterator.CreateFinallyHost (this);
+                               }
+                       }
+
+                       return base.Resolve (bc);
+               }
        }
 
        //
@@ -4535,21 +4729,9 @@ namespace Mono.CSharp {
                                locked = false;
                        }
 
-                       using (ec.Set (ResolveContext.Options.LockScope)) {
-                               ec.StartFlowBranching (this);
-                               Statement.Resolve (ec);
-                               ec.EndFlowBranching ();
-                       }
-
-                       if (lv != null) {
-                               lv.IsLockedByStatement = locked;
-                       }
-
-                       base.Resolve (ec);
-
                        //
                        // Have to keep original lock value around to unlock same location
-                       // in the case the original has changed or is null
+                       // in the case of original value has changed or is null
                        //
                        expr_copy = TemporaryVariableReference.Create (ec.BuiltinTypes.Object, ec.CurrentBlock, loc);
                        expr_copy.Resolve (ec);
@@ -4562,6 +4744,18 @@ namespace Mono.CSharp {
                                lock_taken.Resolve (ec);
                        }
 
+                       using (ec.Set (ResolveContext.Options.LockScope)) {
+                               ec.StartFlowBranching (this);
+                               Statement.Resolve (ec);
+                               ec.EndFlowBranching ();
+                       }
+
+                       if (lv != null) {
+                               lv.IsLockedByStatement = locked;
+                       }
+
+                       base.Resolve (ec);
+
                        return true;
                }
                
@@ -4600,7 +4794,7 @@ namespace Mono.CSharp {
                        Statement.Emit (ec);
                }
 
-               protected override void EmitFinallyBody (EmitContext ec)
+               public override void EmitFinallyBody (EmitContext ec)
                {
                        //
                        // if (lock_taken) Monitor.Exit (expr_copy)
@@ -4915,8 +5109,8 @@ namespace Mono.CSharp {
                                        // fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0])
                                        //
                                        converted = new Conditional (new BooleanExpression (new Binary (Binary.Operator.LogicalOr,
-                                               new Binary (Binary.Operator.Equality, initializer, new NullLiteral (loc), loc),
-                                               new Binary (Binary.Operator.Equality, new MemberAccess (initializer, "Length"), new IntConstant (bc.BuiltinTypes, 0, loc), loc), loc)),
+                                               new Binary (Binary.Operator.Equality, initializer, new NullLiteral (loc)),
+                                               new Binary (Binary.Operator.Equality, new MemberAccess (initializer, "Length"), new IntConstant (bc.BuiltinTypes, 0, loc)))),
                                                        new NullLiteral (loc),
                                                        converted, loc);
 
@@ -5194,6 +5388,7 @@ namespace Mono.CSharp {
 
                        if (ok)
                                ec.CurrentBranching.CreateSibling (fini, FlowBranching.SiblingType.Finally);
+
                        using (ec.With (ResolveContext.Options.FinallyScope, true)) {
                                if (!fini.Resolve (ec))
                                        ok = false;
@@ -5211,7 +5406,7 @@ namespace Mono.CSharp {
                        stmt.Emit (ec);
                }
 
-               protected override void EmitFinallyBody (EmitContext ec)
+               public override void EmitFinallyBody (EmitContext ec)
                {
                        fini.Emit (ec);
                }
@@ -5473,7 +5668,7 @@ namespace Mono.CSharp {
 
                                // Add conditional call when disposing possible null variable
                                if (!type.IsStruct || type.IsNullableType)
-                                       dispose = new If (new Binary (Binary.Operator.Inequality, lvr, new NullLiteral (loc), loc), dispose, dispose.loc);
+                                       dispose = new If (new Binary (Binary.Operator.Inequality, lvr, new NullLiteral (loc)), dispose, dispose.loc);
 
                                return dispose;
                        }
@@ -5487,7 +5682,7 @@ namespace Mono.CSharp {
                        {
                                for (int i = declarators.Count - 1; i >= 0; --i) {
                                        var d = declarators [i];
-                                       var vd = new VariableDeclaration (d.Variable, type_expr.Location);
+                                       var vd = new VariableDeclaration (d.Variable, d.Variable.Location);
                                        vd.Initializer = d.Initializer;
                                        vd.IsNested = true;
                                        vd.dispose_call = CreateDisposeCall (bc, d.Variable);
@@ -5555,7 +5750,7 @@ namespace Mono.CSharp {
                        stmt.Emit (ec);
                }
 
-               protected override void EmitFinallyBody (EmitContext ec)
+               public override void EmitFinallyBody (EmitContext ec)
                {
                        decl.EmitDispose (ec);
                }
@@ -5621,27 +5816,43 @@ namespace Mono.CSharp {
        /// </summary>
        public class Foreach : Statement
        {
-               sealed class ArrayForeach : Statement
+               abstract class IteratorStatement : Statement
                {
-                       readonly Foreach for_each;
-                       readonly Statement statement;
+                       protected readonly Foreach for_each;
+
+                       protected IteratorStatement (Foreach @foreach)
+                       {
+                               this.for_each = @foreach;
+                               this.loc = @foreach.expr.Location;
+                       }
+
+                       protected override void CloneTo (CloneContext clonectx, Statement target)
+                       {
+                               throw new NotImplementedException ();
+                       }
+
+                       public override void Emit (EmitContext ec)
+                       {
+                               if (ec.EmitAccurateDebugInfo) {
+                                       ec.Emit (OpCodes.Nop);
+                               }
 
-                       Expression conv;
+                               base.Emit (ec);
+                       }
+               }
+
+               sealed class ArrayForeach : IteratorStatement
+               {
                        TemporaryVariableReference[] lengths;
                        Expression [] length_exprs;
                        StatementExpression[] counter;
                        TemporaryVariableReference[] variables;
 
                        TemporaryVariableReference copy;
-                       Expression access;
-                       LocalVariableReference variable;
 
                        public ArrayForeach (Foreach @foreach, int rank)
+                               : base (@foreach)
                        {
-                               for_each = @foreach;
-                               statement = for_each.statement;
-                               loc = @foreach.loc;
-
                                counter = new StatementExpression[rank];
                                variables = new TemporaryVariableReference[rank];
                                length_exprs = new Expression [rank];
@@ -5654,11 +5865,6 @@ namespace Mono.CSharp {
                                        lengths = new TemporaryVariableReference [rank];
                        }
 
-                       protected override void CloneTo (CloneContext clonectx, Statement target)
-                       {
-                               throw new NotImplementedException ();
-                       }
-
                        public override bool Resolve (BlockContext ec)
                        {
                                Block variables_block = for_each.variable.Block;
@@ -5670,7 +5876,7 @@ namespace Mono.CSharp {
                                for (int i = 0; i < rank; i++) {
                                        var v = TemporaryVariableReference.Create (ec.BuiltinTypes.Int, variables_block, loc);
                                        variables[i] = v;
-                                       counter[i] = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, v, loc));
+                                       counter[i] = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, v, Location.Null));
                                        counter[i].Resolve (ec);
 
                                        if (rank == 1) {
@@ -5687,7 +5893,7 @@ namespace Mono.CSharp {
                                        list.Add (new Argument (v));
                                }
 
-                               access = new ElementAccess (copy, list, loc).Resolve (ec);
+                               var access = new ElementAccess (copy, list, loc).Resolve (ec);
                                if (access == null)
                                        return false;
 
@@ -5697,26 +5903,30 @@ namespace Mono.CSharp {
                                        var_type = access.Type;
                                } else {
                                        var_type = for_each.type.ResolveAsType (ec);
+
+                                       if (var_type == null)
+                                               return false;
+
+                                       access = Convert.ExplicitConversion (ec, access, var_type, loc);
+                                       if (access == null)
+                                               return false;
                                }
 
-                               if (var_type == null)
-                                       return false;
+                               for_each.variable.Type = var_type;
 
-                               conv = Convert.ExplicitConversion (ec, access, var_type, loc);
-                               if (conv == null)
+                               var variable_ref = new LocalVariableReference (for_each.variable, loc).Resolve (ec);
+                               if (variable_ref == null)
                                        return false;
 
+                               for_each.body.AddScopeStatement (new StatementExpression (new CompilerAssign (variable_ref, access, Location.Null), for_each.type.Location));
+
                                bool ok = true;
 
                                ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
                                ec.CurrentBranching.CreateSibling ();
 
-                               for_each.variable.Type = conv.Type;
-                               variable = new LocalVariableReference (for_each.variable, loc);
-                               variable.Resolve (ec);
-
                                ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
-                               if (!statement.Resolve (ec))
+                               if (!for_each.body.Resolve (ec))
                                        ok = false;
                                ec.EndFlowBranching ();
 
@@ -5752,12 +5962,10 @@ namespace Mono.CSharp {
                                        ec.MarkLabel (loop [i]);
                                }
 
-                               variable.local_info.CreateBuilder (ec);
-                               variable.EmitAssign (ec, conv, false, false);
-
-                               statement.Emit (ec);
+                               for_each.body.Emit (ec);
 
                                ec.MarkLabel (ec.LoopBegin);
+                               ec.Mark (for_each.expr.Location);
 
                                for (int i = rank - 1; i >= 0; i--){
                                        counter [i].Emit (ec);
@@ -5777,59 +5985,8 @@ namespace Mono.CSharp {
                        }
                }
 
-               sealed class CollectionForeach : Statement, OverloadResolver.IErrorHandler
+               sealed class CollectionForeach : IteratorStatement, OverloadResolver.IErrorHandler
                {
-                       class Body : Statement
-                       {
-                               TypeSpec type;
-                               LocalVariableReference variable;
-                               Expression current, conv;
-                               Statement statement;
-
-                               public Body (TypeSpec type, LocalVariable variable,
-                                                                  Expression current, Statement statement,
-                                                                  Location loc)
-                               {
-                                       this.type = type;
-                                       this.variable = new LocalVariableReference (variable, loc);
-                                       this.current = current;
-                                       this.statement = statement;
-                                       this.loc = loc;
-                               }
-
-                               protected override void CloneTo (CloneContext clonectx, Statement target)
-                               {
-                                       throw new NotImplementedException ();
-                               }
-
-                               public override bool Resolve (BlockContext ec)
-                               {
-                                       current = current.Resolve (ec);
-                                       if (current == null)
-                                               return false;
-
-                                       conv = Convert.ExplicitConversion (ec, current, type, loc);
-                                       if (conv == null)
-                                               return false;
-
-                                       variable.local_info.Type = conv.Type;
-                                       variable.Resolve (ec);
-
-                                       if (!statement.Resolve (ec))
-                                               return false;
-
-                                       return true;
-                               }
-
-                               protected override void DoEmit (EmitContext ec)
-                               {
-                                       variable.local_info.CreateBuilder (ec);
-                                       variable.EmitAssign (ec, conv, false, false);
-
-                                       statement.Emit (ec);
-                               }
-                       }
-
                        class RuntimeDispose : Using.VariableDeclaration
                        {
                                public RuntimeDispose (LocalVariable lv, Location loc)
@@ -5857,7 +6014,7 @@ namespace Mono.CSharp {
                                        var idisaposable_test = new Binary (Binary.Operator.Inequality, new CompilerAssign (
                                                dispose_variable.CreateReferenceExpression (bc, loc),
                                                new As (lv.CreateReferenceExpression (bc, loc), new TypeExpression (dispose_variable.Type, loc), loc),
-                                               loc), new NullLiteral (loc), loc);
+                                               loc), new NullLiteral (loc));
 
                                        var m = bc.Module.PredefinedMembers.IDisposableDispose.Resolve (loc);
 
@@ -5872,23 +6029,15 @@ namespace Mono.CSharp {
                        LocalVariable variable;
                        Expression expr;
                        Statement statement;
-                       Expression var_type;
                        ExpressionStatement init;
                        TemporaryVariableReference enumerator_variable;
                        bool ambiguous_getenumerator_name;
 
-                       public CollectionForeach (Expression var_type, LocalVariable var, Expression expr, Statement stmt, Location l)
+                       public CollectionForeach (Foreach @foreach, LocalVariable var, Expression expr)
+                               : base (@foreach)
                        {
-                               this.var_type = var_type;
                                this.variable = var;
                                this.expr = expr;
-                               statement = stmt;
-                               loc = l;
-                       }
-
-                       protected override void CloneTo (CloneContext clonectx, Statement target)
-                       {
-                               throw new NotImplementedException ();
                        }
 
                        void Error_WrongEnumerator (ResolveContext rc, MethodSpec enumerator)
@@ -5911,7 +6060,7 @@ namespace Mono.CSharp {
                                if (mg != null) {
                                        mg.InstanceExpression = expr;
                                        Arguments args = new Arguments (0);
-                                       mg = mg.OverloadResolve (rc, ref args, this, OverloadResolver.Restrictions.None);
+                                       mg = mg.OverloadResolve (rc, ref args, this, OverloadResolver.Restrictions.ProbingOnly);
 
                                        // For ambiguous GetEnumerator name warning CS0278 was reported, but Option 2 could still apply
                                        if (ambiguous_getenumerator_name)
@@ -5932,39 +6081,31 @@ namespace Mono.CSharp {
                                if (!gen_ienumerable.Define ())
                                        gen_ienumerable = null;
 
-                               do {
-                                       var ifaces = t.Interfaces;
-                                       if (ifaces != null) {
-                                               foreach (var iface in ifaces) {
-                                                       if (gen_ienumerable != null && iface.MemberDefinition == gen_ienumerable.TypeSpec.MemberDefinition) {
-                                                               if (iface_candidate != null && iface_candidate != rc.Module.PredefinedMembers.IEnumerableGetEnumerator) {
-                                                                       rc.Report.SymbolRelatedToPreviousError (expr.Type);
-                                                                       rc.Report.Error (1640, loc,
-                                                                               "foreach statement cannot operate on variables of type `{0}' because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
-                                                                               expr.Type.GetSignatureForError (), gen_ienumerable.TypeSpec.GetSignatureForError ());
-
-                                                                       return null;
-                                                               }
-
-                                                               // TODO: Cache this somehow
-                                                               iface_candidate = new PredefinedMember<MethodSpec> (rc.Module, iface,
-                                                                       MemberFilter.Method ("GetEnumerator", 0, ParametersCompiled.EmptyReadOnlyParameters, null));
-
-                                                               continue;
+                               var ifaces = t.Interfaces;
+                               if (ifaces != null) {
+                                       foreach (var iface in ifaces) {
+                                               if (gen_ienumerable != null && iface.MemberDefinition == gen_ienumerable.TypeSpec.MemberDefinition) {
+                                                       if (iface_candidate != null && iface_candidate != rc.Module.PredefinedMembers.IEnumerableGetEnumerator) {
+                                                               rc.Report.SymbolRelatedToPreviousError (expr.Type);
+                                                               rc.Report.Error (1640, loc,
+                                                                       "foreach statement cannot operate on variables of type `{0}' because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
+                                                                       expr.Type.GetSignatureForError (), gen_ienumerable.TypeSpec.GetSignatureForError ());
+
+                                                               return null;
                                                        }
 
-                                                       if (iface.BuiltinType == BuiltinTypeSpec.Type.IEnumerable && iface_candidate == null) {
-                                                               iface_candidate = rc.Module.PredefinedMembers.IEnumerableGetEnumerator;
-                                                       }
-                                               }
-                                       }
+                                                       // TODO: Cache this somehow
+                                                       iface_candidate = new PredefinedMember<MethodSpec> (rc.Module, iface,
+                                                               MemberFilter.Method ("GetEnumerator", 0, ParametersCompiled.EmptyReadOnlyParameters, null));
 
-                                       if (t.IsGenericParameter)
-                                               t = t.BaseType;
-                                       else
-                                               t = null;
+                                                       continue;
+                                               }
 
-                               } while (t != null);
+                                               if (iface.BuiltinType == BuiltinTypeSpec.Type.IEnumerable && iface_candidate == null) {
+                                                       iface_candidate = rc.Module.PredefinedMembers.IEnumerableGetEnumerator;
+                                               }
+                                       }
+                               }
 
                                if (iface_candidate == null) {
                                        if (expr.Type != InternalType.ErrorType) {
@@ -6050,7 +6191,7 @@ namespace Mono.CSharp {
                                if (current_pe == null)
                                        return false;
 
-                               VarExpr ve = var_type as VarExpr;
+                               VarExpr ve = for_each.type as VarExpr;
 
                                if (ve != null) {
                                        if (is_dynamic) {
@@ -6066,16 +6207,26 @@ namespace Mono.CSharp {
                                                current_pe = EmptyCast.Create (current_pe, ec.BuiltinTypes.Dynamic);
                                        }
 
-                                       variable.Type = var_type.ResolveAsType (ec);
+                                       variable.Type = for_each.type.ResolveAsType (ec);
+
+                                       if (variable.Type == null)
+                                               return false;
+
+                                       current_pe = Convert.ExplicitConversion (ec, current_pe, variable.Type, loc);
+                                       if (current_pe == null)
+                                               return false;
                                }
 
-                               if (variable.Type == null)
+                               var variable_ref = new LocalVariableReference (variable, loc).Resolve (ec);
+                               if (variable_ref == null)
                                        return false;
 
+                               for_each.body.AddScopeStatement (new StatementExpression (new CompilerAssign (variable_ref, current_pe, Location.Null), for_each.type.Location));
+
                                var init = new Invocation (get_enumerator_mg, null);
 
                                statement = new While (new BooleanExpression (new Invocation (move_next_mg, null)),
-                                       new Body (variable.Type, variable, current_pe, statement, variable.Location), Location.Null);
+                                        for_each.body, Location.Null);
 
                                var enum_type = enumerator_variable.Type;
 
@@ -6155,13 +6306,15 @@ namespace Mono.CSharp {
                LocalVariable variable;
                Expression expr;
                Statement statement;
+               Block body;
 
-               public Foreach (Expression type, LocalVariable var, Expression expr, Statement stmt, Location l)
+               public Foreach (Expression type, LocalVariable var, Expression expr, Statement stmt, Block body, Location l)
                {
                        this.type = type;
                        this.variable = var;
                        this.expr = expr;
-                       statement = stmt;
+                       this.statement = stmt;
+                       this.body = body;
                        loc = l;
                }
 
@@ -6181,7 +6334,6 @@ namespace Mono.CSharp {
                        get { return variable; }
                }
 
-
                public override bool Resolve (BlockContext ec)
                {
                        expr = expr.Resolve (ec);
@@ -6193,6 +6345,8 @@ namespace Mono.CSharp {
                                return false;
                        }
 
+                       body.AddStatement (statement);
+
                        if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.String) {
                                statement = new ArrayForeach (this, 1);
                        } else if (expr.Type is ArrayContainer) {
@@ -6204,7 +6358,7 @@ namespace Mono.CSharp {
                                        return false;
                                }
 
-                               statement = new CollectionForeach (type, variable, expr, statement, loc);
+                               statement = new CollectionForeach (this, variable, expr);
                        }
 
                        return statement.Resolve (ec);
@@ -6212,6 +6366,8 @@ namespace Mono.CSharp {
 
                protected override void DoEmit (EmitContext ec)
                {
+                       variable.CreateBuilder (ec);
+
                        Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
                        ec.LoopBegin = ec.DefineLabel ();
                        ec.LoopEnd = ec.DefineLabel ();
@@ -6228,6 +6384,7 @@ namespace Mono.CSharp {
 
                        target.type = type.Clone (clonectx);
                        target.expr = expr.Clone (clonectx);
+                       target.body = (Block) body.Clone (clonectx);
                        target.statement = statement.Clone (clonectx);
                }