[csharp] repl using statement fix + support for --fatal
[mono.git] / mcs / mcs / statement.cs
index 3710cf7977ad1ac14c6d9412c78b9915b2b56f97..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 {
@@ -730,33 +732,43 @@ namespace Mono.CSharp {
                        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);
 
@@ -788,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;
@@ -844,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;
                }
 
@@ -863,6 +883,12 @@ namespace Mono.CSharp {
                        return label;
                }
 
+               public Block Block {
+                       get {
+                               return block;
+                       }
+               }
+
                public string Name {
                        get { return name; }
                }
@@ -900,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);
                }
@@ -1130,720 +1159,756 @@ 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 (VariableType.IsPointer && !ec.IsUnsafe)
-                               Expression.UnsafeError (ec, Location);
+                               if (type == null) {
+                                       var texpr = type_expr.ResolveAsTypeTerminal (bc, false);
+                                       if (texpr == null)
+                                               return false;
 
-                       return true;
-               }
+                                       type = texpr.Type;
 
-               public bool IsConstant {
-                       get { return (flags & Flags.IsConstant) != 0; }
-                       set { flags |= Flags.IsConstant; }
-               }
+                                       if (li.IsConstant && !type.IsConstantCompatible) {
+                                               Const.Error_InvalidConstantType (type, loc, bc.Report);
+                                       }
+                               }
 
-               public bool AddressTaken {
-                       get { return (flags & Flags.AddressTaken) != 0; }
-                       set { flags |= Flags.AddressTaken; }
-               }
+                               if (type.IsStatic)
+                                       FieldBase.Error_VariableOfStaticClass (loc, li.Name, type, bc.Report);
 
-               public bool CompilerGenerated {
-                       get { return (flags & Flags.CompilerGenerated) != 0; }
-                       set { flags |= Flags.CompilerGenerated; }
-               }
+                               if (type.IsPointer && !bc.IsUnsafe)
+                                       Expression.UnsafeError (bc, loc);
 
-               public override string ToString ()
-               {
-                       return String.Format ("LocalInfo ({0},{1},{2},{3})",
-                                             Name, Type, VariableInfo, Location);
-               }
+                               li.Type = type;
+                       }
 
-               public bool Used {
-                       get { return (flags & Flags.Used) != 0; }
-                       set { flags = value ? (flags | Flags.Used) : (unchecked (flags & ~Flags.Used)); }
-               }
+                       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 (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 
+                                       }
+                               }
+                       }
 
-               public bool ReadOnly {
-                       get { return (flags & Flags.ReadOnly) != 0; }
+                       return true;
                }
 
-               public void SetReadOnlyContext (ReadOnlyContext context)
+               protected virtual Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
                {
-                       flags |= Flags.ReadOnly;
-                       ro_context = context;
+                       var a = new SimpleAssign (li.CreateReferenceExpression (bc, li.Location), initializer, li.Location);
+                       return a.ResolveStatement (bc);
                }
 
-               public string GetReadOnlyContext ()
+               protected override void DoEmit (EmitContext ec)
                {
-                       if (!ReadOnly)
-                               throw new InternalErrorException ("Variable is not readonly");
+                       if (li.IsConstant)
+                               return;
 
-                       switch (ro_context) {
-                       case ReadOnlyContext.Fixed:
-                               return "fixed variable";
-                       case ReadOnlyContext.Foreach:
-                               return "foreach iteration variable";
-                       case ReadOnlyContext.Using:
-                               return "using variable";
+                       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);
+                               }
                        }
-                       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); }
-               }
+               protected override void CloneTo (CloneContext clonectx, Statement target)
+               {
+                       BlockVariableDeclaration t = (BlockVariableDeclaration) target;
 
-               public bool IsThis {
-                       get { return (flags & Flags.IsThis) != 0; }
-                       set { flags = value ? (flags | Flags.IsThis) : (flags & ~Flags.IsThis); }
-               }
+                       if (type_expr != null)
+                               t.type_expr = (FullNamedExpression) type_expr.Clone (clonectx);
 
-               Block IKnownVariable.Block {
-                       get { return Block; }
+                       if (initializer != null)
+                               t.initializer = initializer.Clone (clonectx);
+
+                       if (declarators != null) {
+                               t.declarators = null;
+                               foreach (var d in declarators)
+                                       t.AddDeclarator (new Declarator (d, d.Initializer == null ? null : d.Initializer.Clone (clonectx)));
+                       }
                }
+       }
 
-               Location IKnownVariable.Location {
-                       get { return Location; }
+       class BlockConstantDeclaration : BlockVariableDeclaration
+       {
+               public BlockConstantDeclaration (FullNamedExpression type, LocalVariable li)
+                       : base (type, li)
+               {
                }
 
-               public LocalInfo Clone (CloneContext clonectx)
+               protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
                {
-                       //
-                       // Variables in anonymous block are not resolved yet
-                       //
-                       if (VariableType == null)
-                               return new LocalInfo ((FullNamedExpression) Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location);
+                       initializer = initializer.Resolve (bc);
+                       if (initializer == null)
+                               return null;
 
-                       //
-                       // Variables in method block are resolved
-                       //
-                       LocalInfo li = new LocalInfo (null, Name, clonectx.LookupBlock (Block), Location);
-                       li.VariableType = VariableType;
-                       return li;                      
-               }
-       }
+                       var c = initializer as Constant;
+                       if (c == null) {
+                               initializer.Error_ExpressionMustBeConstant (bc, initializer.Location, li.Name);
+                               return null;
+                       }
 
-       /// <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;
+                       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);
 
-               public ExplicitBlock Explicit;
-               public ToplevelBlock Toplevel; // TODO: Use Explicit
+                               return null;
+                       }
+
+                       li.ConstantValue = c;
+                       return initializer;
+               }
+       }
 
+       //
+       // The information about a user-perceived local variable
+       //
+       public class LocalVariable : INamedBlockVariable, ILocalVariable
+       {
                [Flags]
                public enum Flags
                {
-                       Unchecked = 1,
-                       BlockUsed = 2,
-                       VariablesInitialized = 4,
-                       HasRet = 8,
-                       Unsafe = 16,
-                       IsIterator = 32,
-                       HasCapturedVariable = 64,
-                       HasCapturedThis = 1 << 7,
-                       IsExpressionTree = 1 << 8
+                       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
                }
 
-               protected Flags flags;
+               TypeSpec type;
+               readonly string name;
+               readonly Location loc;
+               readonly Block block;
+               Flags flags;
+               Constant const_value;
 
-               public bool Unchecked {
-                       get { return (flags & Flags.Unchecked) != 0; }
-                       set { flags = value ? flags | Flags.Unchecked : flags & ~Flags.Unchecked; }
+               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;
                }
 
-               public bool Unsafe {
-                       get { return (flags & Flags.Unsafe) != 0; }
-                       set { flags |= Flags.Unsafe; }
+               public LocalVariable (Block block, string name, Flags flags, Location loc)
+                       : this (block, name, loc)
+               {
+                       this.flags = flags;
                }
 
                //
-               // The statements in this block
+               // Used by variable declarators
                //
-               protected List<Statement> statements;
+               public LocalVariable (LocalVariable li, string name, Location loc)
+                       : this (li.block, name, li.flags, loc)
+               {
+               }
 
-               //
-               // 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;
+               #region Properties
 
-               //
-               // Labels.  (label, block) pairs.
-               //
-               protected Dictionary<string, LabeledStatement> labels;
+               public bool AddressTaken {
+                       get { return (flags & Flags.AddressTaken) != 0; }
+                       set { flags |= Flags.AddressTaken; }
+               }
 
-               //
-               // 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;
-
-               int? resolving_init_idx;
-
-               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 {
+                       get {
+                               return block;
+                       }
+               }
 
-               public Block (Block parent, Location start, Location end)
-                       : this (parent, (Flags) 0, start, end)
-               { }
+               public Constant ConstantValue {
+                       get {
+                               return const_value;
+                       }
+                       set {
+                               const_value = value;
+                       }
+               }
 
                //
-               // 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);
                }
 
-               #region Properties
-
-               public int ID {
-                       get { return this_id; }
+               public bool IsConstant {
+                       get {
+                               return (flags & Flags.Constant) != 0;
+                       }
                }
 
-               public IDictionary<string, LocalInfo> Variables {
+               public bool IsLocked {
                        get {
-                               if (variables == null)
-                                       variables = new Dictionary<string, LocalInfo> ();
-                               return variables;
+                               return (flags & Flags.IsLocked) != 0;
+                       }
+                       set {
+                               flags = value ? flags | Flags.IsLocked : flags & ~Flags.IsLocked;
                        }
                }
 
-               #endregion
-
-               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 IsThis {
+                       get {
+                               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;
+                       throw new InternalErrorException ("Variable is not readonly");
+               }
 
-                       // 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;
-                               }
+               public bool IsThisAssigned (BlockContext ec, Block block)
+               {
+                       if (VariableInfo == null)
+                               throw new Exception ();
 
-                               //
-                               // 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.
-                               //
+                       if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo))
                                return true;
-                       }
 
-                       //
-                       // 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))
-                               return true;
+                       return VariableInfo.TypeInfo.IsFullyInitialized (ec, VariableInfo, block.StartLocation);
+               }
 
-                       if (this is ToplevelBlock) {
-                               Toplevel.Report.SymbolRelatedToPreviousError (kvi.Location, name);
-                               e.Error_VariableIsUsedBeforeItIsDeclared (Toplevel.Report, name);
-                               return false;
-                       }
+               public bool IsAssigned (BlockContext ec)
+               {
+                       if (VariableInfo == null)
+                               throw new Exception ();
 
-                       //
-                       // 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 !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo);
                }
 
-               protected bool CheckParentConflictName (ToplevelBlock block, string name, Location l)
+               public void PrepareForFlowAnalysis (BlockContext bc)
                {
-                       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;
-                       }
+                       //
+                       // No need for definitely assigned check for these guys
+                       //
+                       if ((flags & (Flags.Constant | Flags.ReadonlyMask | Flags.CompilerGenerated)) != 0)
+                               return;
 
-                       if (block != null) {
-                               var tblock = block.CheckParameterNameConflict (name);
-                               if (tblock != null) {
-                                       if (block == tblock && block is Linq.QueryBlock)
-                                               Error_AlreadyDeclared (loc, name);
-                                       else
-                                               Error_AlreadyDeclared (loc, name, "parent or current");
+                       VariableInfo = new VariableInfo (this, bc.FlowOffset);
+                       bc.FlowOffset += VariableInfo.Length;
+               }
 
-                                       return false;
-                               }
-                       }
+               //
+               // Mark the variables as referenced in the user code
+               //
+               public void SetIsUsed ()
+               {
+                       flags |= Flags.Used;
+               }
 
-                       return true;
+               public override string ToString ()
+               {
+                       return string.Format ("LocalInfo ({0},{1},{2},{3})", name, type, VariableInfo, Location);
                }
+       }
 
-               public LocalInfo AddVariable (Expression type, string name, Location l)
+       /// <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
                {
-                       if (!CheckParentConflictName (Toplevel, name, l))
-                               return null;
+                       Unchecked = 1,
+                       HasRet = 8,
+                       Unsafe = 16,
+                       IsIterator = 32,
+                       HasCapturedVariable = 64,
+                       HasCapturedThis = 1 << 7,
+                       IsExpressionTree = 1 << 8,
+                       CompilerGenerated = 1 << 9
+               }
 
-                       IKnownVariable kvi = Explicit.GetKnownVariable (name);
-                       if (kvi != null) {
-                               Toplevel.Report.SymbolRelatedToPreviousError (kvi.Location, name);
-                               Error_AlreadyDeclared (l, name, "child");
-                               return null;
-                       }
+               public Block Parent;
+               public Location StartLocation;
+               public Location EndLocation;
 
-                       LocalInfo vi = new LocalInfo ((FullNamedExpression) type, name, this, l);
-                       AddVariable (vi);
+               public ExplicitBlock Explicit;
+               public ParametersBlock ParametersBlock;
 
-                       if ((flags & Flags.VariablesInitialized) != 0)
-                               throw new InternalErrorException ("block has already been resolved");
+               protected Flags flags;
 
-                       return vi;
-               }
+               //
+               // The statements in this block
+               //
+               protected List<Statement> statements;
+
+               protected List<Statement> scope_initializers;
+
+               int? resolving_init_idx;
+
+               Block original;
+
+#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;
                
-               protected virtual void AddVariable (LocalInfo li)
+               public Block (Block parent, Location start, Location end)
+                       : this (parent, 0, start, end)
                {
-                       Variables.Add (li.Name, li);
-                       Explicit.AddKnownVariable (li.Name, li);
                }
 
-               protected virtual void Error_AlreadyDeclared (Location loc, string var, string reason)
+               public Block (Block parent, Flags flags, Location start, Location end)
                {
-                       if (reason == null) {
-                               Error_AlreadyDeclared (loc, var);
-                               return;
+                       if (parent != null) {
+                               // the appropriate constructors will fixup these fields
+                               ParametersBlock = parent.ParametersBlock;
+                               Explicit = parent.Explicit;
                        }
                        
-                       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);
+                       this.Parent = parent;
+                       this.flags = flags;
+                       this.StartLocation = start;
+                       this.EndLocation = end;
+                       this.loc = start;
+                       statements = new List<Statement> (4);
+
+                       this.original = this;
                }
 
-               protected virtual void Error_AlreadyDeclared (Location loc, string name)
-               {
-                       Toplevel.Report.Error (128, loc,
-                               "A local variable named `{0}' is already defined in this scope", name);
+               #region Properties
+
+               public bool HasRet {
+                       get { return (flags & Flags.HasRet) != 0; }
                }
-                                       
-               public virtual void Error_AlreadyDeclaredTypeParameter (Location loc, string name, string conflict)
-               {
-                       Toplevel.Report.Error (412, loc, "The type parameter name `{0}' is the same as `{1}'",
-                               name, conflict);
+
+               public Block Original {
+                       get {
+                               return original;
+                       }
                }
 
-               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 bool IsCompilerGenerated {
+                       get { return (flags & Flags.CompilerGenerated) != 0; }
+                       set { flags = value ? flags | Flags.CompilerGenerated : flags & ~Flags.CompilerGenerated; }
+               }
 
-                       constants.Add (name, value);
+               public bool Unchecked {
+                       get { return (flags & Flags.Unchecked) != 0; }
+                       set { flags = value ? flags | Flags.Unchecked : flags & ~Flags.Unchecked; }
+               }
 
-                       // A block is considered used if we perform an initialization in a local declaration, even if it is constant.
-                       Use ();
-                       return true;
+               public bool Unsafe {
+                       get { return (flags & Flags.Unsafe) != 0; }
+                       set { flags |= Flags.Unsafe; }
                }
 
-               static int next_temp_id = 0;
+               #endregion
 
-               public LocalInfo AddTemporaryVariable (TypeExpr te, Location loc)
+               public Block CreateSwitchBlock (Location start)
                {
-                       Report.Debug (64, "ADD TEMPORARY", this, Toplevel, loc);
-
-                       if (temporary_variables == null)
-                               temporary_variables = new List<LocalInfo> ();
+                       // FIXME: Only explicit block should be created
+                       var new_block = new Block (this, start, start);
+                       new_block.IsCompilerGenerated = true;
+                       return new_block;
+               }
 
-                       int id = ++next_temp_id;
-                       string name = "$s_" + id.ToString ();
+               public void SetEndLocation (Location loc)
+               {
+                       EndLocation = loc;
+               }
 
-                       LocalInfo li = new LocalInfo (te, name, this, loc);
-                       li.CompilerGenerated = true;
-                       temporary_variables.Add (li);
-                       return li;
+               public void AddLabel (LabeledStatement target)
+               {
+                       ParametersBlock.TopBlock.AddLabel (target.Name, target);
                }
 
-               public LocalInfo GetLocalInfo (string name)
+               public void AddLocalName (LocalVariable li)
                {
-                       LocalInfo ret;
-                       for (Block b = this; b != null; b = b.Parent) {
-                               if (b.variables != null && b.variables.TryGetValue (name, out ret)) {
-                                       return ret;
-                               }
-                       }
+                       AddLocalName (li.Name, li);
+               }
 
-                       return null;
+               public virtual void AddLocalName (string name, INamedBlockVariable li)
+               {
+                       ParametersBlock.TopBlock.AddLocalName (name, li);
                }
 
-               public Expression GetVariableType (string name)
+               public virtual void Error_AlreadyDeclared (string name, INamedBlockVariable variable, string reason)
                {
-                       LocalInfo vi = GetLocalInfo (name);
-                       return vi == null ? null : vi.Type;
+                       if (reason == null) {
+                               Error_AlreadyDeclared (name, variable);
+                               return;
+                       }
+
+                       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);
                }
 
-               public Expression GetConstantExpression (string name)
+               public virtual void Error_AlreadyDeclared (string name, INamedBlockVariable variable)
                {
-                       Expression ret;
-                       for (Block b = this; b != null; b = b.Parent) {
-                               if (b.constants != null) {
-                                       if (b.constants.TryGetValue (name, out ret))
-                                               return ret;
+                       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);
                                }
+
+                               return;
                        }
-                       return null;
+
+                       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);
                }
 
                //
@@ -1872,206 +1937,19 @@ namespace Mono.CSharp {
                public void AddStatement (Statement s)
                {
                        statements.Add (s);
-                       flags |= Flags.BlockUsed;
-               }
-
-               public bool Used {
-                       get { return (flags & Flags.BlockUsed) != 0; }
-               }
-
-               public void Use ()
-               {
-                       flags |= Flags.BlockUsed;
-               }
-
-               public bool HasRet {
-                       get { return (flags & Flags.HasRet) != 0; }
                }
 
                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 IList<ToplevelBlock> AnonymousChildren {
-                       get { return anonymous_children; }
-               }
-
-               public void AddAnonymousChild (ToplevelBlock b)
-               {
-                       if (anonymous_children == null)
-                               anonymous_children = new List<ToplevelBlock> ();
-
-                       anonymous_children.Add (b);
-               }
-
-               void DoResolveConstants (BlockContext ec)
-               {
-                       if (constants == null)
-                               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)) {\r
-                                       using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {\r
-                                               e = cv.Resolve (ec);\r
-                                       }
-                               }
-                               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;
-                       }
-               }
-
-               protected void ResolveMeta (BlockContext ec, int offset)
-               {
-                       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;
-                                       }
-                               }
-                               assignable_slots = offset;
-
-                               DoResolveConstants (ec);
-
-                               if (children == null)
-                                       return;
-                               foreach (Block b in children)
-                                       b.ResolveMeta (ec, offset);
+                               // FIXME: HACK, we don't know the block available variables count now, so set this high enough
+                               return 4096;
+//                             return assignable_slots;
                        }
                }
 
-               //
-               // Emits the local variable declarations for a block
-               //
-               public virtual void EmitMeta (EmitContext ec)
-               {
-                       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 (children != null) {
-                               for (int i = 0; i < children.Count; i++)
-                                       ((Block)children[i]).EmitMeta(ec);
-                       }
-               }
-
-               void UsageWarning (BlockContext ec)
+               public LabeledStatement LookupLabel (string name)
                {
-                       if (variables == null || ec.Report.WarningLevel < 3)
-                               return;
-
-                       foreach (var de in variables) {
-                               LocalInfo vi = de.Value;
-
-                               if (!vi.Used) {
-                                       string name = de.Key;
-
-                                       // 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);
-                               }
-                       }
-               }
-
-               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");
+                       return ParametersBlock.TopBlock.GetLabel (name, this);
                }
 
                public override bool Resolve (BlockContext ec)
@@ -2079,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);
 
@@ -2106,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.
@@ -2168,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;
                }
 
@@ -2231,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 (), this_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)
@@ -2297,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;
@@ -2350,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)
@@ -2363,141 +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);
                }
 
-               public IKnownVariable GetKnownVariable (string name)
+               public void WrapIntoDestructor (TryFinally tf, ExplicitBlock tryBlock)
                {
-                       if (known_variables == null)
-                               return null;
-
-                       IKnownVariable kw;
-                       known_variables.TryGetValue (name, out kw);
-                       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 Block Block {
+                               get {
+                                       return block;
+                               }
+                       }
+
+                       public bool IsDeclared {
+                               get {
+                                       return true;
+                               }
+                       }
+
+                       public bool IsLocked {
+                               get {
+                                       return is_locked;
+                               }
+                               set {
+                                       is_locked = value;
+                               }
+                       }
 
-       public class ToplevelParameterInfo : IKnownVariable {
-               public readonly ToplevelBlock Block;
-               public readonly int Index;
-               public VariableInfo VariableInfo;
+                       public Location Location {
+                               get {
+                                       return Parameter.Location;
+                               }
+                       }
 
-               Block IKnownVariable.Block {
-                       get { return Block; }
-               }
-               public Parameter Parameter {
-                       get { return Block.Parameters [Index]; }
-               }
+                       public Parameter Parameter {
+                               get {
+                                       return block.Parameters [index];
+                               }
+                       }
 
-               public TypeSpec ParameterType {
-                       get { return Block.Parameters.Types [Index]; }
-               }
+                       public TypeSpec ParameterType {
+                               get {
+                                       return Parameter.Type;
+                               }
+                       }
 
-               public Location Location {
-                       get { return Parameter.Location; }
-               }
+                       #endregion
 
-               public ToplevelParameterInfo (ToplevelBlock block, int idx)
-               {
-                       this.Block = block;
-                       this.Index = idx;
+                       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;
@@ -2512,7 +2366,7 @@ namespace Mono.CSharp {
                        {
                                if (child == null)
                                        return null;
-                               
+
                                child = child.Resolve (ec);
                                if (child == null)
                                        return null;
@@ -2524,24 +2378,62 @@ namespace Mono.CSharp {
 
                        public override void Emit (EmitContext ec)
                        {
-                               block.EmitMeta (ec);
                                block.EmitScopeInitializers (ec);
                                child.Emit (ec);
                        }
                }
 
                protected ParametersCompiled parameters;
-               protected 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;
                        }
                }
 
@@ -2549,194 +2441,455 @@ namespace Mono.CSharp {
                // The parameters for the block.
                //
                public ParametersCompiled Parameters {
-                       get { return parameters; }
+                       get {
+                               return parameters;
+                       }
                }
 
-               public Report Report {
-                       get { return compiler.Report; }
+               public ToplevelBlock TopBlock {
+                       get {
+                               return top_block;
+                       }
                }
 
-               public ToplevelBlock Container {
-                       get { return Parent == null ? null : Parent.Toplevel; }
+               public bool Resolved {
+                       get {
+                               return resolved;
+                       }
                }
 
-               public ToplevelBlock (CompilerContext ctx, Block parent, ParametersCompiled parameters, Location start) :
-                       this (ctx, parent, (Flags) 0, parameters, start)
-               {
-               }
+               #endregion
 
-               public ToplevelBlock (CompilerContext ctx, ParametersCompiled parameters, Location start) :
-                       this (ctx, null, (Flags) 0, parameters, start)
+               // <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);
+                       }
                }
 
-               ToplevelBlock (CompilerContext ctx, Flags flags, ParametersCompiled parameters, Location start) :
-                       this (ctx, null, flags, parameters, start)
+               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);
                }
 
-               // 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)
+               public ParameterInfo GetParameterInfo (Parameter p)
                {
-                       this.compiler = ctx;
-                       this.Toplevel = this;
-
-                       this.parameters = parameters;
-                       this.Parent = parent;
-                       if (parent != null)
-                               parent.AddAnonymousChild (this);
+                       for (int i = 0; i < parameters.Count; ++i) {
+                               if (parameters[i] == p)
+                                       return parameter_info[i];
+                       }
 
-                       if (!this.parameters.IsEmpty)
-                               ProcessParameters ();
+                       throw new ArgumentException ("Invalid parameter");
                }
 
-               public ToplevelBlock (CompilerContext ctx, Location loc)
-                       : this (ctx, null, (Flags) 0, ParametersCompiled.EmptyReadOnlyParameters, loc)
+               public Expression GetParameterReference (int index, Location loc)
                {
+                       return new ParameterReference (parameter_info[index], loc);
                }
 
-               protected override void CloneTo (CloneContext clonectx, Statement t)
+               protected void ProcessParameters ()
                {
-                       ToplevelBlock target = (ToplevelBlock) t;
-                       base.CloneTo (clonectx, t);
+                       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;
 
-                       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);
+                               // TODO: Should use Parameter only and more block there
+                               parameter_info[i] = new ParameterInfo (this, i);
+                               AddLocalName (p.Name, parameter_info[i]);
                        }
                }
 
-               public bool CheckError158 (string name, Location loc)
+               public bool Resolve (FlowBranching parent, BlockContext rc, IMethodData md)
                {
-                       if (AnonymousChildren != null) {
-                               foreach (ToplevelBlock child in AnonymousChildren) {
-                                       if (!child.CheckError158 (name, loc))
+                       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;
                        }
 
-                       for (ToplevelBlock c = Container; c != null; c = c.Container) {
-                               if (!c.DoCheckError158 (name, loc))
+                       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;
                }
 
-               void ProcessParameters ()
+               void ResolveMeta (BlockContext ec)
                {
-                       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);
+                       int orig_count = parameters.Count;
 
-                               Parameter p = parameters [i];
-                               if (p == null)
+                       for (int i = 0; i < orig_count; ++i) {
+                               Parameter.Modifier mod = parameters.FixedParameters[i].ModFlags;
+
+                               if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT)
                                        continue;
 
-                               string name = p.Name;
-                               if (CheckParentConflictName (top_parent, name, loc))
-                                       AddKnownVariable (name, parameter_info [i]);
+                               VariableInfo vi = new VariableInfo (parameters, i, ec.FlowOffset);
+                               parameter_info[i].VariableInfo = vi;
+                               ec.FlowOffset += vi.Length;
                        }
-
-                       // mark this block as "used" so that we create local declarations in a sub-block
-                       // FIXME: This appears to uncover a lot of bugs
-                       //this.Use ();
                }
 
-               bool DoCheckError158 (string name, Location loc)
+               public void WrapIntoIterator (IMethodData method, TypeContainer host, TypeSpec iterator_type, bool is_enumerable)
                {
-                       LabeledStatement s = LookupLabel (name);
-                       if (s != null) {
-                               Report.SymbolRelatedToPreviousError (s.loc, s.Name);
-                               Error_158 (name, loc);
-                               return false;
-                       }
+                       ParametersBlock pb = new ParametersBlock (this, ParametersCompiled.EmptyReadOnlyParameters, StartLocation);
+                       pb.EndLocation = EndLocation;
+                       pb.statements = statements;
 
-                       return true;
+                       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));
                }
+       }
 
-               public override Expression CreateExpressionTree (ResolveContext ec)
+       //
+       //
+       //
+       public class ToplevelBlock : ParametersBlock
+       {
+               LocalVariable this_variable;
+               CompilerContext compiler;
+               Dictionary<string, object> names;
+               Dictionary<string, object> labels;
+
+               public HoistedVariable HoistedThisVariable;
+
+               public Report Report {
+                       get { return compiler.Report; }
+               }
+
+               public ToplevelBlock (CompilerContext ctx, Location loc)
+                       : this (ctx, ParametersCompiled.EmptyReadOnlyParameters, loc)
                {
-                       if (statements.Count == 1) {
-                               Expression expr = ((Statement) statements[0]).CreateExpressionTree (ec);
-                               if (scope_initializers != null)
-                                       expr = new BlockScopeExpression (expr, this);
+               }
 
-                               return expr;
-                       }
+               public ToplevelBlock (CompilerContext ctx, ParametersCompiled parameters, Location start)
+                       : base (parameters, start)
+               {
+                       this.compiler = ctx;
+                       top_block = this;
 
-                       return base.CreateExpressionTree (ec);
+                       ProcessParameters ();
                }
 
                //
-               // Reformats this block to be top-level iterator block
+               // 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 IteratorStorey ChangeToIterator (Iterator iterator, ToplevelBlock source)
+               public ToplevelBlock (ParametersBlock source, ParametersCompiled parameters)
+                       : base (source, parameters)
+               {
+                       this.compiler = source.TopBlock.compiler;
+                       top_block = this;
+               }
+
+               public override void AddLocalName (string name, INamedBlockVariable li)
                {
-                       IsIterator = true;
+                       if (names == null)
+                               names = new Dictionary<string, object> ();
+
+                       object value;
+                       if (!names.TryGetValue (name, out value)) {
+                               names.Add (name, li);
+                               return;
+                       }
+
+                       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;
+                       }
+
+                       //
+                       // A collision checking between local names
+                       //
+                       for (int i = 0; i < existing_list.Count; ++i) {
+                               existing = existing_list[i];
+                               Block b = existing.Block;
+
+                               // Collision at same level
+                               if (li.Block == b) {
+                                       li.Block.Error_AlreadyDeclared (name, li);
+                                       break;
+                               }
 
-                       // Creates block with original statements
-                       AddStatement (new IteratorStatement (iterator, new Block (this, source)));
+                               // 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;
+                                       }
+                               }
 
-                       source.statements = new List<Statement> (1);
-                       source.AddStatement (new Return (iterator, iterator.Location));
-                       source.IsIterator = false;
+                               // 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;
+                                       }
+                               }
+                       }
 
-                       IteratorStorey iterator_storey = new IteratorStorey (iterator);
-                       source.am_storey = iterator_storey;
-                       return iterator_storey;
+                       existing_list.Add (li);
                }
 
-               //
-               // Returns a parameter reference expression for the given name,
-               // or null if there is no such parameter
-               //
-               public Expression GetParameterReference (string name, Location loc)
+               public void AddLabel (string name, LabeledStatement label)
                {
-                       for (ToplevelBlock t = this; t != null; t = t.Container) {
-                               if (t.parameters.IsEmpty)
-                                       continue;
+                       if (labels == null)
+                               labels = new Dictionary<string, object> ();
 
-                               Expression expr = t.GetParameterReferenceExpression (name, loc);
-                               if (expr != null)
-                                       return expr;
+                       object value;
+                       if (!labels.TryGetValue (name, out value)) {
+                               labels.Add (name, label);
+                               return;
                        }
 
-                       return null;
+                       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;
+                       }
+
+                       //
+                       // 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;
+                               }
+
+                               // 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;
+                                       }
+                               }
+                       }
+
+                       existing_list.Add (label);
                }
 
-               protected virtual Expression GetParameterReferenceExpression (string name, Location loc)
+               //
+               // Creates an arguments set from all parameters, useful for method proxy calls
+               //
+               public Arguments GetAllParametersArguments ()
                {
-                       int idx = parameters.GetParameterIndexByName (name);
-                       return idx < 0 ?
-                               null : new ParameterReference (parameter_info [idx], loc);
+                       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));
+                       }
+
+                       return args;
                }
 
-               public ToplevelBlock CheckParameterNameConflict (string name)
+               //
+               // 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 bool GetLocalName (string name, Block block, ref INamedBlockVariable variable)
                {
-                       for (ToplevelBlock t = this; t != null; t = t.Container) {
-                               if (t.HasParameterWithName (name))
-                                       return t;
+                       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 bool HasParameterWithName (string name)
+               public LabeledStatement GetLabel (string name, Block block)
                {
-                       return parameters.GetParameterIndexByName (name) >= 0;
+                       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; }
                }
 
@@ -2747,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;
@@ -2765,122 +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 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) {
-                                       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)
@@ -2889,8 +2929,6 @@ namespace Mono.CSharp {
 #if PRODUCTION
                        try {
 #endif
-                       EmitMeta (ec);
-
                        if (ec.HasReturnLabel)
                                ec.ReturnLabel = ec.DefineLabel ();
 
@@ -2936,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;
@@ -3061,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;
                
@@ -3080,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));
@@ -3115,6 +3146,7 @@ namespace Mono.CSharp {
                ExpressionStatement string_dictionary;
                FieldExpr switch_cache_field;
                static int unique_counter;
+               ExplicitBlock block;
 
                //
                // Nullable Types support
@@ -3131,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;
@@ -3787,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 ();
 
@@ -3881,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);
@@ -3908,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);
                        }
 
@@ -3958,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) {
@@ -4032,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)
@@ -4050,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);
+                       //
+                       // 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 ok;
+
+                       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)
@@ -4104,7 +4244,7 @@ namespace Mono.CSharp {
                        Lock target = (Lock) t;
 
                        target.expr = expr.Clone (clonectx);
-                       target.Statement = Statement.Clone (clonectx);
+                       target.stmt = Statement.Clone (clonectx);
                }
        }
 
@@ -4203,40 +4343,37 @@ namespace Mono.CSharp {
        // 
        // Fixed statement
        //
-       public 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);
                        }
 
@@ -4250,32 +4387,39 @@ 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
@@ -4297,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,
@@ -4352,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, loc);
 
-                                       converted = converted.Resolve (ec);                                     
+                                       converted = converted.Resolve (bc);
 
-                                       data [i] = new ExpressionEmitter (converted, vi);
-                                       i++;
+                                       return new ExpressionEmitter (converted, li);
+                               }
 
-                                       continue;
+                               //
+                               // Case 2: string
+                               //
+                               if (initializer.Type == TypeManager.string_type) {
+                                       return new StringEmitter (initializer, li, loc).Resolve (bc);
+                               }
+
+                               // Case 3: fixed buffer
+                               if (initializer is FixedBufferPtr) {
+                                       return new ExpressionEmitter (initializer, li);
                                }
 
                                //
-                               // Case 3: string
+                               // Case 4: & object.
                                //
-                               if (e.Type == TypeManager.string_type){
-                                       data [i] = new StringEmitter (e, vi, loc).Resolve (ec);
-                                       i++;
-                                       continue;
+                               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) {
+                                               already_fixed = false;
+                                       }
+                               }
+
+                               if (already_fixed) {
+                                       bc.Report.Error (213, loc, "You cannot use the fixed statement to take the address of an already fixed expression");
                                }
 
-                               // Case 4: fixed buffer
-                               if (e is FixedBufferPtr) {
-                                       data [i++] = new ExpressionEmitter (e, vi);
-                                       continue;
-                               }
+                               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;
+                       }
+               }
 
-                               //
-                               // Case 1: & object.
-                               //
-                               Unary u = e 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);
-                                       }
-                               }
+               public BlockVariableDeclaration Variables {
+                       get {
+                               return decl;
+                       }
+               }
 
-                               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");
+               #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);
@@ -4446,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);
@@ -4458,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);
+                               }
                        }
                }
 
@@ -4467,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 {
@@ -4507,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);
                }
@@ -4552,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);
                        }
                }
 
@@ -4577,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)
@@ -4677,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;
@@ -4692,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]));
@@ -4704,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);
@@ -4765,144 +4930,185 @@ namespace Mono.CSharp {
                }
        }
 
-       // FIXME: Why is it almost exact copy of Using ??
-       public class UsingTemporary : ExceptionStatement
+       public class Using : ExceptionStatement
        {
-               protected TemporaryVariable local_copy;
-               Statement statement;
-               Expression expr;
-               protected Statement dispose_call;
-
-               public UsingTemporary (Expression expr, Statement stmt, Location l)
+               public class VariableDeclaration : BlockVariableDeclaration
                {
-                       this.expr = expr;
-                       statement = stmt;
-                       loc = l;
-               }
+                       Statement dispose_call;
 
-               #region Properties
-               public Expression Expression {
-                       get {
-                               return expr;
+                       public VariableDeclaration (FullNamedExpression type, LocalVariable li)
+                               : base (type, li)
+                       {
                        }
-               }
 
-               public Statement Statement {
-                       get {
-                               return statement;
+                       public VariableDeclaration (LocalVariable li, Location loc)
+                               : base (li)
+                       {
+                               this.loc = loc;
                        }
-               }
 
-               #endregion
+                       public VariableDeclaration (Expression expr)
+                               : base (null)
+                       {
+                               loc = expr.Location;
+                               Initializer = expr;
+                       }
 
-               protected virtual bool DoResolve (BlockContext ec)
-               {
-                       expr = expr.Resolve (ec);
-                       if (expr == null)
-                               return false;
+                       #region Properties
 
-                       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 bool IsNested { get; private set; }
+
+                       #endregion
+
+                       public void EmitDispose (EmitContext ec)
+                       {
+                               dispose_call.Emit (ec);
+                       }
+
+                       public override bool Resolve (BlockContext bc)
+                       {
+                               if (IsNested)
+                                       return true;
+
+                               return base.Resolve (bc);
+                       }
+
+                       public Expression ResolveExpression (BlockContext bc)
+                       {
+                               var e = Initializer.Resolve (bc);
+                               if (e == null)
+                                       return null;
 
-                               expr = Convert.ImplicitConversionRequired (ec, expr, TypeManager.idisposable_type, loc);
+                               li = LocalVariable.CreateCompilerGenerated (e.Type, bc.CurrentBlock, loc);
+                               Initializer = ResolveInitializer (bc, Variable, e);
+                               return e;
                        }
 
-                       var expr_type = expr.Type;
+                       protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
+                       {
+                               if (li.Type == InternalType.Dynamic) {
+                                       initializer = initializer.Resolve (bc);
+                                       if (initializer == null)
+                                               return null;
+
+                                       // 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;
+
+                                       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));
+                               }
 
-                       local_copy = new TemporaryVariable (expr_type, loc);
-                       local_copy.Resolve (ec);
+                               if (li == Variable) {
+                                       CheckIDiposableConversion (bc, li, initializer);
+                                       dispose_call = CreateDisposeCall (bc, li);
+                                       dispose_call.Resolve (bc);
+                               }
 
-                       if (TypeManager.void_dispose_void == null) {
-                               TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
-                                       TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes);
+                               return base.ResolveInitializer (bc, li, initializer);
                        }
 
-                       var dispose_mg = MethodGroupExpr.CreatePredefined (TypeManager.void_dispose_void, TypeManager.idisposable_type, loc);
-                       dispose_mg.InstanceExpression = TypeManager.IsNullableType (expr_type) ?
-                               new Cast (new TypeExpression (TypeManager.idisposable_type, loc), local_copy, loc).Resolve (ec) :
-                               local_copy;
+                       protected virtual void CheckIDiposableConversion (BlockContext bc, LocalVariable li, Expression initializer)
+                       {
+                               var type = li.Type;
 
-                       dispose_call = new StatementExpression (new Invocation (dispose_mg, null));
+                               if (type != TypeManager.idisposable_type && !type.ImplementsInterface (TypeManager.idisposable_type, false)) {
+                                       if (TypeManager.IsNullableType (type)) {
+                                               // it's handled in CreateDisposeCall
+                                               return;
+                                       }
 
-                       // Add conditional call when disposing possible null variable
-                       if (!expr_type.IsStruct || TypeManager.IsNullableType (expr_type))
-                               dispose_call = new If (new Binary (Binary.Operator.Inequality, local_copy, new NullLiteral (loc), loc), dispose_call, loc);
+                                       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 ());
 
-                       return dispose_call.Resolve (ec);
-               }
+                                       return;
+                               }
+                       }
 
-               public override bool Resolve (BlockContext ec)
-               {
-                       bool ok = DoResolve (ec);
+                       protected virtual Statement CreateDisposeCall (BlockContext bc, LocalVariable lv)
+                       {
+                               var lvr = lv.CreateReferenceExpression (bc, lv.Location);
+                               var type = lv.Type;
+                               var loc = lv.Location;
 
-                       ec.StartFlowBranching (this);
+                               if (TypeManager.void_dispose_void == null) {
+                                       TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
+                                               TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes);
+                               }
 
-                       ok &= statement.Resolve (ec);
+                               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;
 
-                       ec.EndFlowBranching ();
+                               Statement dispose = new StatementExpression (new Invocation (dispose_mg, null));
 
-                       ok &= base.Resolve (ec);
+                               // 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 ok;
-               }
+                               return dispose;
+                       }
 
-               protected override void EmitPreTryBody (EmitContext ec)
-               {
-                       local_copy.EmitAssign (ec, expr);
-               }
+                       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);
+                               }
 
-               protected override void EmitTryBody (EmitContext ec)
-               {
-                       statement.Emit (ec);
+                               declarators = null;
+                               return stmt;
+                       }
                }
 
-               protected override void EmitFinallyBody (EmitContext ec)
-               {
-                       dispose_call.Emit (ec);
-               }
+               VariableDeclaration decl;
 
-               protected override void CloneTo (CloneContext clonectx, Statement t)
+               public Using (VariableDeclaration decl, Statement stmt, Location loc)
+                       : base (stmt, loc)
                {
-                       UsingTemporary target = (UsingTemporary) t;
-
-                       target.expr = expr.Clone (clonectx);
-                       target.statement = statement.Clone (clonectx);
+                       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)
@@ -4912,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, 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);
                }
        }
@@ -4991,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];
 
                                //
@@ -5037,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)
@@ -5047,27 +5214,30 @@ 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, loc).Resolve (ec);
@@ -5094,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))
@@ -5129,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);
@@ -5164,16 +5334,16 @@ namespace Mono.CSharp {
                        class Body : Statement
                        {
                                TypeSpec type;
-                               Expression variable, current, conv;
+                               LocalVariableReference variable;
+                               Expression current, conv;
                                Statement statement;
-                               Assign assign;
 
-                               public Body (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;
@@ -5194,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;
@@ -5206,67 +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);
                                }
                        }
 
-                       class Dispose : UsingTemporary
+                       class RuntimeDispose : Using.VariableDeclaration
                        {
-                               LocalTemporary dispose;
+                               public RuntimeDispose (LocalVariable lv, Location loc)
+                                       : base (lv, loc)
+                               {
+                               }
 
-                               public Dispose (TemporaryVariable variable, LocalTemporary dispose, Expression expr, Statement statement, Location loc)
-                                       : base (expr, statement, loc)
+                               protected override void CheckIDiposableConversion (BlockContext bc, LocalVariable li, Expression initializer)
                                {
-                                       base.local_copy = variable;
-                                       this.dispose = dispose;
+                                       // Defered to runtime check
                                }
 
-                               protected override bool DoResolve (BlockContext ec)
+                               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);
                                        }
 
-                                       Expression dispose_var = (Expression) dispose ?? local_copy;
-
-                                       var dispose_mg = MethodGroupExpr.CreatePredefined (TypeManager.void_dispose_void, TypeManager.idisposable_type, loc);
-                                       dispose_mg.InstanceExpression = dispose_var;
-
-                                       dispose_call = new StatementExpression (new Invocation (dispose_mg, null));
-
-                                       if (!dispose_var.Type.IsStruct)
-                                               dispose_call = new If (new Binary (Binary.Operator.Inequality, dispose_var, new NullLiteral (loc), loc), dispose_call, loc);
+                                       //
+                                       // Fabricates code like
+                                       //
+                                       // if ((temp = vr as IDisposable) != null) temp.Dispose ();
+                                       //
 
-                                       return dispose_call.Resolve (ec);
-                               }
+                                       var dispose_variable = LocalVariable.CreateCompilerGenerated (TypeManager.idisposable_type, bc.CurrentBlock, loc);
 
-                               protected override void EmitFinallyBody (EmitContext ec)
-                               {
-                                       Label call_dispose = ec.DefineLabel ();
-                                       if (dispose != null) {
-                                               local_copy.Emit (ec, false);
-                                               ec.Emit (OpCodes.Isinst, dispose.Type);
-                                               dispose.Store (ec);
-                                       }
+                                       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);
 
-                                       base.EmitFinallyBody (ec);
+                                       var dispose_mg = MethodGroupExpr.CreatePredefined (TypeManager.void_dispose_void, TypeManager.idisposable_type, loc);
+                                       dispose_mg.InstanceExpression = dispose_variable.CreateReferenceExpression (bc, loc);
 
-                                       if (dispose != null) {
-                                               ec.MarkLabel (call_dispose);
-                                               dispose.Release (ec);
-                                       }
+                                       Statement dispose = new StatementExpression (new Invocation (dispose_mg, null));
+                                       return new If (idisaposable_test, dispose, loc);
                                }
                        }
 
-                       Expression variable, expr;
+                       LocalVariable variable;
+                       Expression expr;
                        Statement statement;
                        Expression var_type;
                        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;
@@ -5288,20 +5452,13 @@ namespace Mono.CSharp {
                                                enumerator.ReturnType.GetSignatureForError (), enumerator.GetSignatureForError ());
                        }
 
-                       void Error_AmbiguousIEnumerable (ResolveContext rc, TypeSpec type)
-                       {
-                               rc.Report.SymbolRelatedToPreviousError (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",
-                                       type.GetSignatureForError (), TypeManager.generic_ienumerable_type.GetSignatureForError ());
-                       }
-
                        MethodGroupExpr ResolveGetEnumerator (ResolveContext rc)
                        {
                                //
                                // Option 1: Try to match by name GetEnumerator first
                                //
-                               var mexpr = Expression.MemberLookup (rc, rc.CurrentType, expr.Type, "GetEnumerator", 0, true, loc);             // TODO: What if CS0229 ?
+                               var mexpr = Expression.MemberLookup (rc, rc.CurrentType, expr.Type,
+                                       "GetEnumerator", 0, Expression.MemberLookupRestrictions.ExactArity, loc);               // TODO: What if CS0229 ?
 
                                var mg = mexpr as MethodGroupExpr;
                                if (mg != null) {
@@ -5309,6 +5466,10 @@ namespace Mono.CSharp {
                                        Arguments args = new Arguments (0);
                                        mg = mg.OverloadResolve (rc, ref args, this, OverloadResolver.Restrictions.None);
 
+                                       // For ambiguous GetEnumerator name warning CS0278 was reported, but Option 2 could still apply
+                                       if (ambiguous_getenumerator_name)
+                                               mg = null;
+
                                        if (mg != null && args.Count == 0 && !mg.BestCandidate.IsStatic && mg.BestCandidate.IsPublic) {
                                                return mg;
                                        }
@@ -5318,13 +5479,18 @@ namespace Mono.CSharp {
                                // Option 2: Try to match using IEnumerable interfaces with preference of generic version
                                //
                                TypeSpec iface_candidate = null;
-                               for (TypeSpec t = expr.Type; t != null && t != TypeManager.object_type; t = t.BaseType) {
+                               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) {
-                                                                       Error_AmbiguousIEnumerable (rc, expr.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;
                                                                }
 
@@ -5337,7 +5503,13 @@ namespace Mono.CSharp {
                                                        }
                                                }
                                        }
-                               }
+
+                                       if (t.IsGenericParameter)
+                                               t = t.BaseType;
+                                       else
+                                               t = null;
+
+                               } while (t != null);
 
                                if (iface_candidate == null) {
                                        rc.Report.Error (1579, loc,
@@ -5389,8 +5561,12 @@ namespace Mono.CSharp {
                        public override bool Resolve (BlockContext ec)
                        {
                                bool is_dynamic = expr.Type == InternalType.Dynamic;
-                               if (is_dynamic)
+
+                               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);
+                               }
 
                                var get_enumerator_mg = ResolveGetEnumerator (ec);
                                if (get_enumerator_mg == null) {
@@ -5398,8 +5574,8 @@ namespace Mono.CSharp {
                                }
 
                                var get_enumerator = get_enumerator_mg.BestCandidate;
-                               var enumerator = new TemporaryVariable (get_enumerator.ReturnType, loc);
-                               enumerator.Resolve (ec);
+                               enumerator_variable = TemporaryVariableReference.Create (get_enumerator.ReturnType, variable.Block, loc);
+                               enumerator_variable.Resolve (ec);
 
                                // Prepare bool MoveNext ()
                                var move_next_mg = ResolveMoveNext (ec, get_enumerator);
@@ -5407,7 +5583,7 @@ namespace Mono.CSharp {
                                        return false;
                                }
 
-                               move_next_mg.InstanceExpression = enumerator;
+                               move_next_mg.InstanceExpression = enumerator_variable;
 
                                // Prepare ~T~ Current { get; }
                                var current_prop = ResolveCurrent (ec, get_enumerator);
@@ -5415,50 +5591,62 @@ namespace Mono.CSharp {
                                        return false;
                                }
 
-                               var current_pe = new PropertyExpr (current_prop, loc) { InstanceExpression = enumerator }.Resolve (ec);
+                               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 (current_pe.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;
 
+                               variable.Type = var_type.Type;
+
                                var init = new Invocation (get_enumerator_mg, null);
-                               init.Resolve (ec);
 
                                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.Type;
+                               var enum_type = enumerator_variable.Type;
 
                                //
                                // Add Dispose method call when enumerator can be IDisposable
                                //
-                               if (!enumerator.Type.ImplementsInterface (TypeManager.idisposable_type)) {
+                               if (!enum_type.ImplementsInterface (TypeManager.idisposable_type, false)) {
                                        if (!enum_type.IsSealed && !TypeManager.IsValueType (enum_type)) {
                                                //
                                                // Runtime Dispose check
                                                //
-                                               var tv = new LocalTemporary (TypeManager.idisposable_type);
-                                               statement = new Dispose (enumerator, tv, init, statement, loc);
+                                               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, init);
+                                               this.init = new SimpleAssign (enumerator_variable, init);
                                                this.init.Resolve (ec);
                                        }
                                } else {
                                        //
                                        // Static Dispose check
                                        //
-                                       statement = new Dispose (enumerator, null, init, statement, loc);
+                                       var vd = new Using.VariableDeclaration (enumerator_variable.LocalInfo, loc);
+                                       vd.Initializer = init;
+                                       statement = new Using (vd, statement, loc);
                                }
 
                                return statement.Resolve (ec);
@@ -5466,6 +5654,8 @@ namespace Mono.CSharp {
 
                        protected override void DoEmit (EmitContext ec)
                        {
+                               enumerator_variable.LocalInfo.CreateBuilder (ec);
+
                                if (init != null)
                                        init.EmitStatement (ec);
 
@@ -5482,7 +5672,7 @@ namespace Mono.CSharp {
                                        expr.Type.GetSignatureForError (), "enumerable",
                                        best.GetSignatureForError (), ambiguous.GetSignatureForError ());
 
-                               Error_AmbiguousIEnumerable (ec, expr.Type);
+                               ambiguous_getenumerator_name = true;
                                return true;
                        }
 
@@ -5505,12 +5695,11 @@ namespace Mono.CSharp {
                }
 
                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;
@@ -5568,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);
                }