[csharp] repl using statement fix + support for --fatal
[mono.git] / mcs / mcs / statement.cs
index 38a7529f89242fb61d8e95671044b6ca6bc12fc9..a639157ca423b056545d341371a7e0bbb9c73f82 100644 (file)
 //
 
 using System;
-using System.Text;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Diagnostics;
 using System.Collections.Generic;
 
+#if STATIC
+using IKVM.Reflection.Emit;
+#else
+using System.Reflection.Emit;
+#endif
+
 namespace Mono.CSharp {
        
        public abstract class Statement {
@@ -632,6 +634,55 @@ namespace Mono.CSharp {
                }
        }
 
+       //
+       // Simple version of statement list not requiring a block
+       //
+       public class StatementList : Statement
+       {
+               List<Statement> statements;
+
+               public StatementList (Statement first, Statement second)
+               {
+                       statements = new List<Statement> () { first, second };
+               }
+
+               #region Properties
+               public IList<Statement> Statements {
+                       get {
+                               return statements;
+                       }
+               }
+               #endregion
+
+               public void Add (Statement statement)
+               {
+                       statements.Add (statement);
+               }
+
+               public override bool Resolve (BlockContext ec)
+               {
+                       foreach (var s in statements)
+                               s.Resolve (ec);
+
+                       return true;
+               }
+
+               protected override void DoEmit (EmitContext ec)
+               {
+                       foreach (var s in statements)
+                               s.Emit (ec);
+               }
+
+               protected override void CloneTo (CloneContext clonectx, Statement target)
+               {
+                       StatementList t = (StatementList) target;
+
+                       t.statements = new List<Statement> (statements.Count);
+                       foreach (Statement s in statements)
+                               t.statements.Add (s.Clone (clonectx));
+               }
+       }
+
        // A 'return' or a 'yield break'
        public abstract class ExitStatement : Statement
        {
@@ -659,46 +710,65 @@ namespace Mono.CSharp {
        /// <summary>
        ///   Implements the return statement
        /// </summary>
-       public class Return : ExitStatement {
+       public class Return : ExitStatement
+       {
                protected Expression Expr;
                public Return (Expression expr, Location l)
                {
                        Expr = expr;
                        loc = l;
                }
-               
+
+               #region Properties
+               public Expression Expression {
+                       get {
+                               return Expr;
+                       }
+               }
+               #endregion
+
                protected override bool DoResolve (BlockContext ec)
                {
                        if (Expr == null) {
                                if (ec.ReturnType == TypeManager.void_type)
                                        return true;
-                               
-                               ec.Report.Error (126, loc,
-                                       "An object of a type convertible to `{0}' is required for the return statement",
-                                       TypeManager.CSharpName (ec.ReturnType));
+
+                               if (ec.CurrentIterator != null) {
+                                       Error_ReturnFromIterator (ec);
+                               } else {
+                                       ec.Report.Error (126, loc,
+                                               "An object of a type convertible to `{0}' is required for the return statement",
+                                               ec.ReturnType.GetSignatureForError ());
+                               }
+
                                return false;
                        }
 
-                       if (ec.CurrentBlock.Toplevel.IsIterator) {
-                               ec.Report.Error (1622, loc, "Cannot return a value from iterators. Use the yield return " +
-                                                 "statement to return a value, or yield break to end the iteration");
-                       }
+                       Expr = Expr.Resolve (ec);
 
                        AnonymousExpression am = ec.CurrentAnonymousMethod;
-                       if (am == null && ec.ReturnType == TypeManager.void_type) {
-                               ec.Report.Error (127, loc, "`{0}': A return keyword must not be followed by any expression when method returns void",
-                                       ec.GetSignatureForError ());
+                       if (am == null) {
+                               if (ec.ReturnType == TypeManager.void_type) {
+                                       ec.Report.Error (127, loc,
+                                               "`{0}': A return keyword must not be followed by any expression when method returns void",
+                                               ec.GetSignatureForError ());
+                               }
+                       } else {
+                               if (am.IsIterator) {
+                                       Error_ReturnFromIterator (ec);
+                                       return false;
+                               }
+
+                               var l = am as AnonymousMethodBody;
+                               if (l != null && l.ReturnTypeInference != null && Expr != null) {
+                                       l.ReturnTypeInference.AddCommonTypeBound (Expr.Type);
+                                       return true;
+                               }
                        }
 
-                       Expr = Expr.Resolve (ec);
                        if (Expr == null)
                                return false;
 
-                       if (ec.HasSet (ResolveContext.Options.InferReturnType)) {
-                               ec.ReturnTypeInference.AddCommonTypeBound (Expr.Type);
-                               return true;
-                       }
-
                        if (Expr.Type != ec.ReturnType) {
                                Expr = Convert.ImplicitConversionRequired (ec, Expr, ec.ReturnType, loc);
 
@@ -730,6 +800,12 @@ namespace Mono.CSharp {
                                ec.Emit (OpCodes.Ret);
                }
 
+               void Error_ReturnFromIterator (ResolveContext rc)
+               {
+                       rc.Report.Error (1622, loc,
+                               "Cannot return a value from iterators. Use the yield return statement to return a value, or yield break to end the iteration");
+               }
+
                protected override void CloneTo (CloneContext clonectx, Statement t)
                {
                        Return target = (Return) t;
@@ -786,12 +862,14 @@ namespace Mono.CSharp {
                bool defined;
                bool referenced;
                Label label;
+               Block block;
 
                FlowBranching.UsageVector vectors;
                
-               public LabeledStatement (string name, Location l)
+               public LabeledStatement (string name, Block block, Location l)
                {
                        this.name = name;
+                       this.block = block;
                        this.loc = l;
                }
 
@@ -805,6 +883,12 @@ namespace Mono.CSharp {
                        return label;
                }
 
+               public Block Block {
+                       get {
+                               return block;
+                       }
+               }
+
                public string Name {
                        get { return name; }
                }
@@ -842,6 +926,9 @@ namespace Mono.CSharp {
 
                protected override void DoEmit (EmitContext ec)
                {
+                       if (!HasBeenReferenced)
+                               ec.Report.Warning (164, 2, loc, "This label has not been referenced");
+
                        LabelTarget (ec);
                        ec.MarkLabel (label);
                }
@@ -1072,940 +1159,797 @@ namespace Mono.CSharp {
                void EmitAddressOf (EmitContext ec);
        }
 
-       public interface IKnownVariable {
+       public interface INamedBlockVariable
+       {
                Block Block { get; }
+               Expression CreateReferenceExpression (ResolveContext rc, Location loc);
+               bool IsDeclared { get; }
                Location Location { get; }
        }
 
-       //
-       // The information about a user-perceived local variable
-       //
-       public class LocalInfo : IKnownVariable, ILocalVariable {
-               public readonly FullNamedExpression Type;
+       public class BlockVariableDeclaration : Statement
+       {
+               public class Declarator
+               {
+                       LocalVariable li;
+                       Expression initializer;
 
-               public TypeSpec VariableType;
-               public readonly string Name;
-               public readonly Location Location;
-               public readonly Block Block;
+                       public Declarator (LocalVariable li, Expression initializer)
+                       {
+                               if (li.Type != null)
+                                       throw new ArgumentException ("Expected null variable type");
 
-               public VariableInfo VariableInfo;
-               HoistedVariable hoisted_variant;
+                               this.li = li;
+                               this.initializer = initializer;
+                       }
 
-               [Flags]
-               enum Flags : byte {
-                       Used = 1,
-                       ReadOnly = 2,
-                       Pinned = 4,
-                       IsThis = 8,
-                       AddressTaken = 32,
-                       CompilerGenerated = 64,
-                       IsConstant = 128
-               }
+                       public Declarator (Declarator clone, Expression initializer)
+                       {
+                               this.li = clone.li;
+                               this.initializer = initializer;
+                       }
+
+                       #region Properties
+
+                       public LocalVariable Variable {
+                               get {
+                                       return li;
+                               }
+                       }
+
+                       public Expression Initializer {
+                               get {
+                                       return initializer;
+                               }
+                               set {
+                                       initializer = value;
+                               }
+                       }
 
-               public enum ReadOnlyContext: byte {
-                       Using,
-                       Foreach,
-                       Fixed
+                       #endregion
                }
 
-               Flags flags;
-               ReadOnlyContext ro_context;
-               LocalBuilder builder;
+               Expression initializer;
+               protected FullNamedExpression type_expr;
+               protected LocalVariable li;
+               protected List<Declarator> declarators;
 
-               public LocalInfo (FullNamedExpression type, string name, Block block, Location l)
+               public BlockVariableDeclaration (FullNamedExpression type, LocalVariable li)
                {
-                       Type = type;
-                       Name = name;
-                       Block = block;
-                       Location = l;
+                       this.type_expr = type;
+                       this.li = li;
+                       this.loc = type_expr.Location;
                }
 
-               public LocalInfo (TypeContainer ds, Block block, Location l)
+               protected BlockVariableDeclaration (LocalVariable li)
                {
-                       VariableType = ds.IsGeneric ? ds.CurrentType : ds.Definition;
-                       Block = block;
-                       Location = l;
+                       this.li = li;
                }
 
-               public void ResolveVariable (EmitContext ec)
-               {
-                       if (HoistedVariant != null)
-                               return;
+               #region Properties
 
-                       if (builder == null) {
-                               builder = ec.DeclareLocal (VariableType, Pinned);
+               public List<Declarator> Declarators {
+                       get {
+                               return declarators;
                        }
                }
 
-               public void Emit (EmitContext ec)
-               {
-                       ec.Emit (OpCodes.Ldloc, builder);
+               public Expression Initializer {
+                       get {
+                               return initializer;
+                       }
+                       set {
+                               initializer = value;
+                       }
                }
 
-               public void EmitAssign (EmitContext ec)
-               {
-                       ec.Emit (OpCodes.Stloc, builder);
+               public FullNamedExpression TypeExpression {
+                       get {
+                               return type_expr;
+                       }
                }
 
-               public void EmitAddressOf (EmitContext ec)
-               {
-                       ec.Emit (OpCodes.Ldloca, builder);
+               public LocalVariable Variable {
+                       get {
+                               return li;
+                       }
                }
 
-               public void EmitSymbolInfo (EmitContext ec)
+               #endregion
+
+               public void AddDeclarator (Declarator decl)
                {
-                       if (builder != null)
-                               ec.DefineLocalVariable (Name, builder);
-               }
+                       if (declarators == null)
+                               declarators = new List<Declarator> ();
 
-               //
-               // Hoisted local variable variant
-               //
-               public HoistedVariable HoistedVariant {
-                       get {
-                               return hoisted_variant;
-                       }
-                       set {
-                               hoisted_variant = value;
-                       }
+                       declarators.Add (decl);
                }
 
-               public bool IsThisAssigned (BlockContext ec, Block block)
+               void CreateEvaluatorVariable (BlockContext bc, LocalVariable li)
                {
-                       if (VariableInfo == null)
-                               throw new Exception ();
+                       var container = bc.CurrentMemberDefinition.Parent;
 
-                       if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo))
-                               return true;
+                       Field f = new Field (container, new TypeExpression (li.Type, li.Location), Modifiers.PUBLIC | Modifiers.STATIC,
+                               new MemberName (li.Name, li.Location), null);
 
-                       return VariableInfo.TypeInfo.IsFullyInitialized (ec, VariableInfo, block.StartLocation);
+                       container.AddField (f);
+                       f.Define ();
+                       Evaluator.QueueField (f);
+
+                       li.HoistedVariant = new HoistedEvaluatorVariable (f);
+                       li.SetIsUsed ();
                }
 
-               public bool IsAssigned (BlockContext ec)
+               public override bool Resolve (BlockContext bc)
                {
-                       if (VariableInfo == null)
-                               throw new Exception ();
+                       if (li.Type == null) {
+                               TypeSpec type = null;
+                               if (type_expr is VarExpr) {
+                                       //
+                                       // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
+                                       // same name exists or as a keyword when no type was found
+                                       // 
+                                       var texpr = type_expr.ResolveAsTypeTerminal (bc, true);
+                                       if (texpr == null) {
+                                               if (RootContext.Version < LanguageVersion.V_3)
+                                                       bc.Report.FeatureIsNotAvailable (loc, "implicitly typed local variable");
+
+                                               if (li.IsFixed) {
+                                                       bc.Report.Error (821, loc, "A fixed statement cannot use an implicitly typed local variable");
+                                                       return false;
+                                               }
 
-                       return !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo);
-               }
+                                               if (li.IsConstant) {
+                                                       bc.Report.Error (822, loc, "An implicitly typed local variable cannot be a constant");
+                                                       return false;
+                                               }
 
-               public bool Resolve (ResolveContext ec)
-               {
-                       if (VariableType != null)
-                               return true;
+                                               if (Initializer == null) {
+                                                       bc.Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");
+                                                       return false;
+                                               }
 
-                       TypeExpr texpr = Type.ResolveAsContextualType (ec, false);
-                       if (texpr == null)
-                               return false;
-                               
-                       VariableType = texpr.Type;
+                                               if (declarators != null) {
+                                                       bc.Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
+                                                       declarators = null;
+                                               }
 
-                       if (VariableType.IsStatic) {
-                               FieldBase.Error_VariableOfStaticClass (Location, Name, VariableType, ec.Report);
-                               return false;
+                                               Initializer = Initializer.Resolve (bc);
+                                               if (Initializer != null) {
+                                                       ((VarExpr) type_expr).InferType (bc, Initializer);
+                                                       type = type_expr.Type;
+                                               }
+                                       }
+                               }
+
+                               if (type == null) {
+                                       var texpr = type_expr.ResolveAsTypeTerminal (bc, false);
+                                       if (texpr == null)
+                                               return false;
+
+                                       type = texpr.Type;
+
+                                       if (li.IsConstant && !type.IsConstantCompatible) {
+                                               Const.Error_InvalidConstantType (type, loc, bc.Report);
+                                       }
+                               }
+
+                               if (type.IsStatic)
+                                       FieldBase.Error_VariableOfStaticClass (loc, li.Name, type, bc.Report);
+
+                               if (type.IsPointer && !bc.IsUnsafe)
+                                       Expression.UnsafeError (bc, loc);
+
+                               li.Type = type;
+                       }
+
+                       bool eval_global = RootContext.StatementMode && bc.CurrentBlock is ToplevelBlock;
+                       if (eval_global) {
+                               CreateEvaluatorVariable (bc, li);
+                       } else {
+                               li.PrepareForFlowAnalysis (bc);
+                       }
+
+                       if (initializer != null) {
+                               initializer = ResolveInitializer (bc, li, initializer);
+                               // li.Variable.DefinitelyAssigned 
                        }
 
-                       if (VariableType.IsPointer && !ec.IsUnsafe)
-                               Expression.UnsafeError (ec, Location);
+                       if (declarators != null) {
+                               foreach (var d in declarators) {
+                                       d.Variable.Type = li.Type;
+                                       if (eval_global) {
+                                               CreateEvaluatorVariable (bc, d.Variable);
+                                       } else {
+                                               d.Variable.PrepareForFlowAnalysis (bc);
+                                       }
+
+                                       if (d.Initializer != null) {
+                                               d.Initializer = ResolveInitializer (bc, d.Variable, d.Initializer);
+                                               // d.Variable.DefinitelyAssigned 
+                                       }
+                               }
+                       }
 
                        return true;
                }
 
-               public bool IsConstant {
-                       get { return (flags & Flags.IsConstant) != 0; }
-                       set { flags |= Flags.IsConstant; }
+               protected virtual Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
+               {
+                       var a = new SimpleAssign (li.CreateReferenceExpression (bc, li.Location), initializer, li.Location);
+                       return a.ResolveStatement (bc);
                }
 
-               public bool AddressTaken {
-                       get { return (flags & Flags.AddressTaken) != 0; }
-                       set { flags |= Flags.AddressTaken; }
-               }
+               protected override void DoEmit (EmitContext ec)
+               {
+                       if (li.IsConstant)
+                               return;
 
-               public bool CompilerGenerated {
-                       get { return (flags & Flags.CompilerGenerated) != 0; }
-                       set { flags |= Flags.CompilerGenerated; }
+                       li.CreateBuilder (ec);
+
+                       if (Initializer != null)
+                               ((ExpressionStatement) Initializer).EmitStatement (ec);
+
+                       if (declarators != null) {
+                               foreach (var d in declarators) {
+                                       d.Variable.CreateBuilder (ec);
+                                       if (d.Initializer != null)
+                                               ((ExpressionStatement) d.Initializer).EmitStatement (ec);
+                               }
+                       }
                }
 
-               public override string ToString ()
+               protected override void CloneTo (CloneContext clonectx, Statement target)
                {
-                       return String.Format ("LocalInfo ({0},{1},{2},{3})",
-                                             Name, Type, VariableInfo, Location);
-               }
+                       BlockVariableDeclaration t = (BlockVariableDeclaration) target;
 
-               public bool Used {
-                       get { return (flags & Flags.Used) != 0; }
-                       set { flags = value ? (flags | Flags.Used) : (unchecked (flags & ~Flags.Used)); }
-               }
+                       if (type_expr != null)
+                               t.type_expr = (FullNamedExpression) type_expr.Clone (clonectx);
+
+                       if (initializer != null)
+                               t.initializer = initializer.Clone (clonectx);
 
-               public bool ReadOnly {
-                       get { return (flags & Flags.ReadOnly) != 0; }
+                       if (declarators != null) {
+                               t.declarators = null;
+                               foreach (var d in declarators)
+                                       t.AddDeclarator (new Declarator (d, d.Initializer == null ? null : d.Initializer.Clone (clonectx)));
+                       }
                }
+       }
 
-               public void SetReadOnlyContext (ReadOnlyContext context)
+       class BlockConstantDeclaration : BlockVariableDeclaration
+       {
+               public BlockConstantDeclaration (FullNamedExpression type, LocalVariable li)
+                       : base (type, li)
                {
-                       flags |= Flags.ReadOnly;
-                       ro_context = context;
                }
 
-               public string GetReadOnlyContext ()
+               protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
                {
-                       if (!ReadOnly)
-                               throw new InternalErrorException ("Variable is not readonly");
+                       initializer = initializer.Resolve (bc);
+                       if (initializer == null)
+                               return null;
 
-                       switch (ro_context) {
-                       case ReadOnlyContext.Fixed:
-                               return "fixed variable";
-                       case ReadOnlyContext.Foreach:
-                               return "foreach iteration variable";
-                       case ReadOnlyContext.Using:
-                               return "using variable";
+                       var c = initializer as Constant;
+                       if (c == null) {
+                               initializer.Error_ExpressionMustBeConstant (bc, initializer.Location, li.Name);
+                               return null;
                        }
-                       throw new NotImplementedException ();
-               }
 
-               //
-               // Whether the variable is pinned, if Pinned the variable has been 
-               // allocated in a pinned slot with DeclareLocal.
-               //
-               public bool Pinned {
-                       get { return (flags & Flags.Pinned) != 0; }
-                       set { flags = value ? (flags | Flags.Pinned) : (flags & ~Flags.Pinned); }
+                       c = c.ConvertImplicitly (bc, li.Type);
+                       if (c == null) {
+                               if (TypeManager.IsReferenceType (li.Type))
+                                       initializer.Error_ConstantCanBeInitializedWithNullOnly (bc, li.Type, initializer.Location, li.Name);
+                               else
+                                       initializer.Error_ValueCannotBeConverted (bc, initializer.Location, li.Type, false);
+
+                               return null;
+                       }
+
+                       li.ConstantValue = c;
+                       return initializer;
                }
+       }
 
-               public bool IsThis {
-                       get { return (flags & Flags.IsThis) != 0; }
-                       set { flags = value ? (flags | Flags.IsThis) : (flags & ~Flags.IsThis); }
+       //
+       // The information about a user-perceived local variable
+       //
+       public class LocalVariable : INamedBlockVariable, ILocalVariable
+       {
+               [Flags]
+               public enum Flags
+               {
+                       Used = 1,
+                       IsThis = 1 << 1,
+                       AddressTaken = 1 << 2,
+                       CompilerGenerated = 1 << 3,
+                       Constant = 1 << 4,
+                       ForeachVariable = 1 << 5,
+                       FixedVariable = 1 << 6,
+                       UsingVariable = 1 << 7,
+//                     DefinitelyAssigned = 1 << 8,
+                       IsLocked = 1 << 9,
+
+                       ReadonlyMask = ForeachVariable | FixedVariable | UsingVariable
                }
 
-               Block IKnownVariable.Block {
-                       get { return Block; }
+               TypeSpec type;
+               readonly string name;
+               readonly Location loc;
+               readonly Block block;
+               Flags flags;
+               Constant const_value;
+
+               public VariableInfo VariableInfo;
+               HoistedVariable hoisted_variant;
+
+               LocalBuilder builder;
+
+               public LocalVariable (Block block, string name, Location loc)
+               {
+                       this.block = block;
+                       this.name = name;
+                       this.loc = loc;
                }
 
-               Location IKnownVariable.Location {
-                       get { return Location; }
+               public LocalVariable (Block block, string name, Flags flags, Location loc)
+                       : this (block, name, loc)
+               {
+                       this.flags = flags;
                }
 
-               public LocalInfo Clone (CloneContext clonectx)
+               //
+               // Used by variable declarators
+               //
+               public LocalVariable (LocalVariable li, string name, Location loc)
+                       : this (li.block, name, li.flags, loc)
                {
-                       //
-                       // Variables in anonymous block are not resolved yet
-                       //
-                       if (VariableType == null)
-                               return new LocalInfo ((FullNamedExpression) Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location);
+               }
 
-                       //
-                       // Variables in method block are resolved
-                       //
-                       LocalInfo li = new LocalInfo (null, Name, clonectx.LookupBlock (Block), Location);
-                       li.VariableType = VariableType;
-                       return li;                      
+               #region Properties
+
+               public bool AddressTaken {
+                       get { return (flags & Flags.AddressTaken) != 0; }
+                       set { flags |= Flags.AddressTaken; }
                }
-       }
 
-       /// <summary>
-       ///   Block represents a C# block.
-       /// </summary>
-       ///
-       /// <remarks>
-       ///   This class is used in a number of places: either to represent
-       ///   explicit blocks that the programmer places or implicit blocks.
-       ///
-       ///   Implicit blocks are used as labels or to introduce variable
-       ///   declarations.
-       ///
-       ///   Top-level blocks derive from Block, and they are called ToplevelBlock
-       ///   they contain extra information that is not necessary on normal blocks.
-       /// </remarks>
-       public class Block : Statement {
-               public Block    Parent;
-               public Location StartLocation;
-               public Location EndLocation = Location.Null;
-
-               public ExplicitBlock Explicit;
-               public ToplevelBlock Toplevel; // TODO: Use Explicit
-
-               [Flags]
-               public enum Flags
-               {
-                       Unchecked = 1,
-                       BlockUsed = 2,
-                       VariablesInitialized = 4,
-                       HasRet = 8,
-                       Unsafe = 16,
-                       IsIterator = 32,
-                       HasCapturedVariable = 64,
-                       HasCapturedThis = 1 << 7,
-                       IsExpressionTree = 1 << 8
-               }
-
-               protected Flags flags;
-
-               public bool Unchecked {
-                       get { return (flags & Flags.Unchecked) != 0; }
-                       set { flags = value ? flags | Flags.Unchecked : flags & ~Flags.Unchecked; }
+               public Block Block {
+                       get {
+                               return block;
+                       }
                }
 
-               public bool Unsafe {
-                       get { return (flags & Flags.Unsafe) != 0; }
-                       set { flags |= Flags.Unsafe; }
+               public Constant ConstantValue {
+                       get {
+                               return const_value;
+                       }
+                       set {
+                               const_value = value;
+                       }
                }
 
                //
-               // The statements in this block
-               //
-               protected List<Statement> statements;
-
-               //
-               // An array of Blocks.  We keep track of children just
-               // to generate the local variable declarations.
-               //
-               // Statements and child statements are handled through the
-               // statements.
-               //
-               List<Block> children;
-
-               //
-               // Labels.  (label, block) pairs.
-               //
-               protected Dictionary<string, LabeledStatement> labels;
-
-               //
-               // Keeps track of (name, type) pairs
-               //
-               Dictionary<string, LocalInfo> variables;
-
-               //
-               // Keeps track of constants
-               Dictionary<string, Expression> constants;
-
-               //
-               // Temporary variables.
-               //
-               List<LocalInfo> temporary_variables;
-               
-               //
-               // If this is a switch section, the enclosing switch block.
-               //
-               Block switch_block;
-
-               protected List<Statement> scope_initializers;
-
-               List<ToplevelBlock> anonymous_children;
-
-               protected static int id;
-
-               int this_id;
-
-               int assignable_slots;
-               bool unreachable_shown;
-               bool unreachable;
-               
-               public Block (Block parent)
-                       : this (parent, (Flags) 0, Location.Null, Location.Null)
-               { }
-
-               public Block (Block parent, Flags flags)
-                       : this (parent, flags, Location.Null, Location.Null)
-               { }
-
-               public Block (Block parent, Location start, Location end)
-                       : this (parent, (Flags) 0, start, end)
-               { }
-
-               //
-               // Useful when TopLevel block is downgraded to normal block
+               // Hoisted local variable variant
                //
-               public Block (ToplevelBlock parent, ToplevelBlock source)
-                       : this (parent, source.flags, source.StartLocation, source.EndLocation)
-               {
-                       statements = source.statements;
-                       children = source.children;
-                       labels = source.labels;
-                       variables = source.variables;
-                       constants = source.constants;
-                       switch_block = source.switch_block;
+               public HoistedVariable HoistedVariant {
+                       get {
+                               return hoisted_variant;
+                       }
+                       set {
+                               hoisted_variant = value;
+                       }
                }
 
-               public Block (Block parent, Flags flags, Location start, Location end)
-               {
-                       if (parent != null) {
-                               parent.AddChild (this);
-
-                               // the appropriate constructors will fixup these fields
-                               Toplevel = parent.Toplevel;
-                               Explicit = parent.Explicit;
+               public bool IsDeclared {
+                       get {
+                               return type != null;
                        }
-                       
-                       this.Parent = parent;
-                       this.flags = flags;
-                       this.StartLocation = start;
-                       this.EndLocation = end;
-                       this.loc = start;
-                       this_id = id++;
-                       statements = new List<Statement> (4);
                }
 
-               public Block CreateSwitchBlock (Location start)
-               {
-                       // FIXME: should this be implicit?
-                       Block new_block = new ExplicitBlock (this, start, start);
-                       new_block.switch_block = this;
-                       return new_block;
+               public bool IsConstant {
+                       get {
+                               return (flags & Flags.Constant) != 0;
+                       }
                }
 
-               public int ID {
-                       get { return this_id; }
+               public bool IsLocked {
+                       get {
+                               return (flags & Flags.IsLocked) != 0;
+                       }
+                       set {
+                               flags = value ? flags | Flags.IsLocked : flags & ~Flags.IsLocked;
+                       }
                }
 
-               public IDictionary<string, LocalInfo> Variables {
+               public bool IsThis {
                        get {
-                               if (variables == null)
-                                       variables = new Dictionary<string, LocalInfo> ();
-                               return variables;
+                               return (flags & Flags.IsThis) != 0;
                        }
                }
 
-               void AddChild (Block b)
-               {
-                       if (children == null)
-                               children = new List<Block> (1);
-                       
-                       children.Add (b);
+               public bool IsFixed {
+                       get {
+                               return (flags & Flags.FixedVariable) != 0;
+                       }
                }
 
-               public void SetEndLocation (Location loc)
-               {
-                       EndLocation = loc;
+               public bool IsReadonly {
+                       get {
+                               return (flags & Flags.ReadonlyMask) != 0;
+                       }
                }
 
-               protected void Error_158 (string name, Location loc)
-               {
-                       Toplevel.Report.Error (158, loc, "The label `{0}' shadows another label " +
-                                     "by the same name in a contained scope", name);
+               public Location Location {
+                       get {
+                               return loc;
+                       }
                }
 
-               /// <summary>
-               ///   Adds a label to the current block. 
-               /// </summary>
-               ///
-               /// <returns>
-               ///   false if the name already exists in this block. true
-               ///   otherwise.
-               /// </returns>
-               ///
-               public bool AddLabel (LabeledStatement target)
-               {
-                       if (switch_block != null)
-                               return switch_block.AddLabel (target);
-
-                       string name = target.Name;
-
-                       Block cur = this;
-                       while (cur != null) {
-                               LabeledStatement s = cur.DoLookupLabel (name);
-                               if (s != null) {
-                                       Toplevel.Report.SymbolRelatedToPreviousError (s.loc, s.Name);
-                                       Toplevel.Report.Error (140, target.loc, "The label `{0}' is a duplicate", name);
-                                       return false;
-                               }
-
-                               if (this == Explicit)
-                                       break;
-
-                               cur = cur.Parent;
+               public string Name {
+                       get {
+                               return name;
                        }
+               }
 
-                       while (cur != null) {
-                               if (cur.DoLookupLabel (name) != null) {
-                                       Error_158 (name, target.loc);
-                                       return false;
-                               }
+               public TypeSpec Type {
+                   get {
+                               return type;
+                       }
+                   set {
+                               type = value;
+                       }
+               }
 
-                               if (children != null) {
-                                       foreach (Block b in children) {
-                                               LabeledStatement s = b.DoLookupLabel (name);
-                                               if (s == null)
-                                                       continue;
+               #endregion
 
-                                               Toplevel.Report.SymbolRelatedToPreviousError (s.loc, s.Name);
-                                               Error_158 (name, target.loc);
-                                               return false;
-                                       }
+               public void CreateBuilder (EmitContext ec)
+               {
+                       if ((flags & Flags.Used) == 0) {
+                               if (VariableInfo == null) {
+                                       // Missing flow analysis or wrong variable flags
+                                       throw new InternalErrorException ("VariableInfo is null and the variable `{0}' is not used", name);
                                }
 
-                               cur = cur.Parent;
+                               if (VariableInfo.IsEverAssigned)
+                                       ec.Report.Warning (219, 3, Location, "The variable `{0}' is assigned but its value is never used", Name);
+                               else
+                                       ec.Report.Warning (168, 3, Location, "The variable `{0}' is declared but never used", Name);
                        }
 
-                       Toplevel.CheckError158 (name, target.loc);
+                       if (HoistedVariant != null)
+                               return;
 
-                       if (labels == null)
-                               labels = new Dictionary<string, LabeledStatement> ();
+                       if (builder != null) {
+                               if ((flags & Flags.CompilerGenerated) != 0)
+                                       return;
 
-                       labels.Add (name, target);
-                       return true;
+                               // To avoid Used warning duplicates
+                               throw new InternalErrorException ("Already created variable `{0}'", name);
+                       }
+
+                       //
+                       // All fixed variabled are pinned, a slot has to be alocated
+                       //
+                       builder = ec.DeclareLocal (Type, IsFixed);
+                       if (SymbolWriter.HasSymbolWriter)
+                               ec.DefineLocalVariable (name, builder);
                }
 
-               public LabeledStatement LookupLabel (string name)
+               public static LocalVariable CreateCompilerGenerated (TypeSpec type, Block block, Location loc)
                {
-                       LabeledStatement s = DoLookupLabel (name);
-                       if (s != null)
-                               return s;
+                       LocalVariable li = new LocalVariable (block, "<$$>", Flags.CompilerGenerated | Flags.Used, loc);
+                       li.Type = type;
+                       return li;
+               }
 
-                       if (children == null)
-                               return null;
+               public Expression CreateReferenceExpression (ResolveContext rc, Location loc)
+               {
+                       if (IsConstant && const_value != null)
+                               return Constant.CreateConstantFromValue (Type, const_value.GetValue (), loc).Resolve (rc);
 
-                       foreach (Block child in children) {
-                               if (Explicit != child.Explicit)
-                                       continue;
+                       return new LocalVariableReference (this, loc);
+               }
 
-                               s = child.LookupLabel (name);
-                               if (s != null)
-                                       return s;
-                       }
+               public void Emit (EmitContext ec)
+               {
+                       // TODO: Need something better for temporary variables
+                       if ((flags & Flags.CompilerGenerated) != 0)
+                               CreateBuilder (ec);
 
-                       return null;
+                       ec.Emit (OpCodes.Ldloc, builder);
                }
 
-               LabeledStatement DoLookupLabel (string name)
+               public void EmitAssign (EmitContext ec)
                {
-                       if (switch_block != null)
-                               return switch_block.LookupLabel (name);
+                       // TODO: Need something better for temporary variables
+                       if ((flags & Flags.CompilerGenerated) != 0)
+                               CreateBuilder (ec);
 
-                       if (labels != null)
-                               if (labels.ContainsKey (name))
-                                       return labels [name];
+                       ec.Emit (OpCodes.Stloc, builder);
+               }
 
-                       return null;
+               public void EmitAddressOf (EmitContext ec)
+               {
+                       ec.Emit (OpCodes.Ldloca, builder);
                }
 
-               public bool CheckInvariantMeaningInBlock (string name, Expression e, Location loc)
+               public string GetReadOnlyContext ()
                {
-                       Block b = this;
-                       IKnownVariable kvi = b.Explicit.GetKnownVariable (name);
-                       while (kvi == null) {
-                               b = b.Explicit.Parent;
-                               if (b == null)
-                                       return true;
-                               kvi = b.Explicit.GetKnownVariable (name);
+                       switch (flags & Flags.ReadonlyMask) {
+                       case Flags.FixedVariable:
+                               return "fixed variable";
+                       case Flags.ForeachVariable:
+                               return "foreach iteration variable";
+                       case Flags.UsingVariable:
+                               return "using variable";
                        }
 
-                       if (kvi.Block == b)
-                               return true;
-
-                       // Is kvi.Block nested inside 'b'
-                       if (b.Explicit != kvi.Block.Explicit) {
-                               //
-                               // If a variable by the same name it defined in a nested block of this
-                               // block, we violate the invariant meaning in a block.
-                               //
-                               if (b == this) {
-                                       Toplevel.Report.SymbolRelatedToPreviousError (kvi.Location, name);
-                                       Toplevel.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", name);
-                                       return false;
-                               }
+                       throw new InternalErrorException ("Variable is not readonly");
+               }
 
-                               //
-                               // It's ok if the definition is in a nested subblock of b, but not
-                               // nested inside this block -- a definition in a sibling block
-                               // should not affect us.
-                               //
-                               return true;
-                       }
+               public bool IsThisAssigned (BlockContext ec, Block block)
+               {
+                       if (VariableInfo == null)
+                               throw new Exception ();
 
-                       //
-                       // Block 'b' and kvi.Block are the same textual block.
-                       // However, different variables are extant.
-                       //
-                       // Check if the variable is in scope in both blocks.  We use
-                       // an indirect check that depends on AddVariable doing its
-                       // part in maintaining the invariant-meaning-in-block property.
-                       //
-                       if (e is VariableReference || (e is Constant && b.GetLocalInfo (name) != null))
+                       if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo))
                                return true;
 
-                       if (this is ToplevelBlock) {
-                               Toplevel.Report.SymbolRelatedToPreviousError (kvi.Location, name);
-                               e.Error_VariableIsUsedBeforeItIsDeclared (Toplevel.Report, name);
-                               return false;
-                       }
-
-                       //
-                       // Even though we detected the error when the name is used, we
-                       // treat it as if the variable declaration was in error.
-                       //
-                       Toplevel.Report.SymbolRelatedToPreviousError (loc, name);
-                       Error_AlreadyDeclared (kvi.Location, name, "parent or current");
-                       return false;
+                       return VariableInfo.TypeInfo.IsFullyInitialized (ec, VariableInfo, block.StartLocation);
                }
 
-               protected virtual bool CheckParentConflictName (ToplevelBlock block, string name, Location l)
+               public bool IsAssigned (BlockContext ec)
                {
-                       LocalInfo vi = GetLocalInfo (name);
-                       if (vi != null) {
-                               block.Report.SymbolRelatedToPreviousError (vi.Location, name);
-                               if (Explicit == vi.Block.Explicit) {
-                                       Error_AlreadyDeclared (l, name, null);
-                               } else {
-                                       Error_AlreadyDeclared (l, name, this is ToplevelBlock ?
-                                               "parent or current" : "parent");
-                               }
-                               return false;
-                       }
-
-                       if (block != null) {
-                               Expression e = block.GetParameterReference (name, Location.Null);
-                               if (e != null) {
-                                       ParameterReference pr = e as ParameterReference;
-                                       if (this is Linq.QueryBlock && (pr != null && pr.Parameter is Linq.QueryBlock.ImplicitQueryParameter || e is MemberAccess))
-                                               Error_AlreadyDeclared (loc, name);
-                                       else
-                                               Error_AlreadyDeclared (loc, name, "parent or current");
-                                       return false;
-                               }
-                       }
+                       if (VariableInfo == null)
+                               throw new Exception ();
 
-                       return true;
+                       return !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo);
                }
 
-               public LocalInfo AddVariable (Expression type, string name, Location l)
+               public void PrepareForFlowAnalysis (BlockContext bc)
                {
-                       if (!CheckParentConflictName (Toplevel, name, l))
-                               return null;
-
-                       if (Toplevel.GenericMethod != null) {
-                               foreach (TypeParameter tp in Toplevel.GenericMethod.CurrentTypeParameters) {
-                                       if (tp.Name == name) {
-                                               Toplevel.Report.SymbolRelatedToPreviousError (tp);
-                                               Error_AlreadyDeclaredTypeParameter (Toplevel.Report, loc, name, "local variable");
-                                               return null;
-                                       }
-                               }
-                       }                       
-
-                       IKnownVariable kvi = Explicit.GetKnownVariable (name);
-                       if (kvi != null) {
-                               Toplevel.Report.SymbolRelatedToPreviousError (kvi.Location, name);
-                               Error_AlreadyDeclared (l, name, "child");
-                               return null;
-                       }
-
-                       LocalInfo vi = new LocalInfo ((FullNamedExpression) type, name, this, l);
-                       AddVariable (vi);
-
-                       if ((flags & Flags.VariablesInitialized) != 0)
-                               throw new InternalErrorException ("block has already been resolved");
+                       //
+                       // No need for definitely assigned check for these guys
+                       //
+                       if ((flags & (Flags.Constant | Flags.ReadonlyMask | Flags.CompilerGenerated)) != 0)
+                               return;
 
-                       return vi;
-               }
-               
-               protected virtual void AddVariable (LocalInfo li)
-               {
-                       Variables.Add (li.Name, li);
-                       Explicit.AddKnownVariable (li.Name, li);
+                       VariableInfo = new VariableInfo (this, bc.FlowOffset);
+                       bc.FlowOffset += VariableInfo.Length;
                }
 
-               protected virtual void Error_AlreadyDeclared (Location loc, string var, string reason)
+               //
+               // Mark the variables as referenced in the user code
+               //
+               public void SetIsUsed ()
                {
-                       if (reason == null) {
-                               Error_AlreadyDeclared (loc, var);
-                               return;
-                       }
-                       
-                       Toplevel.Report.Error (136, loc, "A local variable named `{0}' cannot be declared " +
-                                     "in this scope because it would give a different meaning " +
-                                     "to `{0}', which is already used in a `{1}' scope " +
-                                     "to denote something else", var, reason);
+                       flags |= Flags.Used;
                }
 
-               protected virtual void Error_AlreadyDeclared (Location loc, string name)
+               public override string ToString ()
                {
-                       Toplevel.Report.Error (128, loc,
-                               "A local variable named `{0}' is already defined in this scope", name);
+                       return string.Format ("LocalInfo ({0},{1},{2},{3})", name, type, VariableInfo, Location);
                }
-                                       
-               public virtual void Error_AlreadyDeclaredTypeParameter (Report r, Location loc, string name, string conflict)
+       }
+
+       /// <summary>
+       ///   Block represents a C# block.
+       /// </summary>
+       ///
+       /// <remarks>
+       ///   This class is used in a number of places: either to represent
+       ///   explicit blocks that the programmer places or implicit blocks.
+       ///
+       ///   Implicit blocks are used as labels or to introduce variable
+       ///   declarations.
+       ///
+       ///   Top-level blocks derive from Block, and they are called ToplevelBlock
+       ///   they contain extra information that is not necessary on normal blocks.
+       /// </remarks>
+       public class Block : Statement {
+               [Flags]
+               public enum Flags
                {
-                       r.Error (412, loc, "The type parameter name `{0}' is the same as `{1}'",
-                               name, conflict);
+                       Unchecked = 1,
+                       HasRet = 8,
+                       Unsafe = 16,
+                       IsIterator = 32,
+                       HasCapturedVariable = 64,
+                       HasCapturedThis = 1 << 7,
+                       IsExpressionTree = 1 << 8,
+                       CompilerGenerated = 1 << 9
                }
 
-               public bool AddConstant (Expression type, string name, Expression value, Location l)
-               {
-                       if (AddVariable (type, name, l) == null)
-                               return false;
-                       
-                       if (constants == null)
-                               constants = new Dictionary<string, Expression> ();
+               public Block Parent;
+               public Location StartLocation;
+               public Location EndLocation;
 
-                       constants.Add (name, value);
+               public ExplicitBlock Explicit;
+               public ParametersBlock ParametersBlock;
 
-                       // A block is considered used if we perform an initialization in a local declaration, even if it is constant.
-                       Use ();
-                       return true;
-               }
+               protected Flags flags;
 
-               static int next_temp_id = 0;
+               //
+               // The statements in this block
+               //
+               protected List<Statement> statements;
 
-               public LocalInfo AddTemporaryVariable (TypeExpr te, Location loc)
-               {
-                       Report.Debug (64, "ADD TEMPORARY", this, Toplevel, loc);
+               protected List<Statement> scope_initializers;
 
-                       if (temporary_variables == null)
-                               temporary_variables = new List<LocalInfo> ();
+               int? resolving_init_idx;
 
-                       int id = ++next_temp_id;
-                       string name = "$s_" + id.ToString ();
+               Block original;
 
-                       LocalInfo li = new LocalInfo (te, name, this, loc);
-                       li.CompilerGenerated = true;
-                       temporary_variables.Add (li);
-                       return li;
+#if DEBUG
+               static int id;
+               public int ID = id++;
+
+               static int clone_id_counter;
+               int clone_id;
+#endif
+
+//             int assignable_slots;
+               bool unreachable_shown;
+               bool unreachable;
+               
+               public Block (Block parent, Location start, Location end)
+                       : this (parent, 0, start, end)
+               {
                }
 
-               public LocalInfo GetLocalInfo (string name)
+               public Block (Block parent, Flags flags, Location start, Location end)
                {
-                       LocalInfo ret;
-                       for (Block b = this; b != null; b = b.Parent) {
-                               if (b.variables != null) {
-                                       if (b.variables.TryGetValue (name, out ret))
-                                               return ret;
-                               }
+                       if (parent != null) {
+                               // the appropriate constructors will fixup these fields
+                               ParametersBlock = parent.ParametersBlock;
+                               Explicit = parent.Explicit;
                        }
+                       
+                       this.Parent = parent;
+                       this.flags = flags;
+                       this.StartLocation = start;
+                       this.EndLocation = end;
+                       this.loc = start;
+                       statements = new List<Statement> (4);
 
-                       return null;
+                       this.original = this;
                }
 
-               public Expression GetVariableType (string name)
-               {
-                       LocalInfo vi = GetLocalInfo (name);
-                       return vi == null ? null : vi.Type;
+               #region Properties
+
+               public bool HasRet {
+                       get { return (flags & Flags.HasRet) != 0; }
                }
 
-               public Expression GetConstantExpression (string name)
-               {
-                       Expression ret;
-                       for (Block b = this; b != null; b = b.Parent) {
-                               if (b.constants != null) {
-                                       if (b.constants.TryGetValue (name, out ret))
-                                               return ret;
-                               }
+               public Block Original {
+                       get {
+                               return original;
                        }
-                       return null;
                }
 
-               //
-               // It should be used by expressions which require to
-               // register a statement during resolve process.
-               //
-               public void AddScopeStatement (Statement s)
-               {
-                       if (scope_initializers == null)
-                               scope_initializers = new List<Statement> ();
-
-                       scope_initializers.Add (s);
+               public bool IsCompilerGenerated {
+                       get { return (flags & Flags.CompilerGenerated) != 0; }
+                       set { flags = value ? flags | Flags.CompilerGenerated : flags & ~Flags.CompilerGenerated; }
                }
-               
-               public void AddStatement (Statement s)
-               {
-                       statements.Add (s);
-                       flags |= Flags.BlockUsed;
+
+               public bool Unchecked {
+                       get { return (flags & Flags.Unchecked) != 0; }
+                       set { flags = value ? flags | Flags.Unchecked : flags & ~Flags.Unchecked; }
                }
 
-               public bool Used {
-                       get { return (flags & Flags.BlockUsed) != 0; }
+               public bool Unsafe {
+                       get { return (flags & Flags.Unsafe) != 0; }
+                       set { flags |= Flags.Unsafe; }
                }
 
-               public void Use ()
+               #endregion
+
+               public Block CreateSwitchBlock (Location start)
                {
-                       flags |= Flags.BlockUsed;
+                       // FIXME: Only explicit block should be created
+                       var new_block = new Block (this, start, start);
+                       new_block.IsCompilerGenerated = true;
+                       return new_block;
                }
 
-               public bool HasRet {
-                       get { return (flags & Flags.HasRet) != 0; }
+               public void SetEndLocation (Location loc)
+               {
+                       EndLocation = loc;
                }
 
-               public int AssignableSlots {
-                       get {
-// TODO: Re-enable                     
-//                             if ((flags & Flags.VariablesInitialized) == 0)
-//                                     throw new Exception ("Variables have not been initialized yet");
-                               return assignable_slots;
-                       }
+               public void AddLabel (LabeledStatement target)
+               {
+                       ParametersBlock.TopBlock.AddLabel (target.Name, target);
                }
 
-               public IList<ToplevelBlock> AnonymousChildren {
-                       get { return anonymous_children; }
+               public void AddLocalName (LocalVariable li)
+               {
+                       AddLocalName (li.Name, li);
                }
 
-               public void AddAnonymousChild (ToplevelBlock b)
+               public virtual void AddLocalName (string name, INamedBlockVariable li)
                {
-                       if (anonymous_children == null)
-                               anonymous_children = new List<ToplevelBlock> ();
-
-                       anonymous_children.Add (b);
+                       ParametersBlock.TopBlock.AddLocalName (name, li);
                }
 
-               void DoResolveConstants (BlockContext ec)
+               public virtual void Error_AlreadyDeclared (string name, INamedBlockVariable variable, string reason)
                {
-                       if (constants == null)
+                       if (reason == null) {
+                               Error_AlreadyDeclared (name, variable);
                                return;
-
-                       if (variables == null)
-                               throw new InternalErrorException ("cannot happen");
-
-                       foreach (var de in variables) {
-                               string name = de.Key;
-                               LocalInfo vi = de.Value;
-                               TypeSpec variable_type = vi.VariableType;
-
-                               if (variable_type == null) {
-                                       if (vi.Type is VarExpr)
-                                               ec.Report.Error (822, vi.Type.Location, "An implicitly typed local variable cannot be a constant");
-
-                                       continue;
-                               }
-
-                               Expression cv;
-                               if (!constants.TryGetValue (name, out cv))
-                                       continue;
-
-                               // Don't let 'const int Foo = Foo;' succeed.
-                               // Removing the name from 'constants' ensures that we get a LocalVariableReference below,
-                               // which in turn causes the 'must be constant' error to be triggered.
-                               constants.Remove (name);
-
-                               if (!variable_type.IsConstantCompatible) {
-                                       Const.Error_InvalidConstantType (variable_type, loc, ec.Report);
-                                       continue;
-                               }
-
-                               ec.CurrentBlock = this;
-                               Expression e;
-                               using (ec.With (ResolveContext.Options.ConstantCheckState, (flags & Flags.Unchecked) == 0)) {
-                                       e = cv.Resolve (ec);
-                               }
-                               if (e == null)
-                                       continue;
-
-                               Constant ce = e as Constant;
-                               if (ce == null) {
-                                       e.Error_ExpressionMustBeConstant (ec, vi.Location, name);
-                                       continue;
-                               }
-
-                               e = ce.ConvertImplicitly (ec, variable_type);
-                               if (e == null) {
-                                       if (TypeManager.IsReferenceType (variable_type))
-                                               ce.Error_ConstantCanBeInitializedWithNullOnly (ec, variable_type, vi.Location, vi.Name);
-                                       else
-                                               ce.Error_ValueCannotBeConverted (ec, vi.Location, variable_type, false);
-                                       continue;
-                               }
-
-                               constants.Add (name, e);
-                               vi.IsConstant = true;
                        }
+
+                       ParametersBlock.TopBlock.Report.Error (136, variable.Location,
+                               "A local variable named `{0}' cannot be declared in this scope because it would give a different meaning " +
+                               "to `{0}', which is already used in a `{1}' scope to denote something else",
+                               name, reason);
                }
 
-               protected void ResolveMeta (BlockContext ec, int offset)
+               public virtual void Error_AlreadyDeclared (string name, INamedBlockVariable variable)
                {
-                       Report.Debug (64, "BLOCK RESOLVE META", this, Parent);
-
-                       // If some parent block was unsafe, we remain unsafe even if this block
-                       // isn't explicitly marked as such.
-                       using (ec.With (ResolveContext.Options.UnsafeScope, ec.IsUnsafe | Unsafe)) {
-                               flags |= Flags.VariablesInitialized;
-
-                               if (variables != null) {
-                                       foreach (LocalInfo li in variables.Values) {
-                                               if (!li.Resolve (ec))
-                                                       continue;
-                                               li.VariableInfo = new VariableInfo (li, offset);
-                                               offset += li.VariableInfo.Length;
-                                       }
+                       var pi = variable as ParametersBlock.ParameterInfo;
+                       if (pi != null) {
+                               var p = pi.Parameter;
+                               if (p is AnonymousTypeClass.GeneratedParameter) {
+                                       ParametersBlock.TopBlock.Report.Error (833, p.Location, "`{0}': An anonymous type cannot have multiple properties with the same name",
+                                               p.Name);
+                               } else {
+                                       ParametersBlock.TopBlock.Report.Error (100, p.Location, "The parameter name `{0}' is a duplicate", p.Name);
                                }
-                               assignable_slots = offset;
-
-                               DoResolveConstants (ec);
 
-                               if (children == null)
-                                       return;
-                               foreach (Block b in children)
-                                       b.ResolveMeta (ec, offset);
+                               return;
                        }
+
+                       ParametersBlock.TopBlock.Report.Error (128, variable.Location,
+                               "A local variable named `{0}' is already defined in this scope", name);
+               }
+                                       
+               public virtual void Error_AlreadyDeclaredTypeParameter (string name, Location loc)
+               {
+                       ParametersBlock.TopBlock.Report.Error (412, loc,
+                               "The type parameter name `{0}' is the same as local variable or parameter name",
+                               name);
                }
 
                //
-               // Emits the local variable declarations for a block
+               // It should be used by expressions which require to
+               // register a statement during resolve process.
                //
-               public virtual void EmitMeta (EmitContext ec)
+               public void AddScopeStatement (Statement s)
                {
-                       if (variables != null){
-                               foreach (LocalInfo vi in variables.Values)
-                                       vi.ResolveVariable (ec);
-                       }
-
-                       if (temporary_variables != null) {
-                               for (int i = 0; i < temporary_variables.Count; i++)
-                                       ((LocalInfo)temporary_variables[i]).ResolveVariable(ec);
-                       }
+                       if (scope_initializers == null)
+                               scope_initializers = new List<Statement> ();
 
-                       if (children != null) {
-                               for (int i = 0; i < children.Count; i++)
-                                       ((Block)children[i]).EmitMeta(ec);
+                       //
+                       // Simple recursive helper, when resolve scope initializer another
+                       // new scope initializer can be added, this ensures it's initialized
+                       // before existing one. For now this can happen with expression trees
+                       // in base ctor initializer only
+                       //
+                       if (resolving_init_idx.HasValue) {
+                               scope_initializers.Insert (resolving_init_idx.Value, s);
+                               ++resolving_init_idx;
+                       } else {
+                               scope_initializers.Add (s);
                        }
                }
-
-               void UsageWarning (BlockContext ec)
+               
+               public void AddStatement (Statement s)
                {
-                       if (variables == null || ec.Report.WarningLevel < 3)
-                               return;
-
-                       foreach (var de in variables) {
-                               LocalInfo vi = de.Value;
-
-                               if (!vi.Used) {
-                                       string name = de.Key;
+                       statements.Add (s);
+               }
 
-                                       // vi.VariableInfo can be null for 'catch' variables
-                                       if (vi.VariableInfo != null && vi.VariableInfo.IsEverAssigned)
-                                               ec.Report.Warning (219, 3, vi.Location, "The variable `{0}' is assigned but its value is never used", name);
-                                       else
-                                               ec.Report.Warning (168, 3, vi.Location, "The variable `{0}' is declared but never used", name);
-                               }
+               public int AssignableSlots {
+                       get {
+                               // FIXME: HACK, we don't know the block available variables count now, so set this high enough
+                               return 4096;
+//                             return assignable_slots;
                        }
                }
 
-               static void CheckPossibleMistakenEmptyStatement (BlockContext ec, Statement s)
-               {
-                       Statement body;
-
-                       // Some statements are wrapped by a Block. Since
-                       // others' internal could be changed, here I treat
-                       // them as possibly wrapped by Block equally.
-                       Block b = s as Block;
-                       if (b != null && b.statements.Count == 1)
-                               s = (Statement) b.statements [0];
-
-                       if (s is Lock)
-                               body = ((Lock) s).Statement;
-                       else if (s is For)
-                               body = ((For) s).Statement;
-                       else if (s is Foreach)
-                               body = ((Foreach) s).Statement;
-                       else if (s is While)
-                               body = ((While) s).Statement;
-                       else if (s is Fixed)
-                               body = ((Fixed) s).Statement;
-                       else if (s is Using)
-                               body = ((Using) s).EmbeddedStatement;
-                       else if (s is UsingTemporary)
-                               body = ((UsingTemporary) s).Statement;
-                       else
-                               return;
-
-                       if (body == null || body is EmptyStatement)
-                               ec.Report.Warning (642, 3, s.loc, "Possible mistaken empty statement");
+               public LabeledStatement LookupLabel (string name)
+               {
+                       return ParametersBlock.TopBlock.GetLabel (name, this);
                }
 
                public override bool Resolve (BlockContext ec)
@@ -2013,8 +1957,6 @@ namespace Mono.CSharp {
                        Block prev_block = ec.CurrentBlock;
                        bool ok = true;
 
-                       int errors = ec.Report.Errors;
-
                        ec.CurrentBlock = this;
                        ec.StartFlowBranching (this);
 
@@ -2024,8 +1966,11 @@ namespace Mono.CSharp {
                        // Compiler generated scope statements
                        //
                        if (scope_initializers != null) {
-                               foreach (Statement s in scope_initializers)
-                                       s.Resolve (ec);
+                               for (resolving_init_idx = 0; resolving_init_idx < scope_initializers.Count; ++resolving_init_idx) {
+                                       scope_initializers[resolving_init_idx.Value].Resolve (ec);
+                               }
+
+                               resolving_init_idx = null;
                        }
 
                        //
@@ -2037,10 +1982,6 @@ namespace Mono.CSharp {
                        int statement_count = statements.Count;
                        for (int ix = 0; ix < statement_count; ix++){
                                Statement s = statements [ix];
-                               // Check possible empty statement (CS0642)
-                               if (ix + 1 < statement_count && ec.Report.WarningLevel >= 3 &&
-                                       statements [ix + 1] is ExplicitBlock)
-                                       CheckPossibleMistakenEmptyStatement (ec, s);
 
                                //
                                // Warn if we detect unreachable code.
@@ -2099,18 +2040,9 @@ namespace Mono.CSharp {
 
                        // If we're a non-static `struct' constructor which doesn't have an
                        // initializer, then we must initialize all of the struct's fields.
-                       if (this == Toplevel && !Toplevel.IsThisAssigned (ec) && !flow_unreachable)
+                       if (this == ParametersBlock.TopBlock && !ParametersBlock.TopBlock.IsThisAssigned (ec) && !flow_unreachable)
                                ok = false;
 
-                       if ((labels != null) && (ec.Report.WarningLevel >= 2)) {
-                               foreach (LabeledStatement label in labels.Values)
-                                       if (!label.HasBeenReferenced)
-                                               ec.Report.Warning (164, 2, label.loc, "This label has not been referenced");
-                       }
-
-                       if (ok && errors == ec.Report.Errors)
-                               UsageWarning (ec);
-
                        return ok;
                }
 
@@ -2132,8 +2064,7 @@ namespace Mono.CSharp {
                protected override void DoEmit (EmitContext ec)
                {
                        for (int ix = 0; ix < statements.Count; ix++){
-                               Statement s = (Statement) statements [ix];
-                               s.Emit (ec);
+                               statements [ix].Emit (ec);
                        }
                }
 
@@ -2163,59 +2094,38 @@ namespace Mono.CSharp {
 
                protected virtual void EmitSymbolInfo (EmitContext ec)
                {
-                       if (variables != null) {
-                               foreach (LocalInfo vi in variables.Values) {
-                                       vi.EmitSymbolInfo (ec);
-                               }
-                       }
                }
 
+#if DEBUG
                public override string ToString ()
                {
-                       return String.Format ("{0} ({1}:{2})", GetType (),ID, StartLocation);
+                       return String.Format ("{0} ({1}:{2})", GetType (), ID, StartLocation);
                }
+#endif
 
                protected override void CloneTo (CloneContext clonectx, Statement t)
                {
                        Block target = (Block) t;
+#if DEBUG
+                       target.clone_id = clone_id_counter++;
+#endif
 
                        clonectx.AddBlockMap (this, target);
 
-                       //target.Toplevel = (ToplevelBlock) clonectx.LookupBlock (Toplevel);
-                       target.Explicit = (ExplicitBlock) clonectx.LookupBlock (Explicit);
+                       target.ParametersBlock = (ParametersBlock) (ParametersBlock == this ? target : clonectx.RemapBlockCopy (ParametersBlock));
+                       target.Explicit = (ExplicitBlock) (Explicit == this ? target : clonectx.LookupBlock (Explicit));
+
                        if (Parent != null)
                                target.Parent = clonectx.RemapBlockCopy (Parent);
 
-                       if (variables != null){
-                               target.variables = new Dictionary<string, LocalInfo> ();
-
-                               foreach (var de in variables){
-                                       LocalInfo newlocal = de.Value.Clone (clonectx);
-                                       target.variables [de.Key] = newlocal;
-                                       clonectx.AddVariableMap (de.Value, newlocal);
-                               }
-                       }
-
                        target.statements = new List<Statement> (statements.Count);
                        foreach (Statement s in statements)
                                target.statements.Add (s.Clone (clonectx));
-
-                       if (target.children != null){
-                               target.children = new List<Block> (children.Count);
-                               foreach (Block b in children){
-                                       target.children.Add (clonectx.LookupBlock (b));
-                               }
-                       }
-
-                       //
-                       // TODO: labels, switch_block, constants (?), anonymous_children
-                       //
                }
        }
 
        public class ExplicitBlock : Block
        {
-               Dictionary<string, IKnownVariable> known_variables;
                protected AnonymousMethodStorey am_storey;
 
                public ExplicitBlock (Block parent, Location start, Location end)
@@ -2229,52 +2139,55 @@ namespace Mono.CSharp {
                        this.Explicit = this;
                }
 
-               // <summary>
-               //   Marks a variable with name @name as being used in this or a child block.
-               //   If a variable name has been used in a child block, it's illegal to
-               //   declare a variable with the same name in the current block.
-               // </summary>
-               internal void AddKnownVariable (string name, IKnownVariable info)
-               {
-                       if (known_variables == null)
-                               known_variables = new Dictionary<string, IKnownVariable> ();
+               #region Properties
 
-                       known_variables [name] = info;
+               public AnonymousMethodStorey AnonymousMethodStorey {
+                       get {
+                               return am_storey;
+                       }
+               }
 
-                       if (Parent != null)
-                               Parent.Explicit.AddKnownVariable (name, info);
+               public bool HasCapturedThis {
+                       set { flags = value ? flags | Flags.HasCapturedThis : flags & ~Flags.HasCapturedThis; }
+                       get {
+                               return (flags & Flags.HasCapturedThis) != 0;
+                       }
                }
 
-               public AnonymousMethodStorey AnonymousMethodStorey {
-                       get { return am_storey; }
+               public bool HasCapturedVariable {
+                       set { flags = value ? flags | Flags.HasCapturedVariable : flags & ~Flags.HasCapturedVariable; }
+                       get {
+                               return (flags & Flags.HasCapturedVariable) != 0;
+                       }
                }
 
+               #endregion
+
                //
                // Creates anonymous method storey in current block
                //
                public AnonymousMethodStorey CreateAnonymousMethodStorey (ResolveContext ec)
                {
-                       //
-                       // When referencing a variable in iterator storey from children anonymous method
-                       //
-                       if (Toplevel.am_storey is IteratorStorey) {
-                               return Toplevel.am_storey;
-                       }
-
                        //
                        // An iterator has only 1 storey block
                        //
                        if (ec.CurrentIterator != null)
                            return ec.CurrentIterator.Storey;
 
+                       //
+                       // When referencing a variable in iterator storey from children anonymous method
+                       //
+                       if (ParametersBlock.am_storey is IteratorStorey) {
+                               return ParametersBlock.am_storey;
+                       }
+
                        if (am_storey == null) {
                                MemberBase mc = ec.MemberContext as MemberBase;
-                               GenericMethod gm = mc == null ? null : mc.GenericMethod;
 
                                //
                                // Creates anonymous method storey for this block
                                //
-                               am_storey = new AnonymousMethodStorey (this, ec.CurrentMemberDefinition.Parent.PartialContainer, mc, gm, "AnonStorey");
+                               am_storey = new AnonymousMethodStorey (this, ec.CurrentMemberDefinition.Parent.PartialContainer, mc, ec.CurrentTypeParameters, "AnonStorey");
                        }
 
                        return am_storey;
@@ -2282,8 +2195,10 @@ namespace Mono.CSharp {
 
                public override void Emit (EmitContext ec)
                {
-                       if (am_storey != null)
-                               am_storey.EmitStoreyInstantiation (ec);
+                       if (am_storey != null) {
+                               DefineAnonymousStorey (ec);
+                               am_storey.EmitStoreyInstantiation (ec, this);
+                       }
 
                        bool emit_debug_info = SymbolWriter.HasSymbolWriter && Parent != null && !(am_storey is IteratorStorey);
                        if (emit_debug_info)
@@ -2295,143 +2210,148 @@ namespace Mono.CSharp {
                                ec.EndScope ();
                }
 
-               public override void EmitMeta (EmitContext ec)
+               void DefineAnonymousStorey (EmitContext ec)
                {
                        //
                        // Creates anonymous method storey
                        //
-                       if (am_storey != null) {
-                               if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null) {
+                       if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null) {
+                               //
+                               // Creates parent storey reference when hoisted this is accessible
+                               //
+                               if (am_storey.OriginalSourceBlock.Explicit.HasCapturedThis) {
+                                       ExplicitBlock parent = am_storey.OriginalSourceBlock.Explicit.Parent.Explicit;
+
                                        //
-                                       // Creates parent storey reference when hoisted this is accessible
+                                       // Hoisted this exists in top-level parent storey only
                                        //
-                                       if (am_storey.OriginalSourceBlock.Explicit.HasCapturedThis) {
-                                               ExplicitBlock parent = Toplevel.Parent.Explicit;
+                                       while (parent.am_storey == null || parent.am_storey.Parent is AnonymousMethodStorey)
+                                               parent = parent.Parent.Explicit;
 
-                                               //
-                                               // Hoisted this exists in top-level parent storey only
-                                               //
-                                               while (parent.am_storey == null || parent.am_storey.Parent is AnonymousMethodStorey)
-                                                       parent = parent.Parent.Explicit;
+                                       am_storey.AddParentStoreyReference (ec, parent.am_storey);
+                               }
 
-                                               am_storey.AddParentStoreyReference (ec, parent.am_storey);
-                                       }
+                               am_storey.SetNestedStoryParent (ec.CurrentAnonymousMethod.Storey);
 
-                                       am_storey.SetNestedStoryParent (ec.CurrentAnonymousMethod.Storey);
+                               // TODO MemberCache: Review
+                               am_storey.Mutator = ec.CurrentAnonymousMethod.Storey.Mutator;
+                       }
 
-                                       // TODO MemberCache: Review
-                                       am_storey.Mutator = ec.CurrentAnonymousMethod.Storey.Mutator;
-                               }
+                       am_storey.CreateType ();
+                       if (am_storey.Mutator == null && ec.CurrentTypeParameters != null)
+                               am_storey.Mutator = new TypeParameterMutator (ec.CurrentTypeParameters, am_storey.CurrentTypeParameters);
+
+                       am_storey.DefineType ();
+                       am_storey.ResolveTypeParameters ();
+
+                       var ref_blocks = am_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);
 
-                               am_storey.CreateType ();
-                               if (am_storey.Mutator == null && ec.CurrentTypeParameters != null)
-                                       am_storey.Mutator = new TypeParameterMutator (ec.CurrentTypeParameters, am_storey.CurrentTypeParameters);
-
-                               am_storey.DefineType ();
-                               am_storey.ResolveTypeParameters ();
-                               am_storey.Define ();
-                               am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey);
-
-                               var ref_blocks = am_storey.ReferencesFromChildrenBlock;
-                               if (ref_blocks != null) {
-                                       foreach (ExplicitBlock ref_block in ref_blocks) {
-                                               for (ExplicitBlock b = ref_block.Explicit; b != this; b = b.Parent.Explicit) {
-                                                       if (b.am_storey != null) {
-                                                               b.am_storey.AddParentStoreyReference (ec, am_storey);
-
-                                                               // Stop propagation inside same top block
-                                                               if (b.Toplevel == Toplevel)
-                                                                       break;
-
-                                                               b = b.Toplevel;
-                                                   }
-                                                       b.HasCapturedVariable = true;
+                                                       // Stop propagation inside same top block
+                                                       if (b.ParametersBlock.am_storey == ParametersBlock.am_storey)
+                                                               break;
+
+                                                       b = b.ParametersBlock;
                                                }
+
+                                               b.HasCapturedVariable = true;
                                        }
                                }
                        }
 
-                       base.EmitMeta (ec);
+                       am_storey.Define ();
+                       am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey);
                }
 
-               internal IKnownVariable GetKnownVariable (string name)
+               public void WrapIntoDestructor (TryFinally tf, ExplicitBlock tryBlock)
                {
-                       if (known_variables == null)
-                               return null;
-
-                       IKnownVariable kw;
-                       if (!known_variables.TryGetValue (name, out kw))
-                               return null;
-
-                       return kw;
+                       tryBlock.statements = statements;
+                       statements = new List<Statement> (1);
+                       statements.Add (tf);
                }
+       }
 
-               public bool HasCapturedThis
+       //
+       // ParametersBlock was introduced to support anonymous methods
+       // and lambda expressions
+       // 
+       public class ParametersBlock : ExplicitBlock
+       {
+               public class ParameterInfo : INamedBlockVariable
                {
-                       set { flags = value ? flags | Flags.HasCapturedThis : flags & ~Flags.HasCapturedThis; }
-                       get { return (flags & Flags.HasCapturedThis) != 0; }
-               }
+                       readonly ParametersBlock block;
+                       readonly int index;
+                       public VariableInfo VariableInfo;
+                       bool is_locked;
 
-               public bool HasCapturedVariable
-               {
-                       set { flags = value ? flags | Flags.HasCapturedVariable : flags & ~Flags.HasCapturedVariable; }
-                       get { return (flags & Flags.HasCapturedVariable) != 0; }
-               }
+                       public ParameterInfo (ParametersBlock block, int index)
+                       {
+                               this.block = block;
+                               this.index = index;
+                       }
 
-               protected override void CloneTo (CloneContext clonectx, Statement t)
-               {
-                       ExplicitBlock target = (ExplicitBlock) t;
-                       target.known_variables = null;
-                       base.CloneTo (clonectx, t);
-               }
-       }
+                       #region Properties
 
-       public class ToplevelParameterInfo : IKnownVariable {
-               public readonly ToplevelBlock Block;
-               public readonly int Index;
-               public VariableInfo VariableInfo;
+                       public Block Block {
+                               get {
+                                       return block;
+                               }
+                       }
 
-               Block IKnownVariable.Block {
-                       get { return Block; }
-               }
-               public Parameter Parameter {
-                       get { return Block.Parameters [Index]; }
-               }
+                       public bool IsDeclared {
+                               get {
+                                       return true;
+                               }
+                       }
 
-               public TypeSpec ParameterType {
-                       get { return Block.Parameters.Types [Index]; }
-               }
+                       public bool IsLocked {
+                               get {
+                                       return is_locked;
+                               }
+                               set {
+                                       is_locked = value;
+                               }
+                       }
 
-               public Location Location {
-                       get { return Parameter.Location; }
-               }
+                       public Location Location {
+                               get {
+                                       return Parameter.Location;
+                               }
+                       }
 
-               public ToplevelParameterInfo (ToplevelBlock block, int idx)
-               {
-                       this.Block = block;
-                       this.Index = idx;
+                       public Parameter Parameter {
+                               get {
+                                       return block.Parameters [index];
+                               }
+                       }
+
+                       public TypeSpec ParameterType {
+                               get {
+                                       return Parameter.Type;
+                               }
+                       }
+
+                       #endregion
+
+                       public Expression CreateReferenceExpression (ResolveContext rc, Location loc)
+                       {
+                               return new ParameterReference (this, loc);
+                       }
                }
-       }
 
-       //
-       // A toplevel block contains extra information, the split is done
-       // only to separate information that would otherwise bloat the more
-       // lightweight Block.
-       //
-       // In particular, this was introduced when the support for Anonymous
-       // Methods was implemented. 
-       // 
-       public class ToplevelBlock : ExplicitBlock
-       {
                // 
                // Block is converted to an expression
                //
                sealed class BlockScopeExpression : Expression
                {
                        Expression child;
-                       readonly ToplevelBlock block;
+                       readonly ParametersBlock block;
 
-                       public BlockScopeExpression (Expression child, ToplevelBlock block)
+                       public BlockScopeExpression (Expression child, ParametersBlock block)
                        {
                                this.child = child;
                                this.block = block;
@@ -2446,7 +2366,7 @@ namespace Mono.CSharp {
                        {
                                if (child == null)
                                        return null;
-                               
+
                                child = child.Resolve (ec);
                                if (child == null)
                                        return null;
@@ -2458,25 +2378,62 @@ namespace Mono.CSharp {
 
                        public override void Emit (EmitContext ec)
                        {
-                               block.EmitMeta (ec);
                                block.EmitScopeInitializers (ec);
                                child.Emit (ec);
                        }
                }
 
-               GenericMethod generic;
                protected ParametersCompiled parameters;
-               ToplevelParameterInfo[] parameter_info;
-               LocalInfo this_variable;
+               protected ParameterInfo[] parameter_info;
                bool resolved;
-               bool unreachable;
-               CompilerContext compiler;
+               protected bool unreachable;
+               protected ToplevelBlock top_block;
 
-               public HoistedVariable HoistedThisVariable;
+               public ParametersBlock (Block parent, ParametersCompiled parameters, Location start)
+                       : base (parent, 0, start, start)
+               {
+                       if (parameters == null)
+                               throw new ArgumentNullException ("parameters");
 
-               public bool Resolved {
+                       this.parameters = parameters;
+                       ParametersBlock = this;
+
+                       this.top_block = parent.ParametersBlock.top_block;
+                       ProcessParameters ();
+               }
+
+               protected ParametersBlock (ParametersCompiled parameters, Location start)
+                       : base (null, 0, start, start)
+               {
+                       if (parameters == null)
+                               throw new ArgumentNullException ("parameters");
+
+                       this.parameters = parameters;
+                       ParametersBlock = this;
+               }
+
+               protected ParametersBlock (ParametersBlock source, ParametersCompiled parameters)
+                       : base (null, 0, source.StartLocation, source.EndLocation)
+               {
+                       this.parameters = parameters;
+                       this.statements = source.statements;
+                       this.scope_initializers = source.scope_initializers;
+
+                       this.resolved = true;
+                       this.unreachable = source.unreachable;
+                       this.am_storey = source.am_storey;
+
+                       ParametersBlock = this;
+               }
+
+               #region Properties
+
+               //
+               // Block has been converted to expression tree
+               //
+               public bool IsExpressionTree {
                        get {
-                               return resolved;
+                               return (flags & Flags.IsExpressionTree) != 0;
                        }
                }
 
@@ -2484,185 +2441,455 @@ namespace Mono.CSharp {
                // The parameters for the block.
                //
                public ParametersCompiled Parameters {
-                       get { return parameters; }
+                       get {
+                               return parameters;
+                       }
+               }
+
+               public ToplevelBlock TopBlock {
+                       get {
+                               return top_block;
+                       }
+               }
+
+               public bool Resolved {
+                       get {
+                               return resolved;
+                       }
+               }
+
+               #endregion
+
+               // <summary>
+               //   Check whether all `out' parameters have been assigned.
+               // </summary>
+               public void CheckOutParameters (FlowBranching.UsageVector vector, Location loc)
+               {
+                       if (vector.IsUnreachable)
+                               return;
+
+                       int n = parameter_info == null ? 0 : parameter_info.Length;
+
+                       for (int i = 0; i < n; i++) {
+                               VariableInfo var = parameter_info[i].VariableInfo;
+
+                               if (var == null)
+                                       continue;
+
+                               if (vector.IsAssigned (var, false))
+                                       continue;
+
+                               TopBlock.Report.Error (177, loc, "The out parameter `{0}' must be assigned to before control leaves the current method",
+                                       var.Name);
+                       }
+               }
+
+               public override Expression CreateExpressionTree (ResolveContext ec)
+               {
+                       if (statements.Count == 1) {
+                               Expression expr = ((Statement) statements[0]).CreateExpressionTree (ec);
+                               if (scope_initializers != null)
+                                       expr = new BlockScopeExpression (expr, this);
+
+                               return expr;
+                       }
+
+                       return base.CreateExpressionTree (ec);
+               }
+
+               public ParameterInfo GetParameterInfo (Parameter p)
+               {
+                       for (int i = 0; i < parameters.Count; ++i) {
+                               if (parameters[i] == p)
+                                       return parameter_info[i];
+                       }
+
+                       throw new ArgumentException ("Invalid parameter");
+               }
+
+               public Expression GetParameterReference (int index, Location loc)
+               {
+                       return new ParameterReference (parameter_info[index], loc);
+               }
+
+               protected void ProcessParameters ()
+               {
+                       if (parameters.Count == 0)
+                               return;
+
+                       parameter_info = new ParameterInfo[parameters.Count];
+                       for (int i = 0; i < parameter_info.Length; ++i) {
+                               var p = parameters.FixedParameters[i];
+                               if (p == null)
+                                       continue;
+
+                               // TODO: Should use Parameter only and more block there
+                               parameter_info[i] = new ParameterInfo (this, i);
+                               AddLocalName (p.Name, parameter_info[i]);
+                       }
                }
 
-               public Report Report {
-                       get { return compiler.Report; }
+               public bool Resolve (FlowBranching parent, BlockContext rc, IMethodData md)
+               {
+                       if (resolved)
+                               return true;
+
+                       resolved = true;
+
+                       if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
+                               flags |= Flags.IsExpressionTree;
+
+                       try {
+                               ResolveMeta (rc);
+
+                               using (rc.With (ResolveContext.Options.DoFlowAnalysis, true)) {
+                                       FlowBranchingToplevel top_level = rc.StartFlowBranching (this, parent);
+
+                                       if (!Resolve (rc))
+                                               return false;
+
+                                       unreachable = top_level.End ();
+                               }
+                       } catch (Exception e) {
+                               if (e is CompletionResult || rc.Report.IsDisabled)
+                                       throw;
+
+                               if (rc.CurrentBlock != null) {
+                                       rc.Report.Error (584, rc.CurrentBlock.StartLocation, "Internal compiler error: {0}", e.Message);
+                               } else {
+                                       rc.Report.Error (587, "Internal compiler error: {0}", e.Message);
+                               }
+
+                               if (Report.DebugFlags > 0)
+                                       throw;
+                       }
+
+                       if (rc.ReturnType != TypeManager.void_type && !unreachable) {
+                               if (rc.CurrentAnonymousMethod == null) {
+                                       // FIXME: Missing FlowAnalysis for generated iterator MoveNext method
+                                       if (md is IteratorMethod) {
+                                               unreachable = true;
+                                       } else {
+                                               rc.Report.Error (161, md.Location, "`{0}': not all code paths return a value", md.GetSignatureForError ());
+                                               return false;
+                                       }
+                               } else {
+                                       rc.Report.Error (1643, rc.CurrentAnonymousMethod.Location, "Not all code paths return a value in anonymous method of type `{0}'",
+                                                         rc.CurrentAnonymousMethod.GetSignatureForError ());
+                                       return false;
+                               }
+                       }
+
+                       return true;
                }
 
-               public GenericMethod GenericMethod {
-                       get { return generic; }
-               }
+               void ResolveMeta (BlockContext ec)
+               {
+                       int orig_count = parameters.Count;
 
-               public ToplevelBlock Container {
-                       get { return Parent == null ? null : Parent.Toplevel; }
-               }
+                       for (int i = 0; i < orig_count; ++i) {
+                               Parameter.Modifier mod = parameters.FixedParameters[i].ModFlags;
 
-               public ToplevelBlock (CompilerContext ctx, Block parent, ParametersCompiled parameters, Location start) :
-                       this (ctx, parent, (Flags) 0, parameters, start)
-               {
-               }
+                               if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT)
+                                       continue;
 
-               public ToplevelBlock (CompilerContext ctx, Block parent, ParametersCompiled parameters, GenericMethod generic, Location start) :
-                       this (ctx, parent, parameters, start)
-               {
-                       this.generic = generic;
+                               VariableInfo vi = new VariableInfo (parameters, i, ec.FlowOffset);
+                               parameter_info[i].VariableInfo = vi;
+                               ec.FlowOffset += vi.Length;
+                       }
                }
 
-               public ToplevelBlock (CompilerContext ctx, ParametersCompiled parameters, Location start) :
-                       this (ctx, null, (Flags) 0, parameters, start)
+               public void WrapIntoIterator (IMethodData method, TypeContainer host, TypeSpec iterator_type, bool is_enumerable)
                {
-               }
+                       ParametersBlock pb = new ParametersBlock (this, ParametersCompiled.EmptyReadOnlyParameters, StartLocation);
+                       pb.EndLocation = EndLocation;
+                       pb.statements = statements;
 
-               ToplevelBlock (CompilerContext ctx, Flags flags, ParametersCompiled parameters, Location start) :
-                       this (ctx, null, flags, parameters, start)
-               {
+                       var iterator = new Iterator (pb, method, host, iterator_type, is_enumerable);
+                       am_storey = new IteratorStorey (iterator);
+
+                       statements = new List<Statement> (1);
+                       AddStatement (new Return (iterator, iterator.Location));
                }
+       }
 
-               // We use 'Parent' to hook up to the containing block, but don't want to register the current block as a child.
-               // So, we use a two-stage setup -- first pass a null parent to the base constructor, and then override 'Parent'.
-               public ToplevelBlock (CompilerContext ctx, Block parent, Flags flags, ParametersCompiled parameters, Location start) :
-                       base (null, flags, start, Location.Null)
-               {
-                       this.compiler = ctx;
-                       this.Toplevel = this;
+       //
+       //
+       //
+       public class ToplevelBlock : ParametersBlock
+       {
+               LocalVariable this_variable;
+               CompilerContext compiler;
+               Dictionary<string, object> names;
+               Dictionary<string, object> labels;
 
-                       this.parameters = parameters;
-                       this.Parent = parent;
-                       if (parent != null)
-                               parent.AddAnonymousChild (this);
+               public HoistedVariable HoistedThisVariable;
 
-                       if (!this.parameters.IsEmpty)
-                               ProcessParameters ();
+               public Report Report {
+                       get { return compiler.Report; }
                }
 
                public ToplevelBlock (CompilerContext ctx, Location loc)
-                       : this (ctx, null, (Flags) 0, ParametersCompiled.EmptyReadOnlyParameters, loc)
+                       : this (ctx, ParametersCompiled.EmptyReadOnlyParameters, loc)
                {
                }
 
-               protected override void CloneTo (CloneContext clonectx, Statement t)
+               public ToplevelBlock (CompilerContext ctx, ParametersCompiled parameters, Location start)
+                       : base (parameters, start)
                {
-                       ToplevelBlock target = (ToplevelBlock) t;
-                       base.CloneTo (clonectx, t);
+                       this.compiler = ctx;
+                       top_block = this;
 
-                       if (parameters.Count != 0)
-                               target.parameter_info = new ToplevelParameterInfo [parameters.Count];
-                       for (int i = 0; i < parameters.Count; ++i)
-                               target.parameter_info [i] = new ToplevelParameterInfo (target, i);
+                       ProcessParameters ();
                }
 
-               public bool CheckError158 (string name, Location loc)
+               //
+               // Recreates a top level block from parameters block. Used for
+               // compiler generated methods where the original block comes from
+               // explicit child block. This works for already resolved blocks
+               // only to ensure we resolve them in the correct flow order
+               //
+               public ToplevelBlock (ParametersBlock source, ParametersCompiled parameters)
+                       : base (source, parameters)
                {
-                       if (AnonymousChildren != null) {
-                               foreach (ToplevelBlock child in AnonymousChildren) {
-                                       if (!child.CheckError158 (name, loc))
-                                               return false;
-                               }
+                       this.compiler = source.TopBlock.compiler;
+                       top_block = this;
+               }
+
+               public override void AddLocalName (string name, INamedBlockVariable li)
+               {
+                       if (names == null)
+                               names = new Dictionary<string, object> ();
+
+                       object value;
+                       if (!names.TryGetValue (name, out value)) {
+                               names.Add (name, li);
+                               return;
                        }
 
-                       for (ToplevelBlock c = Container; c != null; c = c.Container) {
-                               if (!c.DoCheckError158 (name, loc))
-                                       return false;
+                       INamedBlockVariable existing = value as INamedBlockVariable;
+                       List<INamedBlockVariable> existing_list;
+                       if (existing != null) {
+                               existing_list = new List<INamedBlockVariable> ();
+                               existing_list.Add (existing);
+                               names[name] = existing_list;
+                       } else {
+                               existing_list = (List<INamedBlockVariable>) value;
                        }
 
-                       return true;
-               }
+                       //
+                       // A collision checking between local names
+                       //
+                       for (int i = 0; i < existing_list.Count; ++i) {
+                               existing = existing_list[i];
+                               Block b = existing.Block;
 
-               void ProcessParameters ()
-               {
-                       int n = parameters.Count;
-                       parameter_info = new ToplevelParameterInfo [n];
-                       ToplevelBlock top_parent = Parent == null ? null : Parent.Toplevel;
-                       for (int i = 0; i < n; ++i) {
-                               parameter_info [i] = new ToplevelParameterInfo (this, i);
+                               // Collision at same level
+                               if (li.Block == b) {
+                                       li.Block.Error_AlreadyDeclared (name, li);
+                                       break;
+                               }
 
-                               Parameter p = parameters [i];
-                               if (p == null)
-                                       continue;
+                               // Collision with parent
+                               b = li.Block;
+                               while ((b = b.Parent) != null) {
+                                       if (existing.Block == b) {
+                                               li.Block.Error_AlreadyDeclared (name, li, "parent or current");
+                                               i = existing_list.Count;
+                                               break;
+                                       }
+                               }
 
-                               string name = p.Name;
-                               if (CheckParentConflictName (top_parent, name, loc))
-                                       AddKnownVariable (name, parameter_info [i]);
+                               // Collision with with children
+                               b = existing.Block;
+                               while ((b = b.Parent) != null) {
+                                       if (li.Block == b) {
+                                               li.Block.Error_AlreadyDeclared (name, li, "child");
+                                               i = existing_list.Count;
+                                               break;
+                                       }
+                               }
                        }
 
-                       // mark this block as "used" so that we create local declarations in a sub-block
-                       // FIXME: This appears to uncover a lot of bugs
-                       //this.Use ();
+                       existing_list.Add (li);
                }
 
-               bool DoCheckError158 (string name, Location loc)
+               public void AddLabel (string name, LabeledStatement label)
                {
-                       LabeledStatement s = LookupLabel (name);
-                       if (s != null) {
-                               Report.SymbolRelatedToPreviousError (s.loc, s.Name);
-                               Error_158 (name, loc);
-                               return false;
+                       if (labels == null)
+                               labels = new Dictionary<string, object> ();
+
+                       object value;
+                       if (!labels.TryGetValue (name, out value)) {
+                               labels.Add (name, label);
+                               return;
                        }
 
-                       return true;
-               }
+                       LabeledStatement existing = value as LabeledStatement;
+                       List<LabeledStatement> existing_list;
+                       if (existing != null) {
+                               existing_list = new List<LabeledStatement> ();
+                               existing_list.Add (existing);
+                               labels[name] = existing_list;
+                       } else {
+                               existing_list = (List<LabeledStatement>) value;
+                       }
 
-               public override Expression CreateExpressionTree (ResolveContext ec)
-               {
-                       if (statements.Count == 1) {
-                               Expression expr = ((Statement) statements[0]).CreateExpressionTree (ec);
-                               if (scope_initializers != null)
-                                       expr = new BlockScopeExpression (expr, this);
+                       //
+                       // A collision checking between labels
+                       //
+                       for (int i = 0; i < existing_list.Count; ++i) {
+                               existing = existing_list[i];
+                               Block b = existing.Block;
+
+                               // Collision at same level
+                               if (label.Block == b) {
+                                       Report.SymbolRelatedToPreviousError (existing.loc, name);
+                                       Report.Error (140, label.loc, "The label `{0}' is a duplicate", name);
+                                       break;
+                               }
 
-                               return expr;
+                               // Collision with parent
+                               b = label.Block;
+                               while ((b = b.Parent) != null) {
+                                       if (existing.Block == b) {
+                                               Report.Error (158, label.loc,
+                                                       "The label `{0}' shadows another label by the same name in a contained scope", name);
+                                               i = existing_list.Count;
+                                               break;
+                                       }
+                               }
+
+                               // Collision with with children
+                               b = existing.Block;
+                               while ((b = b.Parent) != null) {
+                                       if (label.Block == b) {
+                                               Report.Error (158, label.loc,
+                                                       "The label `{0}' shadows another label by the same name in a contained scope", name);
+                                               i = existing_list.Count;
+                                               break;
+                                       }
+                               }
                        }
 
-                       return base.CreateExpressionTree (ec);
+                       existing_list.Add (label);
                }
 
                //
-               // Reformats this block to be top-level iterator block
+               // Creates an arguments set from all parameters, useful for method proxy calls
                //
-               public IteratorStorey ChangeToIterator (Iterator iterator, ToplevelBlock source)
+               public Arguments GetAllParametersArguments ()
                {
-                       IsIterator = true;
-
-                       // Creates block with original statements
-                       AddStatement (new IteratorStatement (iterator, new Block (this, source)));
-
-                       source.statements = new List<Statement> (1);
-                       source.AddStatement (new Return (iterator, iterator.Location));
-                       source.IsIterator = false;
+                       int count = parameters.Count;
+                       Arguments args = new Arguments (count);
+                       for (int i = 0; i < count; ++i) {
+                               var arg_expr = GetParameterReference (i, parameter_info[i].Location);
+                               args.Add (new Argument (arg_expr));
+                       }
 
-                       IteratorStorey iterator_storey = new IteratorStorey (iterator);
-                       source.am_storey = iterator_storey;
-                       return iterator_storey;
+                       return args;
                }
 
                //
-               // Returns a parameter reference expression for the given name,
-               // or null if there is no such parameter
+               // Lookup inside a block, the returned value can represent 3 states
+               //
+               // true+variable: A local name was found and it's valid
+               // false+variable: A local name was found in a child block only
+               // false+null: No local name was found
                //
-               public Expression GetParameterReference (string name, Location loc)
+               public bool GetLocalName (string name, Block block, ref INamedBlockVariable variable)
                {
-                       for (ToplevelBlock t = this; t != null; t = t.Container) {
-                               Expression expr = t.GetParameterReferenceExpression (name, loc);
-                               if (expr != null)
-                                       return expr;
+                       if (names == null)
+                               return false;
+
+                       object value;
+                       if (!names.TryGetValue (name, out value))
+                               return false;
+
+                       variable = value as INamedBlockVariable;
+                       Block b = block;
+                       if (variable != null) {
+                               do {
+                                       if (variable.Block == b.Original)
+                                               return true;
+
+                                       b = b.Parent;
+                               } while (b != null);
+
+                               b = variable.Block;
+                               do {
+                                       if (block == b)
+                                               return false;
+
+                                       b = b.Parent;
+                               } while (b != null);
+                       } else {
+                               List<INamedBlockVariable> list = (List<INamedBlockVariable>) value;
+                               for (int i = 0; i < list.Count; ++i) {
+                                       variable = list[i];
+                                       do {
+                                               if (variable.Block == b.Original)
+                                                       return true;
+
+                                               b = b.Parent;
+                                       } while (b != null);
+
+                                       b = variable.Block;
+                                       do {
+                                               if (block == b)
+                                                       return false;
+
+                                               b = b.Parent;
+                                       } while (b != null);
+
+                                       b = block;
+                               }
                        }
 
-                       return null;
+                       variable = null;
+                       return false;
                }
 
-               protected virtual Expression GetParameterReferenceExpression (string name, Location loc)
+               public LabeledStatement GetLabel (string name, Block block)
                {
-                       int idx = parameters.GetParameterIndexByName (name);
-                       return idx < 0 ?
-                               null : new ParameterReference (parameter_info [idx], loc);
+                       if (labels == null)
+                               return null;
+
+                       object value;
+                       if (!labels.TryGetValue (name, out value)) {
+                               return null;
+                       }
+
+                       var label = value as LabeledStatement;
+                       Block b = block;
+                       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 LocalInfo ThisVariable {
+               public LocalVariable ThisVariable {
                        get { return this_variable; }
                }
 
@@ -2673,14 +2900,12 @@ namespace Mono.CSharp {
                //   analysis code to ensure that it's been fully initialized before control
                //   leaves the constructor.
                // </summary>
-               public LocalInfo AddThisVariable (TypeContainer ds, Location l)
+               public LocalVariable AddThisVariable (BlockContext bc, TypeContainer ds, Location l)
                {
                        if (this_variable == null) {
-                               this_variable = new LocalInfo (ds, this, l);
-                               this_variable.Used = true;
-                               this_variable.IsThis = true;
-
-                               Variables.Add ("this", this_variable);
+                               this_variable = new LocalVariable (this, "this", LocalVariable.Flags.IsThis | LocalVariable.Flags.Used, l);
+                               this_variable.Type = ds.CurrentType;
+                               this_variable.PrepareForFlowAnalysis (bc);
                        }
 
                        return this_variable;
@@ -2691,119 +2916,11 @@ namespace Mono.CSharp {
                        set { flags = value ? flags | Flags.IsIterator : flags & ~Flags.IsIterator; }
                }
 
-               //
-               // Block has been converted to expression tree
-               //
-               public bool IsExpressionTree {
-                       get { return (flags & Flags.IsExpressionTree) != 0; }
-               }
-
                public bool IsThisAssigned (BlockContext ec)
                {
                        return this_variable == null || this_variable.IsThisAssigned (ec, this);
                }
 
-               public bool Resolve (FlowBranching parent, BlockContext rc, ParametersCompiled ip, IMethodData md)
-               {
-                       if (resolved)
-                               return true;
-
-                       resolved = true;
-
-                       if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
-                               flags |= Flags.IsExpressionTree;
-
-                       try {
-                               if (!ResolveMeta (rc, ip))
-                                       return false;
-
-                               using (rc.With (ResolveContext.Options.DoFlowAnalysis, true)) {
-                                       FlowBranchingToplevel top_level = rc.StartFlowBranching (this, parent);
-
-                                       if (!Resolve (rc))
-                                               return false;
-
-                                       unreachable = top_level.End ();
-                               }
-                       } catch (Exception) {
-#if PRODUCTION
-                               if (rc.CurrentBlock != null) {
-                                       ec.Report.Error (584, rc.CurrentBlock.StartLocation, "Internal compiler error: Phase Resolve");
-                               } else {
-                                       ec.Report.Error (587, "Internal compiler error: Phase Resolve");
-                               }
-#endif
-                               throw;
-                       }
-
-                       if (rc.ReturnType != TypeManager.void_type && !unreachable) {
-                               if (rc.CurrentAnonymousMethod == null) {
-                                       rc.Report.Error (161, md.Location, "`{0}': not all code paths return a value", md.GetSignatureForError ());
-                                       return false;
-                               } else if (!rc.CurrentAnonymousMethod.IsIterator) {
-                                       rc.Report.Error (1643, rc.CurrentAnonymousMethod.Location, "Not all code paths return a value in anonymous method of type `{0}'",
-                                                         rc.CurrentAnonymousMethod.GetSignatureForError ());
-                                       return false;
-                               }
-                       }
-
-                       return true;
-               }
-
-               bool ResolveMeta (BlockContext ec, ParametersCompiled ip)
-               {
-                       int errors = ec.Report.Errors;
-                       int orig_count = parameters.Count;
-
-                       if (ip != null)
-                               parameters = ip;
-
-                       // Assert: orig_count != parameter.Count => orig_count == 0
-                       if (orig_count != 0 && orig_count != parameters.Count)
-                               throw new InternalErrorException ("parameter information mismatch");
-
-                       int offset = Parent == null ? 0 : Parent.AssignableSlots;
-
-                       for (int i = 0; i < orig_count; ++i) {
-                               Parameter.Modifier mod = parameters.FixedParameters [i].ModFlags;
-
-                               if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT)
-                                       continue;
-
-                               VariableInfo vi = new VariableInfo (ip, i, offset);
-                               parameter_info [i].VariableInfo = vi;
-                               offset += vi.Length;
-                       }
-
-                       ResolveMeta (ec, offset);
-
-                       return ec.Report.Errors == errors;
-               }
-
-               // <summary>
-               //   Check whether all `out' parameters have been assigned.
-               // </summary>
-               public void CheckOutParameters (FlowBranching.UsageVector vector, Location loc)
-               {
-                       if (vector.IsUnreachable)
-                               return;
-
-                       int n = parameter_info == null ? 0 : parameter_info.Length;
-
-                       for (int i = 0; i < n; i++) {
-                               VariableInfo var = parameter_info [i].VariableInfo;
-
-                               if (var == null)
-                                       continue;
-
-                               if (vector.IsAssigned (var, false))
-                                       continue;
-
-                               Report.Error (177, loc, "The out parameter `{0}' must be assigned to before control leaves the current method",
-                                       var.Name);
-                       }
-               }
-
                public override void Emit (EmitContext ec)
                {
                        if (Report.Errors > 0)
@@ -2812,8 +2929,6 @@ namespace Mono.CSharp {
 #if PRODUCTION
                        try {
 #endif
-                       EmitMeta (ec);
-
                        if (ec.HasReturnLabel)
                                ec.ReturnLabel = ec.DefineLabel ();
 
@@ -2859,15 +2974,6 @@ namespace Mono.CSharp {
 #endif
                }
 
-               public override void EmitMeta (EmitContext ec)
-               {
-                       // Avoid declaring an IL variable for this_variable since it is not accessed
-                       // from the generated IL
-                       if (this_variable != null)
-                               Variables.Remove ("this");
-                       base.EmitMeta (ec);
-               }
-
                protected override void EmitSymbolInfo (EmitContext ec)
                {
                        AnonymousExpression ae = ec.CurrentAnonymousMethod;
@@ -2984,12 +3090,14 @@ namespace Mono.CSharp {
 
                public SwitchLabel Clone (CloneContext clonectx)
                {
+                       if (label == null)
+                               return this;
+
                        return new SwitchLabel (label.Clone (clonectx), loc);
                }
        }
 
        public class SwitchSection {
-               // An array of SwitchLabels.
                public readonly List<SwitchLabel> Labels;
                public readonly Block Block;
                
@@ -3003,7 +3111,7 @@ namespace Mono.CSharp {
                {
                        var cloned_labels = new List<SwitchLabel> ();
 
-                       foreach (SwitchLabel sl in cloned_labels)
+                       foreach (SwitchLabel sl in Labels)
                                cloned_labels.Add (sl.Clone (clonectx));
                        
                        return new SwitchSection (cloned_labels, clonectx.LookupBlock (Block));
@@ -3038,6 +3146,7 @@ namespace Mono.CSharp {
                ExpressionStatement string_dictionary;
                FieldExpr switch_cache_field;
                static int unique_counter;
+               ExplicitBlock block;
 
                //
                // Nullable Types support
@@ -3054,13 +3163,20 @@ namespace Mono.CSharp {
                //
                static TypeSpec [] allowed_types;
 
-               public Switch (Expression e, List<SwitchSection> sects, Location l)
+               public Switch (Expression e, ExplicitBlock block, List<SwitchSection> sects, Location l)
                {
                        Expr = e;
+                       this.block = block;
                        Sections = sects;
                        loc = l;
                }
 
+               public ExplicitBlock Block {
+                       get {
+                               return block;
+                       }
+               }
+
                public bool GotDefault {
                        get {
                                return default_section != null;
@@ -3689,7 +3805,7 @@ namespace Mono.CSharp {
                                Arguments get_value_args = new Arguments (1);
                                get_value_args.Add (new Argument (value));
 
-                               Expression get_item = new IndexerAccess (new ElementAccess (switch_cache_field, get_value_args), loc).Resolve (rc);
+                               Expression get_item = new ElementAccess (switch_cache_field, get_value_args, loc).Resolve (rc);
                                if (get_item == null)
                                        return;
 
@@ -3710,6 +3826,12 @@ namespace Mono.CSharp {
                
                protected override void DoEmit (EmitContext ec)
                {
+                       //
+                       // Needed to emit anonymous storey initialization
+                       // Otherwise it does not contain any statements for now
+                       //
+                       block.Emit (ec);
+
                        default_target = ec.DefineLabel ();
                        null_target = ec.DefineLabel ();
 
@@ -3804,6 +3926,25 @@ namespace Mono.CSharp {
                Iterator iter;
                List<ResumableStatement> resume_points;
                int first_resume_pc;
+               protected Statement stmt;
+               Label dispose_try_block;
+               bool prepared_for_dispose, emitted_dispose;
+
+               protected ExceptionStatement (Statement stmt, Location loc)
+               {
+                       this.stmt = stmt;
+                       this.loc = loc;
+               }
+
+               #region Properties
+
+               public Statement Statement {
+                       get {
+                               return stmt;
+                       }
+               }
+
+               #endregion
 
                protected abstract void EmitPreTryBody (EmitContext ec);
                protected abstract void EmitTryBody (EmitContext ec);
@@ -3831,7 +3972,7 @@ namespace Mono.CSharp {
 
                                Label [] labels = new Label [resume_points.Count];
                                for (int i = 0; i < resume_points.Count; ++i)
-                                       labels [i] = ((ResumableStatement) resume_points [i]).PrepareForEmit (ec);
+                                       labels [i] = resume_points [i].PrepareForEmit (ec);
                                ec.Emit (OpCodes.Switch, labels);
                        }
 
@@ -3881,8 +4022,6 @@ namespace Mono.CSharp {
                        resume_points.Add (stmt);
                }
 
-               Label dispose_try_block;
-               bool prepared_for_dispose, emitted_dispose;
                public override Label PrepareForDispose (EmitContext ec, Label end)
                {
                        if (!prepared_for_dispose) {
@@ -3955,14 +4094,13 @@ namespace Mono.CSharp {
 
        public class Lock : ExceptionStatement {
                Expression expr;
-               public Statement Statement;
-               TemporaryVariable temp;
+               TemporaryVariableReference expr_copy;
+               TemporaryVariableReference lock_taken;
                        
-               public Lock (Expression expr, Statement stmt, Location l)
+               public Lock (Expression expr, Statement stmt, Location loc)
+                       : base (stmt, loc)
                {
                        this.expr = expr;
-                       Statement = stmt;
-                       loc = l;
                }
 
                public override bool Resolve (BlockContext ec)
@@ -3973,53 +4111,132 @@ namespace Mono.CSharp {
 
                        if (!TypeManager.IsReferenceType (expr.Type)){
                                ec.Report.Error (185, loc,
-                                             "`{0}' is not a reference type as required by the lock statement",
-                                             TypeManager.CSharpName (expr.Type));
-                               return false;
+                                       "`{0}' is not a reference type as required by the lock statement",
+                                       expr.Type.GetSignatureForError ());
+                       }
+
+                       if (expr.Type.IsGenericParameter) {
+                               expr = Convert.ImplicitTypeParameterConversion (expr, TypeManager.object_type);
+                       }
+
+                       VariableReference lv = expr as VariableReference;
+                       bool locked;
+                       if (lv != null) {
+                               locked = lv.IsLockedByStatement;
+                               lv.IsLockedByStatement = true;
+                       } else {
+                               lv = null;
+                               locked = false;
                        }
 
                        ec.StartFlowBranching (this);
-                       bool ok = Statement.Resolve (ec);
+                       Statement.Resolve (ec);
                        ec.EndFlowBranching ();
 
-                       ok &= base.Resolve (ec);
+                       if (lv != null) {
+                               lv.IsLockedByStatement = locked;
+                       }
 
-                       // Avoid creating libraries that reference the internal
-                       // mcs NullType:
-                       TypeSpec t = expr.Type;
-                       if (t == TypeManager.null_type)
-                               t = TypeManager.object_type;
-                       
-                       temp = new TemporaryVariable (t, loc);
-                       temp.Resolve (ec);
+                       base.Resolve (ec);
 
-                       if (TypeManager.void_monitor_enter_object == null || TypeManager.void_monitor_exit_object == null) {
-                               TypeSpec monitor_type = TypeManager.CoreLookupType (ec.Compiler, "System.Threading", "Monitor", MemberKind.Class, true);
-                               TypeManager.void_monitor_enter_object = TypeManager.GetPredefinedMethod (
-                                       monitor_type, "Enter", loc, TypeManager.object_type);
-                               TypeManager.void_monitor_exit_object = TypeManager.GetPredefinedMethod (
-                                       monitor_type, "Exit", loc, TypeManager.object_type);
-                       }
-                       
-                       return ok;
+                       //
+                       // Have to keep original lock value around to unlock same location
+                       // in the case the original has changed or is null
+                       //
+                       expr_copy = TemporaryVariableReference.Create (TypeManager.object_type, ec.CurrentBlock.Parent, loc);
+                       expr_copy.Resolve (ec);
+
+                       //
+                       // Ensure Monitor methods are available
+                       //
+                       if (ResolvePredefinedMethods (ec) > 1) {
+                               lock_taken = TemporaryVariableReference.Create (TypeManager.bool_type, ec.CurrentBlock.Parent, loc);
+                               lock_taken.Resolve (ec);
+                       }
+
+                       return true;
                }
                
                protected override void EmitPreTryBody (EmitContext ec)
                {
-                       temp.EmitAssign (ec, expr);
-                       temp.Emit (ec);
-                       ec.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
+                       expr_copy.EmitAssign (ec, expr);
+
+                       if (lock_taken != null) {
+                               //
+                               // Initialize ref variable
+                               //
+                               lock_taken.EmitAssign (ec, new BoolLiteral (false, loc));
+                       } else {
+                               //
+                               // Monitor.Enter (expr_copy)
+                               //
+                               expr_copy.Emit (ec);
+                               ec.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
+                       }
                }
 
                protected override void EmitTryBody (EmitContext ec)
                {
+                       //
+                       // Monitor.Enter (expr_copy, ref lock_taken)
+                       //
+                       if (lock_taken != null) {
+                               expr_copy.Emit (ec);
+                               lock_taken.LocalInfo.CreateBuilder (ec);
+                               lock_taken.AddressOf (ec, AddressOp.Load);
+                               ec.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
+                       }
+
                        Statement.Emit (ec);
                }
 
                protected override void EmitFinallyBody (EmitContext ec)
                {
-                       temp.Emit (ec);
+                       //
+                       // if (lock_taken) Monitor.Exit (expr_copy)
+                       //
+                       Label skip = ec.DefineLabel ();
+
+                       if (lock_taken != null) {
+                               lock_taken.Emit (ec);
+                               ec.Emit (OpCodes.Brfalse_S, skip);
+                       }
+
+                       expr_copy.Emit (ec);
                        ec.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object);
+                       ec.MarkLabel (skip);
+               }
+
+               int ResolvePredefinedMethods (ResolveContext rc)
+               {
+                       if (TypeManager.void_monitor_enter_object == null || TypeManager.void_monitor_exit_object == null) {
+                               TypeSpec monitor_type = rc.Module.PredefinedTypes.Monitor.Resolve (loc);
+
+                               if (monitor_type == null)
+                                       return 0;
+
+                               // Try 4.0 Monitor.Enter (object, ref bool) overload first
+                               var filter = MemberFilter.Method ("Enter", 0, new ParametersImported (
+                                       new[] {
+                                                       new ParameterData (null, Parameter.Modifier.NONE),
+                                                       new ParameterData (null, Parameter.Modifier.REF)
+                                               },
+                                       new[] {
+                                                       TypeManager.object_type,
+                                                       TypeManager.bool_type
+                                               }, false), null);
+
+                               TypeManager.void_monitor_enter_object = TypeManager.GetPredefinedMethod (monitor_type, filter, true, loc);
+                               if (TypeManager.void_monitor_enter_object == null) {
+                                       TypeManager.void_monitor_enter_object = TypeManager.GetPredefinedMethod (
+                                               monitor_type, "Enter", loc, TypeManager.object_type);
+                               }
+
+                               TypeManager.void_monitor_exit_object = TypeManager.GetPredefinedMethod (
+                                       monitor_type, "Exit", loc, TypeManager.object_type);
+                       }
+
+                       return TypeManager.void_monitor_enter_object.Parameters.Count;
                }
 
                protected override void CloneTo (CloneContext clonectx, Statement t)
@@ -4027,17 +4244,18 @@ namespace Mono.CSharp {
                        Lock target = (Lock) t;
 
                        target.expr = expr.Clone (clonectx);
-                       target.Statement = Statement.Clone (clonectx);
+                       target.stmt = Statement.Clone (clonectx);
                }
        }
 
        public class Unchecked : Statement {
                public Block Block;
                
-               public Unchecked (Block b)
+               public Unchecked (Block b, Location loc)
                {
                        Block = b;
                        b.Unchecked = true;
+                       this.loc = loc;
                }
 
                public override bool Resolve (BlockContext ec)
@@ -4063,10 +4281,11 @@ namespace Mono.CSharp {
        public class Checked : Statement {
                public Block Block;
                
-               public Checked (Block b)
+               public Checked (Block b, Location loc)
                {
                        Block = b;
                        b.Unchecked = false;
+                       this.loc = loc;
                }
 
                public override bool Resolve (BlockContext ec)
@@ -4092,11 +4311,11 @@ namespace Mono.CSharp {
        public class Unsafe : Statement {
                public Block Block;
 
-               public Unsafe (Block b)
+               public Unsafe (Block b, Location loc)
                {
                        Block = b;
                        Block.Unsafe = true;
-                       loc = b.StartLocation;
+                       this.loc = loc;
                }
 
                public override bool Resolve (BlockContext ec)
@@ -4124,40 +4343,37 @@ namespace Mono.CSharp {
        // 
        // Fixed statement
        //
-       class Fixed : Statement {
-               Expression type;
-               List<KeyValuePair<LocalInfo, Expression>> declarators;
-               Statement statement;
-               TypeSpec expr_type;
-               Emitter[] data;
-               bool has_ret;
-
-               abstract class Emitter
+       public class Fixed : Statement
+       {
+               abstract class Emitter : ShimExpression
                {
-                       protected LocalInfo vi;
-                       protected Expression converted;
+                       protected LocalVariable vi;
 
-                       protected Emitter (Expression expr, LocalInfo li)
+                       protected Emitter (Expression expr, LocalVariable li)
+                               : base (expr)
                        {
-                               converted = expr;
                                vi = li;
                        }
 
-                       public abstract void Emit (EmitContext ec);
                        public abstract void EmitExit (EmitContext ec);
                }
 
                class ExpressionEmitter : Emitter {
-                       public ExpressionEmitter (Expression converted, LocalInfo li) :
+                       public ExpressionEmitter (Expression converted, LocalVariable li) :
                                base (converted, li)
                        {
                        }
 
+                       protected override Expression DoResolve (ResolveContext rc)
+                       {
+                               throw new NotImplementedException ();
+                       }
+
                        public override void Emit (EmitContext ec) {
                                //
                                // Store pointer in pinned location
                                //
-                               converted.Emit (ec);
+                               expr.Emit (ec);
                                vi.EmitAssign (ec);
                        }
 
@@ -4171,39 +4387,46 @@ namespace Mono.CSharp {
 
                class StringEmitter : Emitter
                {
-                       LocalInfo pinned_string;
+                       LocalVariable pinned_string;
 
-                       public StringEmitter (Expression expr, LocalInfo li, Location loc):
-                               base (expr, li)
+                       public StringEmitter (Expression expr, LocalVariable li, Location loc)
+                               base (expr, li)
                        {
-                               pinned_string = new LocalInfo (new TypeExpression (TypeManager.string_type, loc), null, null, loc);
-                               pinned_string.Pinned = true;
                        }
 
-                       public StringEmitter Resolve (ResolveContext rc)
+                       protected override Expression DoResolve (ResolveContext rc)
                        {
-                               pinned_string.Resolve (rc);
+                               pinned_string = new LocalVariable (vi.Block, "$pinned",
+                                       LocalVariable.Flags.FixedVariable | LocalVariable.Flags.CompilerGenerated | LocalVariable.Flags.Used,
+                                       vi.Location);
+
+                               pinned_string.Type = TypeManager.string_type;
 
                                if (TypeManager.int_get_offset_to_string_data == null) {
-                                       TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedProperty (
-                                               TypeManager.runtime_helpers_type, "OffsetToStringData", pinned_string.Location, TypeManager.int32_type);
+                                       var helper = rc.Module.PredefinedTypes.RuntimeHelpers.Resolve (loc);
+                                       if (helper != null) {
+                                               TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedProperty (helper,
+                                                       "OffsetToStringData", pinned_string.Location, TypeManager.int32_type);
+                                       }
                                }
 
+                               eclass = ExprClass.Variable;
+                               type = TypeManager.int32_type;
                                return this;
                        }
 
                        public override void Emit (EmitContext ec)
                        {
-                               pinned_string.ResolveVariable (ec);
+                               pinned_string.CreateBuilder (ec);
 
-                               converted.Emit (ec);
+                               expr.Emit (ec);
                                pinned_string.EmitAssign (ec);
 
                                // TODO: Should use Binary::Add
                                pinned_string.Emit (ec);
                                ec.Emit (OpCodes.Conv_I);
 
-                               PropertyExpr pe = new PropertyExpr (pinned_string.VariableType, TypeManager.int_get_offset_to_string_data, pinned_string.Location);
+                               PropertyExpr pe = new PropertyExpr (TypeManager.int_get_offset_to_string_data, pinned_string.Location);
                                //pe.InstanceExpression = pinned_string;
                                pe.Resolve (new ResolveContext (ec.MemberContext)).Emit (ec);
 
@@ -4218,49 +4441,20 @@ namespace Mono.CSharp {
                        }
                }
 
-               public Fixed (Expression type, List<KeyValuePair<LocalInfo, Expression>> decls, Statement stmt, Location l)
-               {
-                       this.type = type;
-                       declarators = decls;
-                       statement = stmt;
-                       loc = l;
-               }
-
-               public Statement Statement {
-                       get { return statement; }
-               }
-
-               public override bool Resolve (BlockContext ec)
+               public class VariableDeclaration : BlockVariableDeclaration
                {
-                       if (!ec.IsUnsafe){
-                               Expression.UnsafeError (ec, loc);
-                               return false;
-                       }
-                       
-                       TypeExpr texpr = type.ResolveAsContextualType (ec, false);
-                       if (texpr == null) {
-                               if (type is VarExpr)
-                                       ec.Report.Error (821, type.Location, "A fixed statement cannot use an implicitly typed local variable");
-
-                               return false;
+                       public VariableDeclaration (FullNamedExpression type, LocalVariable li)
+                               : base (type, li)
+                       {
                        }
 
-                       expr_type = texpr.Type;
-
-                       data = new Emitter [declarators.Count];
-
-                       if (!expr_type.IsPointer){
-                               ec.Report.Error (209, loc, "The type of locals declared in a fixed statement must be a pointer type");
-                               return false;
-                       }
-                       
-                       int i = 0;
-                       foreach (var p in declarators){
-                               LocalInfo vi = p.Key;
-                               Expression e = p.Value;
-                               
-                               vi.VariableInfo.SetAssigned (ec);
-                               vi.SetReadOnlyContext (LocalInfo.ReadOnlyContext.Fixed);
+                       protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
+                       {
+                               if (!Variable.Type.IsPointer && li == Variable) {
+                                       bc.Report.Error (209, TypeExpression.Location,
+                                               "The type of locals declared in a fixed statement must be a pointer type");
+                                       return null;
+                               }
 
                                //
                                // The rules for the possible declarators are pretty wise,
@@ -4273,88 +4467,119 @@ namespace Mono.CSharp {
                                // is present, so we need to test for this particular case.
                                //
 
-                               if (e is Cast){
-                                       ec.Report.Error (254, loc, "The right hand side of a fixed statement assignment may not be a cast expression");
-                                       return false;
+                               if (initializer is Cast) {
+                                       bc.Report.Error (254, initializer.Location, "The right hand side of a fixed statement assignment may not be a cast expression");
+                                       return null;
                                }
 
-                               using (ec.Set (ResolveContext.Options.FixedInitializerScope)) {
-                                       e = e.Resolve (ec);
-                               }
+                               initializer = initializer.Resolve (bc);
 
-                               if (e == null)
-                                       return false;
+                               if (initializer == null)
+                                       return null;
 
                                //
-                               // Case 2: Array
+                               // Case 1: Array
                                //
-                               if (e.Type.IsArray){
-                                       TypeSpec array_type = TypeManager.GetElementType (e.Type);
-                                       
+                               if (initializer.Type.IsArray) {
+                                       TypeSpec array_type = TypeManager.GetElementType (initializer.Type);
+
                                        //
                                        // Provided that array_type is unmanaged,
                                        //
-                                       if (!TypeManager.VerifyUnmanaged (ec.Compiler, array_type, loc))
-                                               return false;
+                                       if (!TypeManager.VerifyUnmanaged (bc.Compiler, array_type, loc))
+                                               return null;
 
                                        //
                                        // and T* is implicitly convertible to the
                                        // pointer type given in the fixed statement.
                                        //
-                                       ArrayPtr array_ptr = new ArrayPtr (e, array_type, loc);
-                                       
+                                       ArrayPtr array_ptr = new ArrayPtr (initializer, array_type, loc);
+
                                        Expression converted = Convert.ImplicitConversionRequired (
-                                               ec, array_ptr, vi.VariableType, loc);
+                                               bc, array_ptr, li.Type, loc);
                                        if (converted == null)
-                                               return false;
-                                       
+                                               return null;
+
                                        //
                                        // 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, e, new NullLiteral (loc), loc),
-                                               new Binary (Binary.Operator.Equality, new MemberAccess (e, "Length"), new IntConstant (0, loc), loc), loc)),
+                                               new Binary (Binary.Operator.Equality, initializer, new NullLiteral (loc), loc),
+                                               new Binary (Binary.Operator.Equality, new MemberAccess (initializer, "Length"), new IntConstant (0, loc), loc), loc)),
                                                        new NullPointer (loc),
-                                                       converted);
-
-                                       converted = converted.Resolve (ec);                                     
+                                                       converted, loc);
 
-                                       data [i] = new ExpressionEmitter (converted, vi);
-                                       i++;
+                                       converted = converted.Resolve (bc);
 
-                                       continue;
+                                       return new ExpressionEmitter (converted, li);
                                }
 
                                //
-                               // Case 3: string
+                               // Case 2: string
                                //
-                               if (e.Type == TypeManager.string_type){
-                                       data [i] = new StringEmitter (e, vi, loc).Resolve (ec);
-                                       i++;
-                                       continue;
+                               if (initializer.Type == TypeManager.string_type) {
+                                       return new StringEmitter (initializer, li, loc).Resolve (bc);
                                }
 
-                               // Case 4: fixed buffer
-                               if (e is FixedBufferPtr) {
-                                       data [i++] = new ExpressionEmitter (e, vi);
-                                       continue;
+                               // Case 3: fixed buffer
+                               if (initializer is FixedBufferPtr) {
+                                       return new ExpressionEmitter (initializer, li);
                                }
 
                                //
-                               // Case 1: & object.
+                               // Case 4: & object.
                                //
-                               Unary u = e as Unary;
+                               bool already_fixed = true;
+                               Unary u = initializer as Unary;
                                if (u != null && u.Oper == Unary.Operator.AddressOf) {
                                        IVariableReference vr = u.Expr as IVariableReference;
                                        if (vr == null || !vr.IsFixed) {
-                                               data [i] = new ExpressionEmitter (e, vi);
+                                               already_fixed = false;
                                        }
                                }
 
-                               if (data [i++] == null)
-                                       ec.Report.Error (213, vi.Location, "You cannot use the fixed statement to take the address of an already fixed expression");
+                               if (already_fixed) {
+                                       bc.Report.Error (213, loc, "You cannot use the fixed statement to take the address of an already fixed expression");
+                               }
+
+                               initializer = Convert.ImplicitConversionRequired (bc, initializer, li.Type, loc);
+                               return new ExpressionEmitter (initializer, li);
+                       }
+               }
+
+
+               VariableDeclaration decl;
+               Statement statement;
+               bool has_ret;
+
+               public Fixed (VariableDeclaration decl, Statement stmt, Location l)
+               {
+                       this.decl = decl;
+                       statement = stmt;
+                       loc = l;
+               }
+
+               #region Properties
+
+               public Statement Statement {
+                       get {
+                               return statement;
+                       }
+               }
+
+               public BlockVariableDeclaration Variables {
+                       get {
+                               return decl;
+                       }
+               }
+
+               #endregion
 
-                               e = Convert.ImplicitConversionRequired (ec, e, expr_type, loc);
+               public override bool Resolve (BlockContext ec)
+               {
+                       using (ec.Set (ResolveContext.Options.FixedInitializerScope)) {
+                               if (!decl.Resolve (ec))
+                                       return false;
                        }
 
                        ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
@@ -4367,8 +4592,13 @@ namespace Mono.CSharp {
                
                protected override void DoEmit (EmitContext ec)
                {
-                       for (int i = 0; i < data.Length; i++) {
-                               data [i].Emit (ec);
+                       decl.Variable.CreateBuilder (ec);
+                       decl.Initializer.Emit (ec);
+                       if (decl.Declarators != null) {
+                               foreach (var d in decl.Declarators) {
+                                       d.Variable.CreateBuilder (ec);
+                                       d.Initializer.Emit (ec);
+                               }
                        }
 
                        statement.Emit (ec);
@@ -4379,8 +4609,11 @@ namespace Mono.CSharp {
                        //
                        // Clear the pinned variable
                        //
-                       for (int i = 0; i < data.Length; i++) {
-                               data [i].EmitExit (ec);
+                       ((Emitter) decl.Initializer).EmitExit (ec);
+                       if (decl.Declarators != null) {
+                               foreach (var d in decl.Declarators) {
+                                       ((Emitter)d.Initializer).EmitExit (ec);
+                               }
                        }
                }
 
@@ -4388,32 +4621,31 @@ namespace Mono.CSharp {
                {
                        Fixed target = (Fixed) t;
 
-                       target.type = type.Clone (clonectx);
-                       target.declarators = new List<KeyValuePair<LocalInfo, Expression>> (declarators.Count);
-                       foreach (var p in declarators) {
-                               target.declarators.Add (new KeyValuePair<LocalInfo, Expression> (
-                                       clonectx.LookupVariable (p.Key), p.Value.Clone (clonectx)));
-                       }
-                       
+                       target.decl = (VariableDeclaration) decl.Clone (clonectx);
                        target.statement = statement.Clone (clonectx);
                }
        }
-       
-       public class Catch : Statement {
-               public readonly string Name;
-               public Block  Block;
-               public Block  VarBlock;
 
-               Expression type_expr;
+       public class Catch : Statement
+       {
+               Block block;
+               LocalVariable li;
+               FullNamedExpression type_expr;
+               CompilerAssign assign;
                TypeSpec type;
                
-               public Catch (Expression type, string name, Block block, Block var_block, Location l)
+               public Catch (Block block, Location loc)
                {
-                       type_expr = type;
-                       Name = name;
-                       Block = block;
-                       VarBlock = var_block;
-                       loc = l;
+                       this.block = block;
+                       this.loc = loc;
+               }
+
+               #region Properties
+
+               public Block Block {
+                       get {
+                               return block;
+                       }
                }
 
                public TypeSpec CatchType {
@@ -4428,38 +4660,55 @@ namespace Mono.CSharp {
                        }
                }
 
+               public FullNamedExpression TypeExpression {
+                       get {
+                               return type_expr;
+                       }
+                       set {
+                               type_expr = value;
+                       }
+               }
+
+               public LocalVariable Variable {
+                       get {
+                               return li;
+                       }
+                       set {
+                               li = value;
+                       }
+               }
+
+               #endregion
+
                protected override void DoEmit (EmitContext ec)
                {
-                       if (CatchType != null)
-                               ec.BeginCatchBlock (CatchType);
-                       else
+                       if (IsGeneral)
                                ec.BeginCatchBlock (TypeManager.object_type);
+                       else
+                               ec.BeginCatchBlock (CatchType);
 
-                       if (VarBlock != null)
-                               VarBlock.Emit (ec);
-
-                       if (Name != null) {
-                               // TODO: Move to resolve
-                               LocalVariableReference lvr = new LocalVariableReference (Block, Name, loc);
-                               lvr.Resolve (new ResolveContext (ec.MemberContext));
-                               
-                               // Only to make verifier happy
-                               if (TypeManager.IsGenericParameter (lvr.Type))
-                                       ec.Emit (OpCodes.Unbox_Any, lvr.Type);
+                       if (li != null) {
+                               li.CreateBuilder (ec);
 
-                               Expression source;
-                               if (lvr.IsHoisted) {
-                                       LocalTemporary lt = new LocalTemporary (lvr.Type);
+                               //
+                               // Special case hoisted catch variable, we have to use a temporary variable
+                               // to pass via anonymous storey initialization with the value still on top
+                               // of the stack
+                               //
+                               if (li.HoistedVariant != null) {
+                                       LocalTemporary lt = new LocalTemporary (li.Type);
+                                       SymbolWriter.OpenCompilerGeneratedBlock (ec);
                                        lt.Store (ec);
-                                       source = lt;
-                               } else {
-                                       // Variable is at the top of the stack
-                                       source = EmptyExpression.Null;
-                               }
+                                       SymbolWriter.CloseCompilerGeneratedBlock (ec);
 
-                               lvr.EmitAssign (ec, source, false, false);
-                       } else
+                                       // switch to assigning from the temporary variable and not from top of the stack
+                                       assign.UpdateSource (lt);
+                               }
+                       } else {
+                               SymbolWriter.OpenCompilerGeneratedBlock (ec);
                                ec.Emit (OpCodes.Pop);
+                               SymbolWriter.CloseCompilerGeneratedBlock (ec);
+                       }
 
                        Block.Emit (ec);
                }
@@ -4473,23 +4722,23 @@ namespace Mono.CSharp {
                                                return false;
 
                                        type = te.Type;
-
-                                       if (type != TypeManager.exception_type && !TypeManager.IsSubclassOf (type, TypeManager.exception_type)){
+                                       if (type != TypeManager.exception_type && !TypeSpec.IsBaseClass (type, TypeManager.exception_type, false)) {
                                                ec.Report.Error (155, loc, "The type caught or thrown must be derived from System.Exception");
-                                               return false;
-                                       }
-                               } else
-                                       type = null;
+                                       } else if (li != null) {
+                                               li.Type = type;
+                                               li.PrepareForFlowAnalysis (ec);
 
-                               if (!Block.Resolve (ec))
-                                       return false;
+                                               // source variable is at the top of the stack
+                                               Expression source = new EmptyExpression (li.Type);
+                                               if (li.Type.IsGenericParameter)
+                                                       source = new UnboxCast (source, li.Type);
 
-                               // Even though VarBlock surrounds 'Block' we resolve it later, so that we can correctly
-                               // emit the "unused variable" warnings.
-                               if (VarBlock != null)
-                                       return VarBlock.Resolve (ec);
+                                               assign = new CompilerAssign (new LocalVariableReference (li, loc), source, loc);
+                                               Block.AddScopeStatement (new StatementExpression (assign));
+                                       }
+                               }
 
-                               return true;
+                               return Block.Resolve (ec);
                        }
                }
 
@@ -4498,22 +4747,19 @@ namespace Mono.CSharp {
                        Catch target = (Catch) t;
 
                        if (type_expr != null)
-                               target.type_expr = type_expr.Clone (clonectx);
-                       if (VarBlock != null)
-                               target.VarBlock = clonectx.LookupBlock (VarBlock);                      
-                       target.Block = clonectx.LookupBlock (Block);
+                               target.type_expr = (FullNamedExpression) type_expr.Clone (clonectx);
+
+                       target.block = clonectx.LookupBlock (block);
                }
        }
 
        public class TryFinally : ExceptionStatement {
-               Statement stmt;
                Block fini;
 
-               public TryFinally (Statement stmt, Block fini, Location l)
+               public TryFinally (Statement stmt, Block fini, Location loc)
+                        : base (stmt, loc)
                {
-                       this.stmt = stmt;
                        this.fini = fini;
-                       loc = l;
                }
 
                public override bool Resolve (BlockContext ec)
@@ -4598,14 +4844,6 @@ namespace Mono.CSharp {
                        foreach (Catch c in Specific){
                                ec.CurrentBranching.CreateSibling (c.Block, FlowBranching.SiblingType.Catch);
 
-                               if (c.Name != null) {
-                                       LocalInfo vi = c.Block.GetLocalInfo (c.Name);
-                                       if (vi == null)
-                                               throw new Exception ();
-
-                                       vi.VariableInfo = null;
-                               }
-
                                if (!c.Resolve (ec)) {
                                        ok = false;
                                        continue;
@@ -4613,7 +4851,7 @@ namespace Mono.CSharp {
 
                                TypeSpec resolved_type = c.CatchType;
                                for (int ii = 0; ii < last_index; ++ii) {
-                                       if (resolved_type == prev_catches [ii] || TypeManager.IsSubclassOf (resolved_type, prev_catches [ii])) {
+                                       if (resolved_type == prev_catches[ii] || TypeSpec.IsBaseClass (resolved_type, prev_catches[ii], true)) {
                                                ec.Report.Error (160, c.loc,
                                                        "A previous catch clause already catches all exceptions of this or a super type `{0}'",
                                                        TypeManager.CSharpName (prev_catches [ii]));
@@ -4625,12 +4863,18 @@ namespace Mono.CSharp {
                        }
 
                        if (General != null) {
-                               if (CodeGen.Assembly.WrapNonExceptionThrows) {
-                                       foreach (Catch c in Specific){
-                                               if (c.CatchType == TypeManager.exception_type && PredefinedAttributes.Get.RuntimeCompatibility.IsDefined) {
-                                                       ec.Report.Warning (1058, 1, c.loc, "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'");
-                                               }
-                                       }
+                               foreach (Catch c in Specific) {
+                                       if (c.CatchType != TypeManager.exception_type)
+                                               continue;
+
+                                       if (!ec.Module.DeclaringAssembly.WrapNonExceptionThrows)
+                                               continue;
+
+                                       if (!ec.Module.PredefinedAttributes.RuntimeCompatibility.IsDefined)
+                                               continue;
+
+                                       ec.Report.Warning (1058, 1, c.loc,
+                                               "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'");
                                }
 
                                ec.CurrentBranching.CreateSibling (General.Block, FlowBranching.SiblingType.Catch);
@@ -4686,133 +4930,185 @@ namespace Mono.CSharp {
                }
        }
 
-       // FIXME: Why is it almost exact copy of Using ??
-       public class UsingTemporary : ExceptionStatement {
-               TemporaryVariable local_copy;
-               public Statement Statement;
-               Expression expr;
-               TypeSpec expr_type;
-
-               public UsingTemporary (Expression expr, Statement stmt, Location l)
+       public class Using : ExceptionStatement
+       {
+               public class VariableDeclaration : BlockVariableDeclaration
                {
-                       this.expr = expr;
-                       Statement = stmt;
-                       loc = l;
-               }
+                       Statement dispose_call;
 
-               public override bool Resolve (BlockContext ec)
-               {
-                       expr = expr.Resolve (ec);
-                       if (expr == null)
-                               return false;
+                       public VariableDeclaration (FullNamedExpression type, LocalVariable li)
+                               : base (type, li)
+                       {
+                       }
 
-                       expr_type = expr.Type;
+                       public VariableDeclaration (LocalVariable li, Location loc)
+                               : base (li)
+                       {
+                               this.loc = loc;
+                       }
 
-                       if (!expr_type.ImplementsInterface (TypeManager.idisposable_type) &&
-                               Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) {
-                               if (expr_type != InternalType.Dynamic) {
-                                       Using.Error_IsNotConvertibleToIDisposable (ec, expr);
-                                       return false;
-                               }
+                       public VariableDeclaration (Expression expr)
+                               : base (null)
+                       {
+                               loc = expr.Location;
+                               Initializer = expr;
+                       }
+
+                       #region Properties
+
+                       public bool IsNested { get; private set; }
 
-                               expr = Convert.ImplicitConversionRequired (ec, expr, TypeManager.idisposable_type, loc);
-                               expr_type = expr.Type;
+                       #endregion
+
+                       public void EmitDispose (EmitContext ec)
+                       {
+                               dispose_call.Emit (ec);
                        }
 
-                       local_copy = new TemporaryVariable (expr_type, loc);
-                       local_copy.Resolve (ec);
+                       public override bool Resolve (BlockContext bc)
+                       {
+                               if (IsNested)
+                                       return true;
+
+                               return base.Resolve (bc);
+                       }
 
-                       ec.StartFlowBranching (this);
+                       public Expression ResolveExpression (BlockContext bc)
+                       {
+                               var e = Initializer.Resolve (bc);
+                               if (e == null)
+                                       return null;
 
-                       bool ok = Statement.Resolve (ec);
+                               li = LocalVariable.CreateCompilerGenerated (e.Type, bc.CurrentBlock, loc);
+                               Initializer = ResolveInitializer (bc, Variable, e);
+                               return e;
+                       }
 
-                       ec.EndFlowBranching ();
+                       protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
+                       {
+                               if (li.Type == InternalType.Dynamic) {
+                                       initializer = initializer.Resolve (bc);
+                                       if (initializer == null)
+                                               return null;
 
-                       ok &= base.Resolve (ec);
+                                       // Once there is dynamic used defer conversion to runtime even if we know it will never succeed
+                                       Arguments args = new Arguments (1);
+                                       args.Add (new Argument (initializer));
+                                       initializer = new DynamicConversion (TypeManager.idisposable_type, 0, args, initializer.Location).Resolve (bc);
+                                       if (initializer == null)
+                                               return null;
 
-                       if (TypeManager.void_dispose_void == null) {
-                               TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
-                                       TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes);
+                                       var var = LocalVariable.CreateCompilerGenerated (TypeManager.idisposable_type, bc.CurrentBlock, loc);
+                                       dispose_call = CreateDisposeCall (bc, var);
+                                       dispose_call.Resolve (bc);
+
+                                       return base.ResolveInitializer (bc, li, new SimpleAssign (var.CreateReferenceExpression (bc, loc), initializer, loc));
+                               }
+
+                               if (li == Variable) {
+                                       CheckIDiposableConversion (bc, li, initializer);
+                                       dispose_call = CreateDisposeCall (bc, li);
+                                       dispose_call.Resolve (bc);
+                               }
+
+                               return base.ResolveInitializer (bc, li, initializer);
                        }
 
-                       return ok;
-               }
+                       protected virtual void CheckIDiposableConversion (BlockContext bc, LocalVariable li, Expression initializer)
+                       {
+                               var type = li.Type;
 
-               protected override void EmitPreTryBody (EmitContext ec)
-               {
-                       local_copy.EmitAssign (ec, expr);
-               }
+                               if (type != TypeManager.idisposable_type && !type.ImplementsInterface (TypeManager.idisposable_type, false)) {
+                                       if (TypeManager.IsNullableType (type)) {
+                                               // it's handled in CreateDisposeCall
+                                               return;
+                                       }
 
-               protected override void EmitTryBody (EmitContext ec)
-               {
-                       Statement.Emit (ec);
-               }
+                                       bc.Report.SymbolRelatedToPreviousError (type);
+                                       var loc = type_expr == null ? initializer.Location : type_expr.Location;
+                                       bc.Report.Error (1674, loc, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
+                                               type.GetSignatureForError ());
 
-               protected override void EmitFinallyBody (EmitContext ec)
-               {
-                       if (!TypeManager.IsStruct (expr_type)) {
-                               Label skip = ec.DefineLabel ();
-                               local_copy.Emit (ec);
-                               ec.Emit (OpCodes.Brfalse, skip);
-                               local_copy.Emit (ec);
-                               ec.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
-                               ec.MarkLabel (skip);
-                               return;
+                                       return;
+                               }
+                       }
+
+                       protected virtual Statement CreateDisposeCall (BlockContext bc, LocalVariable lv)
+                       {
+                               var lvr = lv.CreateReferenceExpression (bc, lv.Location);
+                               var type = lv.Type;
+                               var loc = lv.Location;
+
+                               if (TypeManager.void_dispose_void == null) {
+                                       TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
+                                               TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes);
+                               }
+
+                               var dispose_mg = MethodGroupExpr.CreatePredefined (TypeManager.void_dispose_void, TypeManager.idisposable_type, loc);
+                               dispose_mg.InstanceExpression = TypeManager.IsNullableType (type) ?
+                                       new Cast (new TypeExpression (TypeManager.idisposable_type, loc), lvr, loc).Resolve (bc) :
+                                       lvr;
+
+                               Statement dispose = new StatementExpression (new Invocation (dispose_mg, null));
+
+                               // Add conditional call when disposing possible null variable
+                               if (!type.IsStruct || TypeManager.IsNullableType (type))
+                                       dispose = new If (new Binary (Binary.Operator.Inequality, lvr, new NullLiteral (loc), loc), dispose, loc);
+
+                               return dispose;
                        }
 
-                       MethodSpec ms = MemberCache.FindMember (expr_type,
-                               MemberFilter.Method ("Dispose", 0, ParametersCompiled.EmptyReadOnlyParameters, TypeManager.void_type),
-                               BindingRestriction.InstanceOnly) as MethodSpec;
+                       public Statement RewriteForDeclarators (BlockContext bc, Statement stmt)
+                       {
+                               for (int i = declarators.Count - 1; i >= 0; --i) {
+                                       var d = declarators [i];
+                                       var vd = new VariableDeclaration (d.Variable, type_expr.Location);
+                                       vd.Initializer = d.Initializer;
+                                       vd.IsNested = true;
+                                       vd.dispose_call = CreateDisposeCall (bc, d.Variable);
+                                       vd.dispose_call.Resolve (bc);
+
+                                       stmt = new Using (vd, stmt, d.Variable.Location);
+                               }
 
-                       if (ms == null) {
-                               local_copy.Emit (ec);
-                               ec.Emit (OpCodes.Box, expr_type);
-                               ec.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
-                               return;
+                               declarators = null;
+                               return stmt;
                        }
-
-                       local_copy.AddressOf (ec, AddressOp.Load);
-                       ec.Emit (OpCodes.Call, ms);
                }
 
-               protected override void CloneTo (CloneContext clonectx, Statement t)
-               {
-                       UsingTemporary target = (UsingTemporary) t;
+               VariableDeclaration decl;
 
-                       target.expr = expr.Clone (clonectx);
-                       target.Statement = Statement.Clone (clonectx);
+               public Using (VariableDeclaration decl, Statement stmt, Location loc)
+                       : base (stmt, loc)
+               {
+                       this.decl = decl;
                }
-       }
 
-       public class Using : ExceptionStatement {
-               Statement stmt;
-               public Statement EmbeddedStatement {
-                       get { return stmt is Using ? ((Using) stmt).EmbeddedStatement : stmt; }
+               public Using (Expression expr, Statement stmt, Location loc)
+                       : base (stmt, loc)
+               {
+                       this.decl = new VariableDeclaration (expr);
                }
 
-               Expression var;
-               Expression init;
-
-               ExpressionStatement assign;
+               #region Properties
 
-               public Using (Expression var, Expression init, Statement stmt, Location l)
-               {
-                       this.var = var;
-                       this.init = init;
-                       this.stmt = stmt;
-                       loc = l;
+               public Expression Expression {
+                       get {
+                               return decl.Variable == null ? decl.Initializer : null;
+                       }
                }
 
-               static public void Error_IsNotConvertibleToIDisposable (BlockContext ec, Expression expr)
-               {
-                       ec.Report.SymbolRelatedToPreviousError (expr.Type);
-                       ec.Report.Error (1674, expr.Location, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
-                               TypeManager.CSharpName (expr.Type));
+               public BlockVariableDeclaration Variables {
+                       get {
+                               return decl;
+                       }
                }
 
+               #endregion
+
                protected override void EmitPreTryBody (EmitContext ec)
                {
-                       assign.EmitStatement (ec);
+                       decl.Emit (ec);
                }
 
                protected override void EmitTryBody (EmitContext ec)
@@ -4822,74 +5118,52 @@ namespace Mono.CSharp {
 
                protected override void EmitFinallyBody (EmitContext ec)
                {
-                       Label skip = ec.DefineLabel ();
-
-                       bool emit_null_check = !TypeManager.IsValueType (var.Type);
-                       if (emit_null_check) {
-                               var.Emit (ec);
-                               ec.Emit (OpCodes.Brfalse, skip);
-                       }
-
-                       Invocation.EmitCall (ec, false, var, TypeManager.void_dispose_void, null, loc);
-
-                       if (emit_null_check)
-                               ec.MarkLabel (skip);
+                       decl.EmitDispose (ec);
                }
 
                public override bool Resolve (BlockContext ec)
                {
-                       if (!ResolveVariable (ec))
-                               return false;
-
-                       ec.StartFlowBranching (this);
-
-                       bool ok = stmt.Resolve (ec);
+                       VariableReference vr;
+                       bool vr_locked = false;
 
-                       ec.EndFlowBranching ();
+                       using (ec.Set (ResolveContext.Options.UsingInitializerScope)) {
+                               if (decl.Variable == null) {
+                                       vr = decl.ResolveExpression (ec) as VariableReference;
+                                       if (vr != null) {
+                                               vr_locked = vr.IsLockedByStatement;
+                                               vr.IsLockedByStatement = true;
+                                       }
+                               } else {
+                                       if (!decl.Resolve (ec))
+                                               return false;
 
-                       ok &= base.Resolve (ec);
+                                       if (decl.Declarators != null) {
+                                               stmt = decl.RewriteForDeclarators (ec, stmt);
+                                       }
 
-                       if (TypeManager.void_dispose_void == null) {
-                               TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
-                                       TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes);
+                                       vr = null;
+                               }
                        }
 
-                       return ok;
-               }
+                       ec.StartFlowBranching (this);
 
-               bool ResolveVariable (BlockContext ec)
-               {
-                       assign = new SimpleAssign (var, init, loc);
-                       assign = assign.ResolveStatement (ec);
-                       if (assign == null)
-                               return false;
+                       stmt.Resolve (ec);
 
-                       if (assign.Type == TypeManager.idisposable_type || assign.Type.ImplementsInterface (TypeManager.idisposable_type)) {
-                               return true;
-                       }
+                       ec.EndFlowBranching ();
 
-                       Expression e = Convert.ImplicitConversionStandard (ec, assign, TypeManager.idisposable_type, var.Location);
-                       if (e == null) {
-                               if (assign.Type == InternalType.Dynamic) {
-                                       e = Convert.ImplicitConversionRequired (ec, assign, TypeManager.idisposable_type, loc);
-                                       var = new TemporaryVariable (e.Type, loc);
-                                       assign = new SimpleAssign (var, e, loc).ResolveStatement (ec);
-                                       return true;
-                               }
+                       if (vr != null)
+                               vr.IsLockedByStatement = vr_locked;
 
-                               Error_IsNotConvertibleToIDisposable (ec, var);
-                               return false;
-                       }
+                       base.Resolve (ec);
 
-                       throw new NotImplementedException ("covariance?");
+                       return true;
                }
 
                protected override void CloneTo (CloneContext clonectx, Statement t)
                {
                        Using target = (Using) t;
 
-                       target.var = var.Clone (clonectx);
-                       target.init = init.Clone (clonectx);
+                       target.decl = (VariableDeclaration) decl.Clone (clonectx);
                        target.stmt = stmt.Clone (clonectx);
                }
        }
@@ -4901,45 +5175,28 @@ namespace Mono.CSharp {
 
                sealed class ArrayForeach : Statement
                {
-                       class ArrayCounter : TemporaryVariable
-                       {
-                               StatementExpression increment;
-
-                               public ArrayCounter (Location loc)
-                                       : base (TypeManager.int32_type, loc)
-                               {
-                               }
-
-                               public void ResolveIncrement (BlockContext ec)
-                               {
-                                       increment = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, this, loc));
-                                       increment.Resolve (ec);
-                               }
-
-                               public void EmitIncrement (EmitContext ec)
-                               {
-                                       increment.Emit (ec);
-                               }
-                       }
-
                        readonly Foreach for_each;
                        readonly Statement statement;
 
                        Expression conv;
-                       TemporaryVariable[] lengths;
+                       TemporaryVariableReference[] lengths;
                        Expression [] length_exprs;
-                       ArrayCounter[] counter;
+                       StatementExpression[] counter;
+                       TemporaryVariableReference[] variables;
 
-                       TemporaryVariable copy;
+                       TemporaryVariableReference copy;
                        Expression access;
+                       LocalVariableReference variable;
 
                        public ArrayForeach (Foreach @foreach, int rank)
                        {
                                for_each = @foreach;
                                statement = for_each.statement;
                                loc = @foreach.loc;
+                               variable = new LocalVariableReference (for_each.variable, loc);
 
-                               counter = new ArrayCounter [rank];
+                               counter = new StatementExpression[rank];
+                               variables = new TemporaryVariableReference[rank];
                                length_exprs = new Expression [rank];
 
                                //
@@ -4947,7 +5204,7 @@ namespace Mono.CSharp {
                                // multi-dimensional arrays
                                //
                                if (rank > 1)
-                                       lengths = new TemporaryVariable [rank];
+                                       lengths = new TemporaryVariableReference [rank];
                        }
 
                        protected override void CloneTo (CloneContext clonectx, Statement target)
@@ -4957,30 +5214,33 @@ namespace Mono.CSharp {
 
                        public override bool Resolve (BlockContext ec)
                        {
-                               copy = new TemporaryVariable (for_each.expr.Type, loc);
+                               Block variables_block = variable.local_info.Block;
+                               copy = TemporaryVariableReference.Create (for_each.expr.Type, variables_block, loc);
                                copy.Resolve (ec);
 
                                int rank = length_exprs.Length;
                                Arguments list = new Arguments (rank);
                                for (int i = 0; i < rank; i++) {
-                                       counter [i] = new ArrayCounter (loc);
-                                       counter [i].ResolveIncrement (ec);                                      
+                                       var v = TemporaryVariableReference.Create (TypeManager.int32_type, variables_block, loc);
+                                       variables[i] = v;
+                                       counter[i] = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, v, loc));
+                                       counter[i].Resolve (ec);
 
                                        if (rank == 1) {
                                                length_exprs [i] = new MemberAccess (copy, "Length").Resolve (ec);
                                        } else {
-                                               lengths [i] = new TemporaryVariable (TypeManager.int32_type, loc);
-                                               lengths [i].Resolve (ec);
+                                               lengths[i] = TemporaryVariableReference.Create (TypeManager.int32_type, variables_block, loc);
+                                               lengths[i].Resolve (ec);
 
                                                Arguments args = new Arguments (1);
                                                args.Add (new Argument (new IntConstant (i, loc)));
                                                length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec);
                                        }
 
-                                       list.Add (new Argument (counter [i]));
+                                       list.Add (new Argument (v));
                                }
 
-                               access = new ElementAccess (copy, list).Resolve (ec);
+                               access = new ElementAccess (copy, list, loc).Resolve (ec);
                                if (access == null)
                                        return false;
 
@@ -5004,9 +5264,8 @@ namespace Mono.CSharp {
                                ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
                                ec.CurrentBranching.CreateSibling ();
 
-                               for_each.variable = for_each.variable.ResolveLValue (ec, conv);
-                               if (for_each.variable == null)
-                                       ok = false;
+                               variable.local_info.Type = conv.Type;
+                               variable.Resolve (ec);
 
                                ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
                                if (!statement.Resolve (ec))
@@ -5039,23 +5298,24 @@ namespace Mono.CSharp {
 
                                IntConstant zero = new IntConstant (0, loc);
                                for (int i = 0; i < rank; i++) {
-                                       counter [i].EmitAssign (ec, zero);
+                                       variables [i].EmitAssign (ec, zero);
 
                                        ec.Emit (OpCodes.Br, test [i]);
                                        ec.MarkLabel (loop [i]);
                                }
 
-                               ((IAssignMethod) for_each.variable).EmitAssign (ec, conv, false, false);
+                               variable.local_info.CreateBuilder (ec);
+                               variable.EmitAssign (ec, conv, false, false);
 
                                statement.Emit (ec);
 
                                ec.MarkLabel (ec.LoopBegin);
 
                                for (int i = rank - 1; i >= 0; i--){
-                                       counter [i].EmitIncrement (ec);
+                                       counter [i].Emit (ec);
 
                                        ec.MarkLabel (test [i]);
-                                       counter [i].Emit (ec);
+                                       variables [i].Emit (ec);
 
                                        if (lengths != null)
                                                lengths [i].Emit (ec);
@@ -5069,21 +5329,21 @@ namespace Mono.CSharp {
                        }
                }
 
-               sealed class CollectionForeach : Statement
+               sealed class CollectionForeach : Statement, OverloadResolver.IErrorHandler
                {
-                       class CollectionForeachStatement : Statement
+                       class Body : Statement
                        {
                                TypeSpec type;
-                               Expression variable, current, conv;
+                               LocalVariableReference variable;
+                               Expression current, conv;
                                Statement statement;
-                               Assign assign;
 
-                               public CollectionForeachStatement (TypeSpec type, Expression variable,
+                               public Body (TypeSpec type, LocalVariable variable,
                                                                   Expression current, Statement statement,
                                                                   Location loc)
                                {
                                        this.type = type;
-                                       this.variable = variable;
+                                       this.variable = new LocalVariableReference (variable, loc);
                                        this.current = current;
                                        this.statement = statement;
                                        this.loc = loc;
@@ -5104,9 +5364,8 @@ namespace Mono.CSharp {
                                        if (conv == null)
                                                return false;
 
-                                       assign = new SimpleAssign (variable, conv, loc);
-                                       if (assign.Resolve (ec) == null)
-                                               return false;
+                                       variable.local_info.Type = conv.Type;
+                                       variable.Resolve (ec);
 
                                        if (!statement.Resolve (ec))
                                                return false;
@@ -5116,28 +5375,62 @@ namespace Mono.CSharp {
 
                                protected override void DoEmit (EmitContext ec)
                                {
-                                       assign.EmitStatement (ec);
+                                       variable.local_info.CreateBuilder (ec);
+                                       variable.EmitAssign (ec, conv, false, false);
+
                                        statement.Emit (ec);
                                }
                        }
 
-                       Expression variable, expr;
-                       Statement statement;
+                       class RuntimeDispose : Using.VariableDeclaration
+                       {
+                               public RuntimeDispose (LocalVariable lv, Location loc)
+                                       : base (lv, loc)
+                               {
+                               }
+
+                               protected override void CheckIDiposableConversion (BlockContext bc, LocalVariable li, Expression initializer)
+                               {
+                                       // Defered to runtime check
+                               }
+
+                               protected override Statement CreateDisposeCall (BlockContext bc, LocalVariable lv)
+                               {
+                                       if (TypeManager.void_dispose_void == null) {
+                                               TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
+                                                       TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes);
+                                       }
+
+                                       //
+                                       // Fabricates code like
+                                       //
+                                       // if ((temp = vr as IDisposable) != null) temp.Dispose ();
+                                       //
+
+                                       var dispose_variable = LocalVariable.CreateCompilerGenerated (TypeManager.idisposable_type, bc.CurrentBlock, loc);
+
+                                       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);
 
-                       TemporaryVariable enumerator;
-                       Expression init;
-                       Statement loop;
-                       Statement wrapper;
+                                       var dispose_mg = MethodGroupExpr.CreatePredefined (TypeManager.void_dispose_void, TypeManager.idisposable_type, loc);
+                                       dispose_mg.InstanceExpression = dispose_variable.CreateReferenceExpression (bc, loc);
 
-                       MethodGroupExpr get_enumerator;
-                       PropertyExpr get_current;
-                       MethodSpec move_next;
+                                       Statement dispose = new StatementExpression (new Invocation (dispose_mg, null));
+                                       return new If (idisaposable_test, dispose, loc);
+                               }
+                       }
+
+                       LocalVariable variable;
+                       Expression expr;
+                       Statement statement;
                        Expression var_type;
-                       TypeSpec enumerator_type;
-                       bool enumerator_found;
+                       ExpressionStatement init;
+                       TemporaryVariableReference enumerator_variable;
+                       bool ambiguous_getenumerator_name;
 
-                       public CollectionForeach (Expression var_type, Expression var,
-                                                 Expression expr, Statement stmt, Location l)
+                       public CollectionForeach (Expression var_type, LocalVariable var, Expression expr, Statement stmt, Location l)
                        {
                                this.var_type = var_type;
                                this.variable = var;
@@ -5151,414 +5444,262 @@ namespace Mono.CSharp {
                                throw new NotImplementedException ();
                        }
 
-                       bool GetEnumeratorFilter (ResolveContext ec, MethodSpec mi)
+                       void Error_WrongEnumerator (ResolveContext rc, MethodSpec enumerator)
                        {
-                               TypeSpec return_type = mi.ReturnType;
+                               rc.Report.SymbolRelatedToPreviousError (enumerator);
+                               rc.Report.Error (202, loc,
+                                       "foreach statement requires that the return type `{0}' of `{1}' must have a suitable public MoveNext method and public Current property",
+                                               enumerator.ReturnType.GetSignatureForError (), enumerator.GetSignatureForError ());
+                       }
 
+                       MethodGroupExpr ResolveGetEnumerator (ResolveContext rc)
+                       {
                                //
-                               // Ok, we can access it, now make sure that we can do something
-                               // with this `GetEnumerator'
+                               // Option 1: Try to match by name GetEnumerator first
                                //
+                               var mexpr = Expression.MemberLookup (rc, rc.CurrentType, expr.Type,
+                                       "GetEnumerator", 0, Expression.MemberLookupRestrictions.ExactArity, loc);               // TODO: What if CS0229 ?
 
-                               if (return_type == TypeManager.ienumerator_type ||
-                                       return_type.ImplementsInterface (TypeManager.ienumerator_type)) {
-                                       //
-                                       // If it is not an interface, lets try to find the methods ourselves.
-                                       // For example, if we have:
-                                       // public class Foo : IEnumerator { public bool MoveNext () {} public int Current { get {}}}
-                                       // We can avoid the iface call. This is a runtime perf boost.
-                                       // even bigger if we have a ValueType, because we avoid the cost
-                                       // of boxing.
-                                       //
-                                       // We have to make sure that both methods exist for us to take
-                                       // this path. If one of the methods does not exist, we will just
-                                       // use the interface. Sadly, this complex if statement is the only
-                                       // way I could do this without a goto
-                                       //
+                               var mg = mexpr as MethodGroupExpr;
+                               if (mg != null) {
+                                       mg.InstanceExpression = expr;
+                                       Arguments args = new Arguments (0);
+                                       mg = mg.OverloadResolve (rc, ref args, this, OverloadResolver.Restrictions.None);
 
-                                       if (TypeManager.bool_movenext_void == null) {
-                                               TypeManager.bool_movenext_void = TypeManager.GetPredefinedMethod (
-                                                       TypeManager.ienumerator_type, "MoveNext", loc, TypeSpec.EmptyTypes);
-                                       }
+                                       // For ambiguous GetEnumerator name warning CS0278 was reported, but Option 2 could still apply
+                                       if (ambiguous_getenumerator_name)
+                                               mg = null;
 
-                                       if (TypeManager.ienumerator_getcurrent == null) {
-                                               TypeManager.ienumerator_getcurrent = TypeManager.GetPredefinedProperty (
-                                                       TypeManager.ienumerator_type, "Current", loc, TypeManager.object_type);
+                                       if (mg != null && args.Count == 0 && !mg.BestCandidate.IsStatic && mg.BestCandidate.IsPublic) {
+                                               return mg;
                                        }
+                               }
 
-                                       //
-                                       // Prefer a generic enumerator over a non-generic one.
-                                       //
-                                       if (return_type.IsInterface && TypeManager.IsGenericType (return_type)) {
-                                               enumerator_type = return_type;
-                                               if (!FetchGetCurrent (ec, return_type))
-                                                       get_current = new PropertyExpr (
-                                                               ec.CurrentType, TypeManager.ienumerator_getcurrent, loc);
-                                               if (!FetchMoveNext (return_type))
-                                                       move_next = TypeManager.bool_movenext_void;
-                                               return true;
-                                       }
+                               //
+                               // Option 2: Try to match using IEnumerable interfaces with preference of generic version
+                               //
+                               TypeSpec iface_candidate = null;
+                               var t = expr.Type;
+                               do {
+                                       var ifaces = t.Interfaces;
+                                       if (ifaces != null) {
+                                               foreach (var iface in ifaces) {
+                                                       if (TypeManager.generic_ienumerable_type != null && iface.MemberDefinition == TypeManager.generic_ienumerable_type.MemberDefinition) {
+                                                               if (iface_candidate != null && iface_candidate != TypeManager.ienumerable_type) {
+                                                                       rc.Report.SymbolRelatedToPreviousError (expr.Type);
+                                                                       rc.Report.Error (1640, loc,
+                                                                               "foreach statement cannot operate on variables of type `{0}' because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
+                                                                               expr.Type.GetSignatureForError (), TypeManager.generic_ienumerable_type.GetSignatureForError ());
+
+                                                                       return null;
+                                                               }
+
+                                                               iface_candidate = iface;
+                                                               continue;
+                                                       }
 
-                                       if (return_type.IsInterface ||
-                                           !FetchMoveNext (return_type) ||
-                                           !FetchGetCurrent (ec, return_type)) {
-                                               enumerator_type = return_type;
-                                               move_next = TypeManager.bool_movenext_void;
-                                               get_current = new PropertyExpr (
-                                                       ec.CurrentType, TypeManager.ienumerator_getcurrent, loc);
-                                               return true;
+                                                       if (iface == TypeManager.ienumerable_type && iface_candidate == null) {
+                                                               iface_candidate = iface;
+                                                       }
+                                               }
                                        }
-                               } else {
-                                       //
-                                       // Ok, so they dont return an IEnumerable, we will have to
-                                       // find if they support the GetEnumerator pattern.
-                                       //
 
-                                       if (TypeManager.HasElementType (return_type) || !FetchMoveNext (return_type) || !FetchGetCurrent (ec, return_type)) {
-                                               ec.Report.Error (202, loc, "foreach statement requires that the return type `{0}' of `{1}' must have a suitable public MoveNext method and public Current property",
-                                                       TypeManager.CSharpName (return_type), TypeManager.CSharpSignature (mi));
-                                               return false;
-                                       }
+                                       if (t.IsGenericParameter)
+                                               t = t.BaseType;
+                                       else
+                                               t = null;
+
+                               } while (t != null);
+
+                               if (iface_candidate == null) {
+                                       rc.Report.Error (1579, loc,
+                                               "foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `{1}' or is inaccessible",
+                                               expr.Type.GetSignatureForError (), "GetEnumerator");
+
+                                       return null;
                                }
 
-                               enumerator_type = return_type;
+                               var method = TypeManager.GetPredefinedMethod (iface_candidate, 
+                                       MemberFilter.Method ("GetEnumerator", 0, ParametersCompiled.EmptyReadOnlyParameters, null), loc);
 
-                               return true;
+                               if (method == null)
+                                       return null;
+
+                               mg = MethodGroupExpr.CreatePredefined (method, expr.Type, loc);
+                               mg.InstanceExpression = expr;
+                               return mg;
                        }
 
-                       //
-                       // Retrieves a `public bool MoveNext ()' method from the Type `t'
-                       //
-                       bool FetchMoveNext (TypeSpec t)
+                       MethodGroupExpr ResolveMoveNext (ResolveContext rc, MethodSpec enumerator)
                        {
-                               move_next = MemberCache.FindMember (t,
+                               var ms = MemberCache.FindMember (enumerator.ReturnType,
                                        MemberFilter.Method ("MoveNext", 0, ParametersCompiled.EmptyReadOnlyParameters, TypeManager.bool_type),
                                        BindingRestriction.InstanceOnly) as MethodSpec;
 
-                               return move_next != null && (move_next.Modifiers & Modifiers.PUBLIC) != 0;
-                       }
-               
-                       //
-                       // Retrieves a `public T get_Current ()' method from the Type `t'
-                       //
-                       bool FetchGetCurrent (ResolveContext ec, TypeSpec t)
-                       {
-                               PropertyExpr pe = Expression.MemberLookup (ec.Compiler,
-                                       ec.CurrentType, t, "Current", 0, MemberKind.Property,
-                                       BindingRestriction.AccessibleOnly, loc) as PropertyExpr;
-                               if (pe == null)
-                                       return false;
+                               if (ms == null || !ms.IsPublic) {
+                                       Error_WrongEnumerator (rc, enumerator);
+                                       return null;
+                               }
 
-                               get_current = pe;
-                               return true;
+                               return MethodGroupExpr.CreatePredefined (ms, enumerator.ReturnType, loc);
                        }
 
-                       void Error_Enumerator (BlockContext ec)
+                       PropertySpec ResolveCurrent (ResolveContext rc, MethodSpec enumerator)
                        {
-                               if (enumerator_found) {
-                                       return;
+                               var ps = MemberCache.FindMember (enumerator.ReturnType,
+                                       MemberFilter.Property ("Current", null),
+                                       BindingRestriction.InstanceOnly) as PropertySpec;
+
+                               if (ps == null || !ps.IsPublic) {
+                                       Error_WrongEnumerator (rc, enumerator);
+                                       return null;
                                }
 
-                           ec.Report.Error (1579, loc,
-                                       "foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `GetEnumerator' or is not accessible",
-                                       TypeManager.CSharpName (expr.Type));
+                               return ps;
                        }
 
-                       bool TryType (ResolveContext ec, TypeSpec t)
+                       public override bool Resolve (BlockContext ec)
                        {
-                               var mg = Expression.MemberLookup (ec.Compiler, ec.CurrentType, null, t, "GetEnumerator", 0,
-                                       MemberKind.Method, BindingRestriction.NoOverrides | BindingRestriction.InstanceOnly, loc) as MethodGroupExpr;
-
-                               if (mg == null)
-                                       return false;
-
-                               MethodSpec result = null;
-                               MethodSpec tmp_move_next = null;
-                               PropertyExpr tmp_get_cur = null;
-                               TypeSpec tmp_enumerator_type = enumerator_type;
-                               foreach (MethodSpec mi in mg.Methods) {
-                                       if (!mi.Parameters.IsEmpty)
-                                               continue;
-                       
-                                       // Check whether GetEnumerator is public
-                                       if ((mi.Modifiers & Modifiers.AccessibilityMask) != Modifiers.PUBLIC)
-                                               continue;
-
-                                       enumerator_found = true;
-
-                                       if (!GetEnumeratorFilter (ec, mi))
-                                               continue;
-
-                                       if (result != null) {
-                                               if (TypeManager.IsGenericType (result.ReturnType)) {
-                                                       if (!TypeManager.IsGenericType (mi.ReturnType))
-                                                               continue;
-
-                                                       ec.Report.SymbolRelatedToPreviousError (t);
-                                                       ec.Report.Error(1640, loc, "foreach statement cannot operate on variables of type `{0}' " +
-                                                                        "because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
-                                                                        TypeManager.CSharpName (t), TypeManager.generic_ienumerable_type.GetSignatureForError ());
-                                                       return false;
-                                               }
-
-                                               // Always prefer generics enumerators
-                                               if (!TypeManager.IsGenericType (mi.ReturnType)) {
-                                                       if (mi.DeclaringType.ImplementsInterface (result.DeclaringType) ||
-                                                               result.DeclaringType.ImplementsInterface (mi.DeclaringType))
-                                                               continue;
+                               bool is_dynamic = expr.Type == InternalType.Dynamic;
 
-                                                       ec.Report.SymbolRelatedToPreviousError (result);
-                                                       ec.Report.SymbolRelatedToPreviousError (mi);
-                                                       ec.Report.Warning (278, 2, loc, "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
-                                                                       TypeManager.CSharpName (t), "enumerable", result.GetSignatureForError (), mi.GetSignatureForError ());
-                                                       return false;
-                                               }
-                                       }
-                                       result = mi;
-                                       tmp_move_next = move_next;
-                                       tmp_get_cur = get_current;
-                                       tmp_enumerator_type = enumerator_type;
-                                       if (mi.DeclaringType == t)
-                                               break;
+                               if (is_dynamic) {
+                                       expr = Convert.ImplicitConversionRequired (ec, expr, TypeManager.ienumerable_type, loc);
+                               } else if (TypeManager.IsNullableType (expr.Type)) {
+                                       expr = new Nullable.UnwrapCall (expr).Resolve (ec);
                                }
 
-                               if (result != null) {
-                                       move_next = tmp_move_next;
-                                       get_current = tmp_get_cur;
-                                       enumerator_type = tmp_enumerator_type;
-                                       get_enumerator = new MethodGroupExpr (result, enumerator_type, loc);
-
-                                       if (t != expr.Type) {
-                                               expr = Convert.ExplicitConversion (
-                                                       ec, expr, t, loc);
-                                               if (expr == null)
-                                                       throw new InternalErrorException ();
-                                       }
-
-                                       get_enumerator.InstanceExpression = expr;
-                                       get_enumerator.IsBase = t != expr.Type;
-
-                                       return true;
+                               var get_enumerator_mg = ResolveGetEnumerator (ec);
+                               if (get_enumerator_mg == null) {
+                                       return false;
                                }
 
-                               return false;
-                       }
-
-                       bool ProbeCollectionType (ResolveContext ec, TypeSpec t)
-                       {
-                               int errors = ec.Report.Errors;
-                               for (TypeSpec tt = t; tt != null && tt != TypeManager.object_type;){
-                                       if (TryType (ec, tt))
-                                               return true;
-                                       tt = tt.BaseType;
-                               }
+                               var get_enumerator = get_enumerator_mg.BestCandidate;
+                               enumerator_variable = TemporaryVariableReference.Create (get_enumerator.ReturnType, variable.Block, loc);
+                               enumerator_variable.Resolve (ec);
 
-                               if (ec.Report.Errors > errors)
+                               // Prepare bool MoveNext ()
+                               var move_next_mg = ResolveMoveNext (ec, get_enumerator);
+                               if (move_next_mg == null) {
                                        return false;
-
-                               //
-                               // Now try to find the method in the interfaces
-                               //
-                               for (TypeSpec tt = t; tt != null && tt != TypeManager.object_type; ) {
-                                       if (tt.Interfaces != null) {
-                                               foreach (TypeSpec i in tt.Interfaces) {
-                                                       if (TryType (ec, i))
-                                                               return true;
-                                               }
-                                       }
-                                       tt = tt.BaseType;
                                }
 
-                               return false;
-                       }
-
-                       public override bool Resolve (BlockContext ec)
-                       {
-                               enumerator_type = TypeManager.ienumerator_type;
+                               move_next_mg.InstanceExpression = enumerator_variable;
 
-                               bool is_dynamic = expr.Type == InternalType.Dynamic;
-                               if (is_dynamic)
-                                       expr = Convert.ImplicitConversionRequired (ec, expr, TypeManager.ienumerable_type, loc);
-                               
-                               if (!ProbeCollectionType (ec, expr.Type)) {
-                                       Error_Enumerator (ec);
+                               // Prepare ~T~ Current { get; }
+                               var current_prop = ResolveCurrent (ec, get_enumerator);
+                               if (current_prop == null) {
                                        return false;
                                }
 
+                               var current_pe = new PropertyExpr (current_prop, loc) { InstanceExpression = enumerator_variable }.Resolve (ec);
+                               if (current_pe == null)
+                                       return false;
+
                                VarExpr ve = var_type as VarExpr;
                                if (ve != null) {
-                                       // Infer implicitly typed local variable from foreach enumerable type
-                                       var_type = new TypeExpression (
-                                               is_dynamic ? InternalType.Dynamic : get_current.Type,
-                                               var_type.Location);
+                                       if (is_dynamic) {
+                                               // Source type is dynamic, set element type to dynamic too
+                                               var_type = new TypeExpression (InternalType.Dynamic, var_type.Location);
+                                       } else {
+                                               // Infer implicitly typed local variable from foreach enumerable type
+                                               var_type = new TypeExpression (current_pe.Type, var_type.Location);
+                                       }
+                               } else if (is_dynamic) {
+                                       // Explicit cast of dynamic collection elements has to be done at runtime
+                                       current_pe = EmptyCast.Create (current_pe, InternalType.Dynamic);
                                }
 
                                var_type = var_type.ResolveAsTypeTerminal (ec, false);
                                if (var_type == null)
                                        return false;
-                                                               
-                               enumerator = new TemporaryVariable (enumerator_type, loc);
-                               enumerator.Resolve (ec);
-
-                               init = new Invocation (get_enumerator, null);
-                               init = init.Resolve (ec);
-                               if (init == null)
-                                       return false;
 
-                               Expression move_next_expr;
-                               {
-                                       var mi = new List<MemberSpec> (1) { move_next };
-                                       MethodGroupExpr mg = new MethodGroupExpr (mi, var_type.Type, loc);
-                                       mg.InstanceExpression = enumerator;
-
-                                       move_next_expr = new Invocation (mg, null);
-                               }
-
-                               get_current.InstanceExpression = enumerator;
+                               variable.Type = var_type.Type;
 
-                               Statement block = new CollectionForeachStatement (
-                                       var_type.Type, variable, get_current, statement, loc);
+                               var init = new Invocation (get_enumerator_mg, null);
 
-                               loop = new While (new BooleanExpression (move_next_expr), block, loc);
+                               statement = new While (new BooleanExpression (new Invocation (move_next_mg, null)),
+                                       new Body (var_type.Type, variable, current_pe, statement, loc), loc);
 
+                               var enum_type = enumerator_variable.Type;
 
-                               bool implements_idisposable = enumerator_type.ImplementsInterface (TypeManager.idisposable_type);
-                               if (implements_idisposable || !enumerator_type.IsSealed) {
-                                       wrapper = new DisposableWrapper (this, implements_idisposable);
+                               //
+                               // Add Dispose method call when enumerator can be IDisposable
+                               //
+                               if (!enum_type.ImplementsInterface (TypeManager.idisposable_type, false)) {
+                                       if (!enum_type.IsSealed && !TypeManager.IsValueType (enum_type)) {
+                                               //
+                                               // Runtime Dispose check
+                                               //
+                                               var vd = new RuntimeDispose (enumerator_variable.LocalInfo, loc);
+                                               vd.Initializer = init;
+                                               statement = new Using (vd, statement, loc);
+                                       } else {
+                                               //
+                                               // No Dispose call needed
+                                               //
+                                               this.init = new SimpleAssign (enumerator_variable, init);
+                                               this.init.Resolve (ec);
+                                       }
                                } else {
-                                       wrapper = new NonDisposableWrapper (this);
+                                       //
+                                       // Static Dispose check
+                                       //
+                                       var vd = new Using.VariableDeclaration (enumerator_variable.LocalInfo, loc);
+                                       vd.Initializer = init;
+                                       statement = new Using (vd, statement, loc);
                                }
 
-                               return wrapper.Resolve (ec);
+                               return statement.Resolve (ec);
                        }
 
                        protected override void DoEmit (EmitContext ec)
                        {
-                               wrapper.Emit (ec);
-                       }
-
-                       class NonDisposableWrapper : Statement {
-                               CollectionForeach parent;
+                               enumerator_variable.LocalInfo.CreateBuilder (ec);
 
-                               internal NonDisposableWrapper (CollectionForeach parent)
-                               {
-                                       this.parent = parent;
-                               }
-
-                               protected override void CloneTo (CloneContext clonectx, Statement target)
-                               {
-                                       throw new NotSupportedException ();
-                               }
-
-                               public override bool Resolve (BlockContext ec)
-                               {
-                                       return parent.ResolveLoop (ec);
-                               }
+                               if (init != null)
+                                       init.EmitStatement (ec);
 
-                               protected override void DoEmit (EmitContext ec)
-                               {
-                                       parent.EmitLoopInit (ec);
-                                       parent.EmitLoopBody (ec);
-                               }
+                               statement.Emit (ec);
                        }
 
-                       sealed class DisposableWrapper : ExceptionStatement
-                       {
-                               CollectionForeach parent;
-                               bool implements_idisposable;
-
-                               internal DisposableWrapper (CollectionForeach parent, bool implements)
-                               {
-                                       this.parent = parent;
-                                       this.implements_idisposable = implements;
-                               }
-
-                               protected override void CloneTo (CloneContext clonectx, Statement target)
-                               {
-                                       throw new NotSupportedException ();
-                               }
-
-                               public override bool Resolve (BlockContext ec)
-                               {
-                                       bool ok = true;
-
-                                       ec.StartFlowBranching (this);
-
-                                       if (!parent.ResolveLoop (ec))
-                                               ok = false;
-
-                                       ec.EndFlowBranching ();
-
-                                       ok &= base.Resolve (ec);
-
-                                       if (TypeManager.void_dispose_void == null) {
-                                               TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
-                                                       TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes);
-                                       }
-                                       return ok;
-                               }
-
-                               protected override void EmitPreTryBody (EmitContext ec)
-                               {
-                                       parent.EmitLoopInit (ec);
-                               }
-
-                               protected override void EmitTryBody (EmitContext ec)
-                               {
-                                       parent.EmitLoopBody (ec);
-                               }
-
-                               protected override void EmitFinallyBody (EmitContext ec)
-                               {
-                                       Expression instance = parent.enumerator;
-                                       if (!TypeManager.IsValueType (parent.enumerator_type)) {
-
-                                               parent.enumerator.Emit (ec);
-
-                                               Label call_dispose = ec.DefineLabel ();
-
-                                               if (!implements_idisposable) {
-                                                       ec.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
-                                                       LocalTemporary temp = new LocalTemporary (TypeManager.idisposable_type);
-                                                       temp.Store (ec);
-                                                       temp.Emit (ec);
-                                                       instance = temp;
-                                               }
-                                               
-                                               ec.Emit (OpCodes.Brtrue_S, call_dispose);
+                       #region IErrorHandler Members
 
-                                               // using 'endfinally' to empty the evaluation stack
-                                               ec.Emit (OpCodes.Endfinally);
-                                               ec.MarkLabel (call_dispose);
-                                       }
+                       bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext ec, MemberSpec best, MemberSpec ambiguous)
+                       {
+                               ec.Report.SymbolRelatedToPreviousError (best);
+                               ec.Report.Warning (278, 2, loc,
+                                       "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
+                                       expr.Type.GetSignatureForError (), "enumerable",
+                                       best.GetSignatureForError (), ambiguous.GetSignatureForError ());
 
-                                       Invocation.EmitCall (ec, false, instance, TypeManager.void_dispose_void, null, loc);
-                               }
+                               ambiguous_getenumerator_name = true;
+                               return true;
                        }
 
-                       bool ResolveLoop (BlockContext ec)
+                       bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
                        {
-                               return loop.Resolve (ec);
+                               return false;
                        }
 
-                       void EmitLoopInit (EmitContext ec)
+                       bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
                        {
-                               enumerator.EmitAssign (ec, init);
+                               return false;
                        }
 
-                       void EmitLoopBody (EmitContext ec)
+                       bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
                        {
-                               loop.Emit (ec);
+                               return false;
                        }
+
+                       #endregion
                }
 
                Expression type;
-               Expression variable;
+               LocalVariable variable;
                Expression expr;
                Statement statement;
 
-               public Foreach (Expression type, LocalVariableReference var, Expression expr,
-                               Statement stmt, Location l)
+               public Foreach (Expression type, LocalVariable var, Expression expr, Statement stmt, Location l)
                {
                        this.type = type;
                        this.variable = var;
@@ -5616,7 +5757,6 @@ namespace Mono.CSharp {
                        Foreach target = (Foreach) t;
 
                        target.type = type.Clone (clonectx);
-                       target.variable = variable.Clone (clonectx);
                        target.expr = expr.Clone (clonectx);
                        target.statement = statement.Clone (clonectx);
                }