[csharp] repl using statement fix + support for --fatal
[mono.git] / mcs / mcs / statement.cs
index f3db628bb1656e2232a666318d5aec04d101e9fa..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 {
@@ -860,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;
                }
 
@@ -879,6 +883,12 @@ namespace Mono.CSharp {
                        return label;
                }
 
+               public Block Block {
+                       get {
+                               return block;
+                       }
+               }
+
                public string Name {
                        get { return name; }
                }
@@ -916,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);
                }
@@ -1170,6 +1183,12 @@ namespace Mono.CSharp {
                                this.initializer = initializer;
                        }
 
+                       public Declarator (Declarator clone, Expression initializer)
+                       {
+                               this.li = clone.li;
+                               this.initializer = initializer;
+                       }
+
                        #region Properties
 
                        public LocalVariable Variable {
@@ -1192,7 +1211,7 @@ namespace Mono.CSharp {
 
                Expression initializer;
                protected FullNamedExpression type_expr;
-               LocalVariable li;
+               protected LocalVariable li;
                protected List<Declarator> declarators;
 
                public BlockVariableDeclaration (FullNamedExpression type, LocalVariable li)
@@ -1263,64 +1282,66 @@ namespace Mono.CSharp {
 
                public override bool Resolve (BlockContext bc)
                {
-                       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;
-                                       }
+                       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;
+                                               }
 
-                                       if (li.IsConstant) {
-                                               bc.Report.Error (822, loc, "An implicitly typed local variable cannot be a constant");
-                                               return false;
-                                       }
+                                               if (li.IsConstant) {
+                                                       bc.Report.Error (822, loc, "An implicitly typed local variable cannot be a constant");
+                                                       return false;
+                                               }
 
-                                       if (Initializer == null) {
-                                               bc.Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");
-                                               return false;
-                                       }
+                                               if (Initializer == null) {
+                                                       bc.Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");
+                                                       return false;
+                                               }
 
-                                       if (declarators != null) {
-                                               bc.Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
-                                               declarators = null;
-                                       }
+                                               if (declarators != null) {
+                                                       bc.Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
+                                                       declarators = null;
+                                               }
 
-                                       Initializer = Initializer.Resolve (bc);
-                                       if (Initializer != null) {
-                                               ((VarExpr) type_expr).InferType (bc, Initializer);
-                                               type = type_expr.Type;
+                                               Initializer = Initializer.Resolve (bc);
+                                               if (Initializer != null) {
+                                                       ((VarExpr) type_expr).InferType (bc, Initializer);
+                                                       type = type_expr.Type;
+                                               }
                                        }
                                }
-                       }
 
-                       if (type == null) {
-                               var texpr = type_expr.ResolveAsTypeTerminal (bc, false);
-                               if (texpr == null)
-                                       return false;
+                               if (type == null) {
+                                       var texpr = type_expr.ResolveAsTypeTerminal (bc, false);
+                                       if (texpr == null)
+                                               return false;
 
-                               type = texpr.Type;
+                                       type = texpr.Type;
 
-                               if (li.IsConstant && !type.IsConstantCompatible) {
-                                       Const.Error_InvalidConstantType (type, loc, bc.Report);
+                                       if (li.IsConstant && !type.IsConstantCompatible) {
+                                               Const.Error_InvalidConstantType (type, loc, bc.Report);
+                                       }
                                }
-                       }
 
-                       if (type.IsStatic)
-                               FieldBase.Error_VariableOfStaticClass (loc, li.Name, type, bc.Report);
+                               if (type.IsStatic)
+                                       FieldBase.Error_VariableOfStaticClass (loc, li.Name, type, bc.Report);
 
-                       if (type.IsPointer && !bc.IsUnsafe)
-                               Expression.UnsafeError (bc, loc);
+                               if (type.IsPointer && !bc.IsUnsafe)
+                                       Expression.UnsafeError (bc, loc);
 
-                       li.Type = type;
+                               li.Type = type;
+                       }
 
                        bool eval_global = RootContext.StatementMode && bc.CurrentBlock is ToplevelBlock;
                        if (eval_global) {
@@ -1336,7 +1357,7 @@ namespace Mono.CSharp {
 
                        if (declarators != null) {
                                foreach (var d in declarators) {
-                                       d.Variable.Type = type;
+                                       d.Variable.Type = li.Type;
                                        if (eval_global) {
                                                CreateEvaluatorVariable (bc, d.Variable);
                                        } else {
@@ -1382,14 +1403,16 @@ namespace Mono.CSharp {
                {
                        BlockVariableDeclaration t = (BlockVariableDeclaration) target;
 
-                       t.type_expr = (FullNamedExpression) type_expr.Clone (clonectx);
+                       if (type_expr != null)
+                               t.type_expr = (FullNamedExpression) type_expr.Clone (clonectx);
+
                        if (initializer != null)
                                t.initializer = initializer.Clone (clonectx);
 
                        if (declarators != null) {
                                t.declarators = null;
                                foreach (var d in declarators)
-                                       t.AddDeclarator (new Declarator (d.Variable, d.Initializer == null ? null : d.Initializer.Clone (clonectx)));
+                                       t.AddDeclarator (new Declarator (d, d.Initializer == null ? null : d.Initializer.Clone (clonectx)));
                        }
                }
        }
@@ -1445,6 +1468,7 @@ namespace Mono.CSharp {
                        FixedVariable = 1 << 6,
                        UsingVariable = 1 << 7,
 //                     DefinitelyAssigned = 1 << 8,
+                       IsLocked = 1 << 9,
 
                        ReadonlyMask = ForeachVariable | FixedVariable | UsingVariable
                }
@@ -1484,6 +1508,11 @@ namespace Mono.CSharp {
 
                #region Properties
 
+               public bool AddressTaken {
+                       get { return (flags & Flags.AddressTaken) != 0; }
+                       set { flags |= Flags.AddressTaken; }
+               }
+
                public Block Block {
                        get {
                                return block;
@@ -1523,6 +1552,15 @@ namespace Mono.CSharp {
                        }
                }
 
+               public bool IsLocked {
+                       get {
+                               return (flags & Flags.IsLocked) != 0;
+                       }
+                       set {
+                               flags = value ? flags | Flags.IsLocked : flags & ~Flags.IsLocked;
+                       }
+               }
+
                public bool IsThis {
                        get {
                                return (flags & Flags.IsThis) != 0;
@@ -1614,6 +1652,10 @@ namespace Mono.CSharp {
 
                public void Emit (EmitContext ec)
                {
+                       // TODO: Need something better for temporary variables
+                       if ((flags & Flags.CompilerGenerated) != 0)
+                               CreateBuilder (ec);
+
                        ec.Emit (OpCodes.Ldloc, builder);
                }
 
@@ -1631,6 +1673,20 @@ namespace Mono.CSharp {
                        ec.Emit (OpCodes.Ldloca, builder);
                }
 
+               public string GetReadOnlyContext ()
+               {
+                       switch (flags & Flags.ReadonlyMask) {
+                       case Flags.FixedVariable:
+                               return "fixed variable";
+                       case Flags.ForeachVariable:
+                               return "foreach iteration variable";
+                       case Flags.UsingVariable:
+                               return "using variable";
+                       }
+
+                       throw new InternalErrorException ("Variable is not readonly");
+               }
+
                public bool IsThisAssigned (BlockContext ec, Block block)
                {
                        if (VariableInfo == null)
@@ -1670,29 +1726,10 @@ namespace Mono.CSharp {
                        flags |= Flags.Used;
                }
 
-               public bool AddressTaken {
-                       get { return (flags & Flags.AddressTaken) != 0; }
-                       set { flags |= Flags.AddressTaken; }
-               }
-
                public override string ToString ()
                {
                        return string.Format ("LocalInfo ({0},{1},{2},{3})", name, type, VariableInfo, Location);
                }
-
-               public string GetReadOnlyContext ()
-               {
-                       switch (flags & Flags.ReadonlyMask) {
-                       case Flags.FixedVariable:
-                               return "fixed variable";
-                       case Flags.ForeachVariable:
-                               return "foreach iteration variable";
-                       case Flags.UsingVariable:
-                               return "using variable";
-                       }
-
-                       throw new InternalErrorException ("Variable is not readonly");
-               }
        }
 
        /// <summary>
@@ -1737,16 +1774,6 @@ namespace Mono.CSharp {
                //
                protected List<Statement> statements;
 
-               //
-               // Labels.  (label, block) pairs.
-               //
-               protected Dictionary<string, LabeledStatement> labels;
-
-               //
-               // If this is a switch section, the enclosing switch block.
-               //
-               protected ExplicitBlock switch_block;
-
                protected List<Statement> scope_initializers;
 
                int? resolving_init_idx;
@@ -1817,11 +1844,11 @@ namespace Mono.CSharp {
 
                #endregion
 
-               public ExplicitBlock CreateSwitchBlock (Location start)
+               public Block CreateSwitchBlock (Location start)
                {
                        // FIXME: Only explicit block should be created
-                       var new_block = new ExplicitBlock (this, start, start);
-                       new_block.switch_block = Explicit;
+                       var new_block = new Block (this, start, start);
+                       new_block.IsCompilerGenerated = true;
                        return new_block;
                }
 
@@ -1830,104 +1857,9 @@ namespace Mono.CSharp {
                        EndLocation = loc;
                }
 
-               protected void Error_158 (string name, Location loc)
-               {
-                       ParametersBlock.TopBlock.Report.Error (158, loc, "The label `{0}' shadows another label " +
-                                     "by the same name in a contained scope", name);
-               }
-
-               /// <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) {
-                                       ParametersBlock.TopBlock.Report.SymbolRelatedToPreviousError (s.loc, s.Name);
-                                       ParametersBlock.TopBlock.Report.Error (140, target.loc, "The label `{0}' is a duplicate", name);
-                                       return false;
-                               }
-
-                               if (this == Explicit)
-                                       break;
-
-                               cur = cur.Parent;
-                       }
-
-                       while (cur != null) {
-                               if (cur.DoLookupLabel (name) != null) {
-                                       Error_158 (name, target.loc);
-                                       return false;
-                               }
-/*
-                               if (children != null) {
-                                       foreach (Block b in children) {
-                                               LabeledStatement s = b.DoLookupLabel (name);
-                                               if (s == null)
-                                                       continue;
-
-                                               Toplevel.Report.SymbolRelatedToPreviousError (s.loc, s.Name);
-                                               Error_158 (name, target.loc);
-                                               return false;
-                                       }
-                               }
-*/
-                               cur = cur.Parent;
-                       }
-
-                       ParametersBlock.TopBlock.CheckError158 (name, target.loc);
-
-                       if (labels == null)
-                               labels = new Dictionary<string, LabeledStatement> ();
-
-                       labels.Add (name, target);
-                       return true;
-               }
-
-               public LabeledStatement LookupLabel (string name)
-               {
-                       LabeledStatement s = DoLookupLabel (name);
-                       if (s != null)
-                               return s;
-/*
-                       if (children == null)
-                               return null;
-
-                       foreach (Block child in children) {
-                               if (Explicit != child.Explicit)
-                                       continue;
-
-                               s = child.LookupLabel (name);
-                               if (s != null)
-                                       return s;
-                       }
-*/
-                       return null;
-               }
-
-               LabeledStatement DoLookupLabel (string name)
+               public void AddLabel (LabeledStatement target)
                {
-                       if (switch_block != null)
-                               return switch_block.LookupLabel (name);
-
-                       if (labels != null)
-                               if (labels.ContainsKey (name))
-                                       return labels [name];
-
-                       return null;
+                       ParametersBlock.TopBlock.AddLabel (target.Name, target);
                }
 
                public void AddLocalName (LocalVariable li)
@@ -2015,6 +1947,11 @@ namespace Mono.CSharp {
                        }
                }
 
+               public LabeledStatement LookupLabel (string name)
+               {
+                       return ParametersBlock.TopBlock.GetLabel (name, this);
+               }
+
                public override bool Resolve (BlockContext ec)
                {
                        Block prev_block = ec.CurrentBlock;
@@ -2106,12 +2043,6 @@ namespace Mono.CSharp {
                        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");
-                       }
-
                        return ok;
                }
 
@@ -2250,15 +2181,6 @@ namespace Mono.CSharp {
                                return ParametersBlock.am_storey;
                        }
 
-                       //
-                       // Switch block does not follow sequential flow and we cannot emit
-                       // storey initialization inside the block because it can be jumped over
-                       // for all non-first cases. Instead we push it up to the parent block to be
-                       // always initialized
-                       //
-                       if (switch_block != null)
-                               return switch_block.CreateAnonymousMethodStorey (ec);
-
                        if (am_storey == null) {
                                MemberBase mc = ec.MemberContext as MemberBase;
 
@@ -2275,7 +2197,7 @@ namespace Mono.CSharp {
                {
                        if (am_storey != null) {
                                DefineAnonymousStorey (ec);
-                               am_storey.EmitStoreyInstantiation (ec);
+                               am_storey.EmitStoreyInstantiation (ec, this);
                        }
 
                        bool emit_debug_info = SymbolWriter.HasSymbolWriter && Parent != null && !(am_storey is IteratorStorey);
@@ -2364,6 +2286,7 @@ namespace Mono.CSharp {
                        readonly ParametersBlock block;
                        readonly int index;
                        public VariableInfo VariableInfo;
+                       bool is_locked;
 
                        public ParameterInfo (ParametersBlock block, int index)
                        {
@@ -2385,6 +2308,15 @@ namespace Mono.CSharp {
                                }
                        }
 
+                       public bool IsLocked {
+                               get {
+                                       return is_locked;
+                               }
+                               set {
+                                       is_locked = value;
+                               }
+                       }
+
                        public Location Location {
                                get {
                                        return Parameter.Location;
@@ -2486,7 +2418,6 @@ namespace Mono.CSharp {
                        this.parameters = parameters;
                        this.statements = source.statements;
                        this.scope_initializers = source.scope_initializers;
-                       this.switch_block = source.switch_block;
 
                        this.resolved = true;
                        this.unreachable = source.unreachable;
@@ -2690,6 +2621,7 @@ namespace Mono.CSharp {
                LocalVariable this_variable;
                CompilerContext compiler;
                Dictionary<string, object> names;
+               Dictionary<string, object> labels;
 
                public HoistedVariable HoistedThisVariable;
 
@@ -2782,34 +2714,65 @@ namespace Mono.CSharp {
                        existing_list.Add (li);
                }
 
-               public bool CheckError158 (string name, Location loc)
+               public void AddLabel (string name, LabeledStatement label)
                {
-/*
-                       if (AnonymousChildren != null) {
-                               foreach (ToplevelBlock child in AnonymousChildren) {
-                                       if (!child.CheckError158 (name, loc))
-                                               return false;
-                               }
+                       if (labels == null)
+                               labels = new Dictionary<string, object> ();
+
+                       object value;
+                       if (!labels.TryGetValue (name, out value)) {
+                               labels.Add (name, label);
+                               return;
                        }
 
-                       for (ToplevelBlock c = Container; c != null; c = c.Container) {
-                               if (!c.DoCheckError158 (name, loc))
-                                       return false;
+                       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;
                        }
-*/
-                       return true;
-               }
 
-               bool DoCheckError158 (string name, Location loc)
-               {
-                       LabeledStatement s = LookupLabel (name);
-                       if (s != null) {
-                               Report.SymbolRelatedToPreviousError (s.loc, s.Name);
-                               Error_158 (name, loc);
-                               return false;
+                       //
+                       // 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;
+                                       }
+                               }
                        }
 
-                       return true;
+                       existing_list.Add (label);
                }
 
                //
@@ -2847,7 +2810,7 @@ namespace Mono.CSharp {
                        Block b = block;
                        if (variable != null) {
                                do {
-                                       if (variable.Block == b)
+                                       if (variable.Block == b.Original)
                                                return true;
 
                                        b = b.Parent;
@@ -2865,7 +2828,7 @@ namespace Mono.CSharp {
                                for (int i = 0; i < list.Count; ++i) {
                                        variable = list[i];
                                        do {
-                                               if (variable.Block == b)
+                                               if (variable.Block == b.Original)
                                                        return true;
 
                                                b = b.Parent;
@@ -2887,6 +2850,41 @@ namespace Mono.CSharp {
                        return false;
                }
 
+               public LabeledStatement GetLabel (string name, Block block)
+               {
+                       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.
@@ -3092,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;
                
@@ -3111,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));
@@ -3146,6 +3146,7 @@ namespace Mono.CSharp {
                ExpressionStatement string_dictionary;
                FieldExpr switch_cache_field;
                static int unique_counter;
+               ExplicitBlock block;
 
                //
                // Nullable Types support
@@ -3162,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;
@@ -3818,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 ();
 
@@ -4080,7 +4094,8 @@ namespace Mono.CSharp {
 
        public class Lock : ExceptionStatement {
                Expression expr;
-               TemporaryVariableReference temp;
+               TemporaryVariableReference expr_copy;
+               TemporaryVariableReference lock_taken;
                        
                public Lock (Expression expr, Statement stmt, Location loc)
                        : base (stmt, loc)
@@ -4096,47 +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;
+                       }
 
-                       temp = TemporaryVariableReference.Create (expr.Type, ec.CurrentBlock.Parent, 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)
@@ -4303,8 +4403,11 @@ namespace Mono.CSharp {
                                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;
@@ -4760,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);
@@ -4821,167 +4930,144 @@ namespace Mono.CSharp {
                }
        }
 
-       // FIXME: Why is it almost exact copy of Using ??
-       public class UsingTemporary : ExceptionStatement
+       public class Using : ExceptionStatement
        {
-               protected TemporaryVariableReference local_copy;
-               Expression expr;
-               protected Statement dispose_call;
-
-               public UsingTemporary (Expression expr, Statement stmt, Location loc)
-                       : base (stmt, loc)
+               public class VariableDeclaration : BlockVariableDeclaration
                {
-                       this.expr = expr;
-               }
+                       Statement dispose_call;
 
-               #region Properties
-               public Expression Expression {
-                       get {
-                               return expr;
+                       public VariableDeclaration (FullNamedExpression type, LocalVariable li)
+                               : base (type, li)
+                       {
                        }
-               }
-
-               #endregion
 
-               protected virtual bool DoResolve (BlockContext ec)
-               {
-                       expr = expr.Resolve (ec);
-                       if (expr == null)
-                               return false;
-
-                       if (expr.Type != TypeManager.idisposable_type && !expr.Type.ImplementsInterface (TypeManager.idisposable_type, false)) {
-                               if (TypeManager.IsNullableType (expr.Type)) {
-                                       // it's handled it a custom code bellow
-                               } else if (expr.Type == InternalType.Dynamic) {
-                                       expr = Convert.ImplicitConversionStandard (ec, expr, TypeManager.idisposable_type, loc);
-                               } else {
-                                       Using.Error_IsNotConvertibleToIDisposable (ec, expr.Type, expr.Location);
-                                       return false;
-                               }
+                       public VariableDeclaration (LocalVariable li, Location loc)
+                               : base (li)
+                       {
+                               this.loc = loc;
                        }
 
-                       var expr_type = expr.Type;
-
-                       local_copy = TemporaryVariableReference.Create (expr_type, ec.CurrentBlock.Parent, loc);
-                       local_copy.Resolve (ec);
-
-                       if (TypeManager.void_dispose_void == null) {
-                               TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
-                                       TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes);
+                       public VariableDeclaration (Expression expr)
+                               : base (null)
+                       {
+                               loc = expr.Location;
+                               Initializer = expr;
                        }
 
-                       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;
-
-                       dispose_call = new StatementExpression (new Invocation (dispose_mg, null));
-
-                       // 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);
-
-                       return dispose_call.Resolve (ec);
-               }
-
-               public override bool Resolve (BlockContext ec)
-               {
-                       bool ok = DoResolve (ec);
-
-                       ec.StartFlowBranching (this);
-
-                       ok &= stmt.Resolve (ec);
-
-                       ec.EndFlowBranching ();
-
-                       ok &= base.Resolve (ec);
-
-                       return ok;
-               }
-
-               protected override void EmitPreTryBody (EmitContext ec)
-               {
-                       //local_copy.Variable.
-                       local_copy.EmitAssign (ec, expr);
-               }
-
-               protected override void EmitTryBody (EmitContext ec)
-               {
-                       stmt.Emit (ec);
-               }
-
-               protected override void EmitFinallyBody (EmitContext ec)
-               {
-                       dispose_call.Emit (ec);
-               }
+                       #region Properties
 
-               protected override void CloneTo (CloneContext clonectx, Statement t)
-               {
-                       UsingTemporary target = (UsingTemporary) t;
+                       public bool IsNested { get; private set; }
 
-                       target.expr = expr.Clone (clonectx);
-                       target.stmt = stmt.Clone (clonectx);
-               }
-       }
+                       #endregion
 
-       public class Using : ExceptionStatement
-       {
-               public class VariableDeclaration : BlockVariableDeclaration
-               {
-                       public VariableDeclaration (FullNamedExpression type, LocalVariable li)
-                               : base (type, li)
+                       public void EmitDispose (EmitContext ec)
                        {
-                       }
-
-                       private VariableDeclaration (LocalVariable li, Location loc)
-                               : base (li)
-                       {
-                               this.loc = loc;
+                               dispose_call.Emit (ec);
                        }
 
                        public override bool Resolve (BlockContext bc)
                        {
-                               if (type_expr == null)
+                               if (IsNested)
                                        return true;
 
                                return base.Resolve (bc);
                        }
 
-                       protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
+                       public Expression ResolveExpression (BlockContext bc)
                        {
-                               Assign assign;
+                               var e = Initializer.Resolve (bc);
+                               if (e == null)
+                                       return null;
+
+                               li = LocalVariable.CreateCompilerGenerated (e.Type, bc.CurrentBlock, loc);
+                               Initializer = ResolveInitializer (bc, Variable, e);
+                               return e;
+                       }
 
+                       protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
+                       {
                                if (li.Type == InternalType.Dynamic) {
                                        initializer = initializer.Resolve (bc);
                                        if (initializer == null)
                                                return null;
 
-                                       initializer = Convert.ImplicitConversionRequired (bc, initializer, TypeManager.idisposable_type, loc);
+                                       // 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 = TemporaryVariableReference.Create (TypeManager.idisposable_type, bc.CurrentBlock, loc);
-                                       assign = new SimpleAssign (var, initializer, loc);
-                                       assign.ResolveStatement (bc);
-                                       return assign;
+                                       var var = LocalVariable.CreateCompilerGenerated (TypeManager.idisposable_type, bc.CurrentBlock, loc);
+                                       dispose_call = CreateDisposeCall (bc, var);
+                                       dispose_call.Resolve (bc);
+
+                                       return base.ResolveInitializer (bc, li, new SimpleAssign (var.CreateReferenceExpression (bc, loc), initializer, loc));
                                }
 
                                if (li == Variable) {
-                                       if (li.Type != TypeManager.idisposable_type && !li.Type.ImplementsInterface (TypeManager.idisposable_type, false)) {
-                                               Using.Error_IsNotConvertibleToIDisposable (bc, li.Type, type_expr.Location);
-                                               return null;
-                                       }
+                                       CheckIDiposableConversion (bc, li, initializer);
+                                       dispose_call = CreateDisposeCall (bc, li);
+                                       dispose_call.Resolve (bc);
                                }
 
                                return base.ResolveInitializer (bc, li, initializer);
                        }
 
+                       protected virtual void CheckIDiposableConversion (BlockContext bc, LocalVariable li, Expression initializer)
+                       {
+                               var type = li.Type;
+
+                               if (type != TypeManager.idisposable_type && !type.ImplementsInterface (TypeManager.idisposable_type, false)) {
+                                       if (TypeManager.IsNullableType (type)) {
+                                               // it's handled in CreateDisposeCall
+                                               return;
+                                       }
+
+                                       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;
+                               }
+                       }
+
+                       protected virtual Statement CreateDisposeCall (BlockContext bc, LocalVariable lv)
+                       {
+                               var lvr = lv.CreateReferenceExpression (bc, lv.Location);
+                               var type = lv.Type;
+                               var loc = lv.Location;
+
+                               if (TypeManager.void_dispose_void == null) {
+                                       TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
+                                               TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes);
+                               }
+
+                               var dispose_mg = MethodGroupExpr.CreatePredefined (TypeManager.void_dispose_void, TypeManager.idisposable_type, loc);
+                               dispose_mg.InstanceExpression = TypeManager.IsNullableType (type) ?
+                                       new Cast (new TypeExpression (TypeManager.idisposable_type, loc), lvr, loc).Resolve (bc) :
+                                       lvr;
+
+                               Statement dispose = new StatementExpression (new Invocation (dispose_mg, null));
+
+                               // Add conditional call when disposing possible null variable
+                               if (!type.IsStruct || TypeManager.IsNullableType (type))
+                                       dispose = new If (new Binary (Binary.Operator.Inequality, lvr, new NullLiteral (loc), loc), dispose, loc);
+
+                               return dispose;
+                       }
+
                        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);
                                }
 
@@ -4998,8 +5084,20 @@ namespace Mono.CSharp {
                        this.decl = decl;
                }
 
+               public Using (Expression expr, Statement stmt, Location loc)
+                       : base (stmt, loc)
+               {
+                       this.decl = new VariableDeclaration (expr);
+               }
+
                #region Properties
 
+               public Expression Expression {
+                       get {
+                               return decl.Variable == null ? decl.Initializer : null;
+                       }
+               }
+
                public BlockVariableDeclaration Variables {
                        get {
                                return decl;
@@ -5008,13 +5106,6 @@ namespace Mono.CSharp {
 
                #endregion
 
-               static public void Error_IsNotConvertibleToIDisposable (BlockContext ec, TypeSpec type, Location loc)
-               {
-                       ec.Report.SymbolRelatedToPreviousError (type);
-                       ec.Report.Error (1674, loc, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
-                               type.GetSignatureForError ());
-               }
-
                protected override void EmitPreTryBody (EmitContext ec)
                {
                        decl.Emit (ec);
@@ -5027,46 +5118,45 @@ namespace Mono.CSharp {
 
                protected override void EmitFinallyBody (EmitContext ec)
                {
-                       Label skip = ec.DefineLabel ();
-
-                       var var = ((Assign) decl.Initializer).Target;
-                       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)
                {
+                       VariableReference vr;
+                       bool vr_locked = false;
+
                        using (ec.Set (ResolveContext.Options.UsingInitializerScope)) {
-                               if (!decl.Resolve (ec))
-                                       return false;
+                               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;
 
-                               if (decl.Declarators != null) {
-                                       stmt = decl.RewriteForDeclarators (ec, stmt);
+                                       if (decl.Declarators != null) {
+                                               stmt = decl.RewriteForDeclarators (ec, stmt);
+                                       }
+
+                                       vr = null;
                                }
                        }
 
                        ec.StartFlowBranching (this);
 
-                       bool ok = stmt.Resolve (ec);
+                       stmt.Resolve (ec);
 
                        ec.EndFlowBranching ();
 
-                       ok &= base.Resolve (ec);
+                       if (vr != null)
+                               vr.IsLockedByStatement = vr_locked;
 
-                       if (TypeManager.void_dispose_void == null) {
-                               TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
-                                       TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes);
-                       }
+                       base.Resolve (ec);
 
-                       return ok;
+                       return true;
                }
 
                protected override void CloneTo (CloneContext clonectx, Statement t)
@@ -5174,7 +5264,6 @@ namespace Mono.CSharp {
                                ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
                                ec.CurrentBranching.CreateSibling ();
 
-                               // TODO: dynamic
                                variable.local_info.Type = conv.Type;
                                variable.Resolve (ec);
 
@@ -5293,52 +5382,43 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       class Dispose : UsingTemporary
+                       class RuntimeDispose : Using.VariableDeclaration
                        {
-                               LocalTemporary dispose;
+                               public RuntimeDispose (LocalVariable lv, Location loc)
+                                       : base (lv, loc)
+                               {
+                               }
 
-                               public Dispose (TemporaryVariableReference 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);
                                }
                        }
 
@@ -5399,7 +5479,8 @@ 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) {
@@ -5422,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,
@@ -5474,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) {
@@ -5525,7 +5616,6 @@ namespace Mono.CSharp {
                                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);
@@ -5540,8 +5630,9 @@ namespace Mono.CSharp {
                                                //
                                                // Runtime Dispose check
                                                //
-                                               var tv = new LocalTemporary (TypeManager.idisposable_type);
-                                               statement = new Dispose (enumerator_variable, 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
@@ -5553,7 +5644,9 @@ namespace Mono.CSharp {
                                        //
                                        // Static Dispose check
                                        //
-                                       statement = new Dispose (enumerator_variable, 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);