New tests, update
[mono.git] / mcs / mcs / statement.cs
index f2dfc37bf955f263b01323f4fe1070066266ee38..ec82cd4fb79f39b584670ed10e247d93267ed242 100644 (file)
@@ -93,9 +93,9 @@ namespace Mono.CSharp {
                // 
                protected virtual void CloneTo (CloneContext clonectx, Statement target)
                {
-                       throw new Exception (String.Format ("Statement.CloneTo not implemented for {0}", this.GetType ()));
+                       throw new InternalErrorException ("{0} does not implement Statement.CloneTo", this.GetType ());
                }
-               
+
                public Statement Clone (CloneContext clonectx)
                {
                        Statement s = (Statement) this.MemberwiseClone ();
@@ -143,6 +143,18 @@ namespace Mono.CSharp {
                        return result;
                }
 
+               ///
+               /// Remaps block to cloned copy if one exists.
+               ///
+               public Block RemapBlockCopy (Block from)
+               {
+                       Block mapped_to = (Block)block_map[from];
+                       if (mapped_to == null)
+                               return from;
+
+                       return mapped_to;
+               }
+
                public void AddVariableMap (LocalInfo from, LocalInfo to)
                {
                        if (variable_map == null)
@@ -183,6 +195,11 @@ namespace Mono.CSharp {
                protected override void DoEmit (EmitContext ec)
                {
                }
+
+               protected override void CloneTo (CloneContext clonectx, Statement target)
+               {
+                       // nothing needed.
+               }
        }
        
        public class If : Statement {
@@ -192,21 +209,21 @@ namespace Mono.CSharp {
 
                bool is_true_ret;
                
-               public If (Expression expr, Statement trueStatement, Location l)
+               public If (Expression expr, Statement true_statement, Location l)
                {
                        this.expr = expr;
-                       TrueStatement = trueStatement;
+                       TrueStatement = true_statement;
                        loc = l;
                }
 
                public If (Expression expr,
-                          Statement trueStatement,
-                          Statement falseStatement,
+                          Statement true_statement,
+                          Statement false_statement,
                           Location l)
                {
                        this.expr = expr;
-                       TrueStatement = trueStatement;
-                       FalseStatement = falseStatement;
+                       TrueStatement = true_statement;
+                       FalseStatement = false_statement;
                        loc = l;
                }
 
@@ -332,9 +349,9 @@ namespace Mono.CSharp {
                public Statement  EmbeddedStatement;
                bool infinite;
                
-               public Do (Statement statement, Expression boolExpr, Location l)
+               public Do (Statement statement, Expression bool_expr, Location l)
                {
-                       expr = boolExpr;
+                       expr = bool_expr;
                        EmbeddedStatement = statement;
                        loc = l;
                }
@@ -417,9 +434,9 @@ namespace Mono.CSharp {
                public Statement Statement;
                bool infinite, empty;
                
-               public While (Expression boolExpr, Statement statement, Location l)
+               public While (Expression bool_expr, Statement statement, Location l)
                {
-                       this.expr = boolExpr;
+                       this.expr = bool_expr;
                        Statement = statement;
                        loc = l;
                }
@@ -524,13 +541,13 @@ namespace Mono.CSharp {
                public Statement Statement;
                bool infinite, empty;
                
-               public For (Statement initStatement,
+               public For (Statement init_statement,
                            Expression test,
                            Statement increment,
                            Statement statement,
                            Location l)
                {
-                       InitStatement = initStatement;
+                       InitStatement = init_statement;
                        Test = test;
                        Increment = increment;
                        Statement = statement;
@@ -697,65 +714,74 @@ namespace Mono.CSharp {
        ///   Implements the return statement
        /// </summary>
        public class Return : Statement {
-               public Expression Expr;
+               Expression Expr;
+               bool unwind_protect;
                
                public Return (Expression expr, Location l)
                {
                        Expr = expr;
                        loc = l;
                }
-
-               bool unwind_protect;
-
-               public override bool Resolve (EmitContext ec)
+               
+               bool DoResolve (EmitContext ec)
                {
+                       if (Expr == null) {
+                               if (ec.ReturnType == TypeManager.void_type)
+                                       return true;
+                               
+                               Error (126, "An object of a type convertible to `{0}' is required " +
+                                          "for the return statement",
+                                          TypeManager.CSharpName (ec.ReturnType));
+                               return false;
+                       }
+
                        AnonymousContainer am = ec.CurrentAnonymousMethod;
                        if ((am != null) && am.IsIterator && ec.InIterator) {
                                Report.Error (1622, loc, "Cannot return a value from iterators. Use the yield return " +
-                                             "statement to return a value, or yield break to end the iteration");
-                               return false;
+                                                 "statement to return a value, or yield break to end the iteration");
                        }
 
-                       if (ec.ReturnType == null){
-                               if (Expr != null){
-                                       if (am != null){
-                                               Report.Error (1662, loc,
-                                                       "Cannot convert anonymous method block to delegate type `{0}' because some of the return types in the block are not implicitly convertible to the delegate return type",
-                                                       am.GetSignatureForError ());
-                                       }
-                                       Error (127, "A return keyword must not be followed by any expression when method returns void");
-                                       return false;
-                               }
-                       } else {
-                               if (Expr == null){
-                                       Error (126, "An object of a type convertible to `{0}' is required " +
-                                              "for the return statement",
-                                              TypeManager.CSharpName (ec.ReturnType));
-                                       return false;
-                               }
+                       if (am == null && ec.ReturnType == TypeManager.void_type) {
+                               MemberCore mc = ec.ResolveContext as MemberCore;
+                               Report.Error (127, loc, "`{0}': A return keyword must not be followed by any expression when method returns void",
+                                       mc.GetSignatureForError ());
+                       }
 
-                               Expr = Expr.Resolve (ec);
-                               if (Expr == null)
-                                       return false;
+                       Expr = Expr.Resolve (ec);
+                       if (Expr == null)
+                               return false;
 
-                               if (Expr.Type != ec.ReturnType) {
-                                       if (ec.InferReturnType) {
-                                               ec.ReturnType = Expr.Type;
-                                       } else {
-                                               Expr = Convert.ImplicitConversionRequired (
-                                                       ec, Expr, ec.ReturnType, loc);
-                                               if (Expr == null)
-                                                       return false;
+                       if (Expr.Type != ec.ReturnType) {
+                               if (ec.InferReturnType) {
+                                       ec.ReturnType = Expr.Type;
+                               } else {
+                                       Expr = Convert.ImplicitConversionRequired (
+                                               ec, Expr, ec.ReturnType, loc);
+
+                                       if (Expr == null) {
+                                               if (am != null) {
+                                                       Report.Error (1662, loc,
+                                                               "Cannot convert `{0}' to delegate type `{1}' because some of the return types in the block are not implicitly convertible to the delegate return type",
+                                                               am.ContainerType, am.GetSignatureForError ());
+                                               }
+                                               return false;
                                        }
                                }
                        }
 
-                       int errors = Report.Errors;
+                       return true;                    
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       if (!DoResolve (ec))
+                               return false;
+                       
                        unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
                        if (unwind_protect)
                                ec.NeedReturnLabel ();
                        ec.CurrentBranching.CurrentUsageVector.Goto ();
-                       return errors == Report.Errors;
+                       return true;
                }
                
                protected override void DoEmit (EmitContext ec)
@@ -776,8 +802,9 @@ namespace Mono.CSharp {
                protected override void CloneTo (CloneContext clonectx, Statement t)
                {
                        Return target = (Return) t;
-
-                       target.Expr = Expr.Clone (clonectx);
+                       // It's null for simple return;
+                       if (Expr != null)
+                               target.Expr = Expr.Clone (clonectx);
                }
        }
 
@@ -1087,6 +1114,11 @@ namespace Mono.CSharp {
                {
                        ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopEnd);
                }
+               
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       // nothing needed
+               }
        }
 
        public class Continue : Statement {
@@ -1110,6 +1142,11 @@ namespace Mono.CSharp {
                {
                        ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin);
                }
+
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       // nothing needed.
+               }
        }
 
        public abstract class Variable
@@ -1243,7 +1280,7 @@ namespace Mono.CSharp {
                public bool Resolve (EmitContext ec)
                {
                        if (VariableType == null) {
-                               TypeExpr texpr = Type.ResolveAsTypeTerminal (ec, false);
+                               TypeExpr texpr = Type.ResolveAsContextualType (ec, false);
                                if (texpr == null)
                                        return false;
                                
@@ -1394,8 +1431,18 @@ namespace Mono.CSharp {
 
                public LocalInfo Clone (CloneContext clonectx)
                {
-                       // Only this kind is created by the parser.
-                       return new LocalInfo (Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location);
+                       //
+                       // Variables in anonymous block are not resolved yet
+                       //
+                       if (VariableType == null)
+                               return new LocalInfo (Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location);
+
+                       //
+                       // Variables in method block are resolved
+                       //
+                       LocalInfo li = new LocalInfo (null, Name, clonectx.LookupBlock (Block), Location);
+                       li.VariableType = VariableType;
+                       return li;                      
                }
        }
 
@@ -1448,7 +1495,6 @@ namespace Mono.CSharp {
                // The statements in this block
                //
                protected ArrayList statements;
-               protected int current_statement;
                int num_statements;
 
                //
@@ -1491,6 +1537,11 @@ namespace Mono.CSharp {
                protected static int id;
 
                int this_id;
+
+               int assignable_slots;
+               protected ScopeInfo scope_info;
+               bool unreachable_shown;
+               bool unreachable;
                
                public Block (Block parent)
                        : this (parent, (Flags) 0, Location.Null, Location.Null)
@@ -1716,8 +1767,7 @@ namespace Mono.CSharp {
                        if (vi != null) {
                                Report.SymbolRelatedToPreviousError (vi.Location, name);
                                if (Explicit == vi.Block.Explicit)
-                                       Report.Error (128, l,
-                                               "A local variable named `{0}' is already defined in this scope", name);
+                                       Error_AlreadyDeclared (l, name, null);
                                else
                                        Error_AlreadyDeclared (l, name, "parent");
                                return null;
@@ -1728,7 +1778,18 @@ namespace Mono.CSharp {
                                Report.SymbolRelatedToPreviousError (pi.Location, name);
                                Error_AlreadyDeclared (loc, name,
                                        pi.Block == Toplevel ? "method argument" : "parent or current");
+                               return null;
                        }
+                       
+                       if (Toplevel.GenericMethod != null) {
+                               foreach (TypeParameter tp in Toplevel.GenericMethod.CurrentTypeParameters) {
+                                       if (tp.Name == name) {
+                                               Report.SymbolRelatedToPreviousError (tp);
+                                               Error_AlreadyDeclaredTypeParameter (loc, name);
+                                               return null;
+                                       }
+                               }
+                       }                       
 
                        IKnownVariable kvi = Explicit.GetKnownVariable (name);
                        if (kvi != null) {
@@ -1738,23 +1799,44 @@ namespace Mono.CSharp {
                        }
 
                        vi = new LocalInfo (type, name, this, l);
-                       Variables.Add (name, vi);
-                       Explicit.AddKnownVariable (name, vi);
+                       AddVariable (vi);
 
                        if ((flags & Flags.VariablesInitialized) != 0)
                                throw new InternalErrorException ("block has already been resolved");
 
                        return vi;
                }
+               
+               protected virtual void AddVariable (LocalInfo li)
+               {
+                       Variables.Add (li.Name, li);
+                       Explicit.AddKnownVariable (li.Name, li);
+               }
 
-               protected static void Error_AlreadyDeclared (Location loc, string var, string reason)
+               protected virtual void Error_AlreadyDeclared (Location loc, string var, string reason)
                {
+                       if (reason == null) {
+                               Error_AlreadyDeclared (loc, var);
+                               return;
+                       }
+                       
                        Report.Error (136, loc, "A local variable named `{0}' cannot be declared " +
                                      "in this scope because it would give a different meaning " +
                                      "to `{0}', which is already used in a `{1}' scope " +
                                      "to denote something else", var, reason);
                }
 
+               protected virtual void Error_AlreadyDeclared (Location loc, string name)
+               {
+                       Report.Error (128, loc,
+                               "A local variable named `{0}' is already defined in this scope", name);
+               }
+                                       
+               protected virtual void Error_AlreadyDeclaredTypeParameter (Location loc, string name)
+               {
+                       GenericMethod.Error_ParameterNameCollision (loc, name, "local variable");
+               }                                       
+
                public bool AddConstant (Expression type, string name, Expression value, Location l)
                {
                        if (AddVariable (type, name, l) == null)
@@ -1823,12 +1905,6 @@ namespace Mono.CSharp {
                        statements.Add (s);
                        flags |= Flags.BlockUsed;
                }
-               
-               public void InsertStatementAfterCurrent (Statement statement)
-               {
-                       statements.Insert (current_statement + 1, statement);
-                       flags |= Flags.BlockUsed;
-               }
 
                public bool Used {
                        get { return (flags & Flags.BlockUsed) != 0; }
@@ -1852,7 +1928,6 @@ namespace Mono.CSharp {
                        flags |= Flags.IsDestructor;
                }
 
-               int assignable_slots;
                public int AssignableSlots {
                        get {
                                if ((flags & Flags.VariablesInitialized) == 0)
@@ -1861,8 +1936,6 @@ namespace Mono.CSharp {
                        }
                }
 
-               protected ScopeInfo scope_info;
-
                public ScopeInfo ScopeInfo {
                        get { return scope_info; }
                }
@@ -2005,7 +2078,7 @@ namespace Mono.CSharp {
                {
                        string name;
 
-                       if ((variables != null) && (RootContext.WarningLevel >= 3)) {
+                       if ((variables != null) && (Report.WarningLevel >= 3)) {
                                foreach (DictionaryEntry de in variables){
                                        LocalInfo vi = (LocalInfo) de.Value;
 
@@ -2024,9 +2097,6 @@ namespace Mono.CSharp {
                        }
                }
 
-               bool unreachable_shown;
-               bool unreachable;
-
                private void CheckPossibleMistakenEmptyStatement (Statement s)
                {
                        Statement body;
@@ -2075,12 +2145,13 @@ namespace Mono.CSharp {
                        // from the beginning of the function.  The outer Resolve() that detected the unreachability is
                        // responsible for handling the situation.
                        //
-                       for (current_statement = 0; current_statement < statements.Count; current_statement++) {
-                               Statement s = (Statement) statements [current_statement];
+                       int statement_count = statements.Count;
+                       for (int ix = 0; ix < statement_count; ix++){
+                               Statement s = (Statement) statements [ix];
                                // Check possible empty statement (CS0642)
-                               if (RootContext.WarningLevel >= 3 &&
-                                       current_statement + 1 < statements.Count &&
-                                               statements [current_statement + 1] is Block)
+                               if (Report.WarningLevel >= 3 &&
+                                       ix + 1 < statement_count &&
+                                               statements [ix + 1] is Block)
                                        CheckPossibleMistakenEmptyStatement (s);
 
                                //
@@ -2108,15 +2179,18 @@ namespace Mono.CSharp {
                                //
 
                                if (!s.Resolve (ec)) {
+                                       if (ec.IsInProbingMode)
+                                               return false;
+
                                        ok = false;
-                                       statements [current_statement] = EmptyStatement.Value;
+                                       statements [ix] = EmptyStatement.Value;
                                        continue;
                                }
 
                                if (unreachable && !(s is LabeledStatement) && !(s is Block))
-                                       statements [current_statement] = EmptyStatement.Value;
+                                       statements [ix] = EmptyStatement.Value;
 
-                               num_statements = current_statement + 1;
+                               num_statements = ix + 1;
 
                                unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
                                if (unreachable && s is LabeledStatement)
@@ -2124,7 +2198,7 @@ namespace Mono.CSharp {
                        }
 
                        Report.Debug (4, "RESOLVE BLOCK DONE", StartLocation,
-                                     ec.CurrentBranching, statements.Count, num_statements);
+                                     ec.CurrentBranching, statement_count, num_statements);
 
                        if (!ok)
                                return false;
@@ -2141,7 +2215,7 @@ namespace Mono.CSharp {
                        if (this == Toplevel && !Toplevel.IsThisAssigned (ec) && !vector.IsUnreachable)
                                ok = false;
 
-                       if ((labels != null) && (RootContext.WarningLevel >= 2)) {
+                       if ((labels != null) && (Report.WarningLevel >= 2)) {
                                foreach (LabeledStatement label in labels.Values)
                                        if (!label.HasBeenReferenced)
                                                Report.Warning (164, 2, label.loc,
@@ -2154,8 +2228,7 @@ namespace Mono.CSharp {
                                flags |= Flags.HasRet;
 
                        if (ok && (errors == Report.Errors)) {
-                               if (RootContext.WarningLevel >= 3)
-                                       UsageWarning (vector);
+                               UsageWarning (vector);
                        }
 
                        return ok;
@@ -2231,24 +2304,10 @@ namespace Mono.CSharp {
 
                        clonectx.AddBlockMap (this, target);
 
-                       target.Toplevel = (ToplevelBlock) clonectx.LookupBlock (Toplevel);
+                       //target.Toplevel = (ToplevelBlock) clonectx.LookupBlock (Toplevel);
                        target.Explicit = (ExplicitBlock) clonectx.LookupBlock (Explicit);
                        if (Parent != null)
-                               target.Parent = clonectx.LookupBlock (Parent);
-                       
-                       target.statements = new ArrayList ();
-                       if (target.children != null){
-                               target.children = new ArrayList ();
-                               foreach (Block b in children){
-                                       Block newblock = (Block) b.Clone (clonectx);
-
-                                       target.children.Add (newblock);
-                               }
-                               
-                       }
-
-                       foreach (Statement s in statements)
-                               target.statements.Add (s.Clone (clonectx));
+                               target.Parent = clonectx.RemapBlockCopy (Parent);
 
                        if (variables != null){
                                target.variables = new Hashtable ();
@@ -2260,6 +2319,17 @@ namespace Mono.CSharp {
                                }
                        }
 
+                       target.statements = new ArrayList (statements.Count);
+                       foreach (Statement s in statements)
+                               target.statements.Add (s.Clone (clonectx));
+
+                       if (target.children != null){
+                               target.children = new ArrayList (children.Count);
+                               foreach (Block b in children){
+                                       target.children.Add (clonectx.LookupBlock (b));
+                               }
+                       }
+
                        //
                        // TODO: labels, switch_block, constants (?), anonymous_children
                        //
@@ -2344,6 +2414,8 @@ namespace Mono.CSharp {
                FlowBranchingToplevel top_level_branching;
                AnonymousContainer anonymous_container;
                RootScopeInfo root_scope;
+               Parameters parameters;
+               ToplevelParameterInfo[] parameter_info;
 
                public bool HasVarargs {
                        get { return (flags & Flags.HasVarargs) != 0; }
@@ -2357,7 +2429,6 @@ namespace Mono.CSharp {
                //
                // The parameters for the block.
                //
-               Parameters parameters;
                public Parameters Parameters {
                        get { return parameters; }
                }
@@ -2467,7 +2538,11 @@ namespace Mono.CSharp {
                        return true;
                }
 
-               ToplevelParameterInfo [] parameter_info;
+               public virtual Expression GetTransparentIdentifier (string name)
+               {
+                       return null;
+               }
+
                void ProcessParameters ()
                {
                        int n = parameters.Count;
@@ -2475,8 +2550,11 @@ namespace Mono.CSharp {
                        for (int i = 0; i < n; ++i) {
                                parameter_info [i] = new ToplevelParameterInfo (this, i);
 
-                               string name = parameters [i].Name;
+                               Parameter p = parameters [i];
+                               if (p == null)
+                                       continue;
 
+                               string name = p.Name;
                                LocalInfo vi = GetLocalInfo (name);
                                if (vi != null) {
                                        Report.SymbolRelatedToPreviousError (vi.Location, name);
@@ -2590,27 +2668,6 @@ namespace Mono.CSharp {
                        return null;
                }
 
-               //
-               // Whether the parameter named `name' is local to this block, 
-               // or false, if the parameter belongs to an encompassing block.
-               //
-               public bool IsLocalParameter (string name)
-               {
-                       return Parameters.GetParameterByName (name) != null;
-               }
-               
-               //
-               // Whether the `name' is a parameter reference
-               //
-               public bool IsParameterReference (string name)
-               {
-                       for (ToplevelBlock t = this; t != null; t = t.Container) {
-                               if (t.IsLocalParameter (name))
-                                       return true;
-                       }
-                       return false;
-               }
-
                LocalInfo this_variable = null;
 
                // <summary>
@@ -2719,7 +2776,7 @@ namespace Mono.CSharp {
                        Block block = new ExplicitBlock (this, StartLocation, EndLocation);
                        foreach (Statement stmt in statements)
                                block.AddStatement (stmt);
-                       statements = new ArrayList ();
+                       statements.Clear ();
                        statements.Add (new MoveNextStatement (iterator, block));
                }
 
@@ -2839,19 +2896,19 @@ namespace Mono.CSharp {
                        return true;
                }
 
-               public void Erorr_AlreadyOccurs (Type switchType, SwitchLabel collisionWith)
+               public void Erorr_AlreadyOccurs (Type switch_type, SwitchLabel collision_with)
                {
                        string label;
                        if (converted == null)
                                label = "default";
                        else if (converted == NullStringCase)
                                label = "null";
-                       else if (TypeManager.IsEnumType (switchType)) 
-                               label = TypeManager.CSharpEnumValue (switchType, converted);
+                       else if (TypeManager.IsEnumType (switch_type)) 
+                               label = TypeManager.CSharpEnumValue (switch_type, converted);
                        else
                                label = converted.ToString ();
                        
-                       Report.SymbolRelatedToPreviousError (collisionWith.loc, null);
+                       Report.SymbolRelatedToPreviousError (collision_with.loc, null);
                        Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label);
                }
 
@@ -3114,22 +3171,22 @@ namespace Mono.CSharp {
                // structure used to hold blocks of keys while calculating table switch
                class KeyBlock : IComparable
                {
-                       public KeyBlock (long _nFirst)
+                       public KeyBlock (long _first)
                        {
-                               nFirst = nLast = _nFirst;
+                               first = last = _first;
                        }
-                       public long nFirst;
-                       public long nLast;
-                       public ArrayList rgKeys = null;
+                       public long first;
+                       public long last;
+                       public ArrayList element_keys = null;
                        // how many items are in the bucket
                        public int Size = 1;
                        public int Length
                        {
-                               get { return (int) (nLast - nFirst + 1); }
+                               get { return (int) (last - first + 1); }
                        }
-                       public static long TotalLength (KeyBlock kbFirst, KeyBlock kbLast)
+                       public static long TotalLength (KeyBlock kb_first, KeyBlock kb_last)
                        {
-                               return kbLast.nLast - kbFirst.nFirst + 1;
+                               return kb_last.last - kb_first.first + 1;
                        }
                        public int CompareTo (object obj)
                        {
@@ -3137,7 +3194,7 @@ namespace Mono.CSharp {
                                int nLength = Length;
                                int nLengthOther = kb.Length;
                                if (nLengthOther == nLength)
-                                       return (int) (kb.nFirst - nFirst);
+                                       return (int) (kb.first - first);
                                return nLength - nLengthOther;
                        }
                }
@@ -3154,74 +3211,74 @@ namespace Mono.CSharp {
                /// <returns></returns>
                void TableSwitchEmit (EmitContext ec, LocalBuilder val)
                {
-                       int cElements = Elements.Count;
-                       object [] rgKeys = new object [cElements];
-                       Elements.Keys.CopyTo (rgKeys, 0);
-                       Array.Sort (rgKeys);
+                       int element_count = Elements.Count;
+                       object [] element_keys = new object [element_count];
+                       Elements.Keys.CopyTo (element_keys, 0);
+                       Array.Sort (element_keys);
 
                        // initialize the block list with one element per key
-                       ArrayList rgKeyBlocks = new ArrayList ();
-                       foreach (object key in rgKeys)
-                               rgKeyBlocks.Add (new KeyBlock (System.Convert.ToInt64 (key)));
+                       ArrayList key_blocks = new ArrayList ();
+                       foreach (object key in element_keys)
+                               key_blocks.Add (new KeyBlock (System.Convert.ToInt64 (key)));
 
-                       KeyBlock kbCurr;
+                       KeyBlock current_kb;
                        // iteratively merge the blocks while they are at least half full
                        // there's probably a really cool way to do this with a tree...
-                       while (rgKeyBlocks.Count > 1)
+                       while (key_blocks.Count > 1)
                        {
-                               ArrayList rgKeyBlocksNew = new ArrayList ();
-                               kbCurr = (KeyBlock) rgKeyBlocks [0];
-                               for (int ikb = 1; ikb < rgKeyBlocks.Count; ikb++)
+                               ArrayList key_blocks_new = new ArrayList ();
+                               current_kb = (KeyBlock) key_blocks [0];
+                               for (int ikb = 1; ikb < key_blocks.Count; ikb++)
                                {
-                                       KeyBlock kb = (KeyBlock) rgKeyBlocks [ikb];
-                                       if ((kbCurr.Size + kb.Size) * 2 >=  KeyBlock.TotalLength (kbCurr, kb))
+                                       KeyBlock kb = (KeyBlock) key_blocks [ikb];
+                                       if ((current_kb.Size + kb.Size) * 2 >=  KeyBlock.TotalLength (current_kb, kb))
                                        {
                                                // merge blocks
-                                               kbCurr.nLast = kb.nLast;
-                                               kbCurr.Size += kb.Size;
+                                               current_kb.last = kb.last;
+                                               current_kb.Size += kb.Size;
                                        }
                                        else
                                        {
                                                // start a new block
-                                               rgKeyBlocksNew.Add (kbCurr);
-                                               kbCurr = kb;
+                                               key_blocks_new.Add (current_kb);
+                                               current_kb = kb;
                                        }
                                }
-                               rgKeyBlocksNew.Add (kbCurr);
-                               if (rgKeyBlocks.Count == rgKeyBlocksNew.Count)
+                               key_blocks_new.Add (current_kb);
+                               if (key_blocks.Count == key_blocks_new.Count)
                                        break;
-                               rgKeyBlocks = rgKeyBlocksNew;
+                               key_blocks = key_blocks_new;
                        }
 
                        // initialize the key lists
-                       foreach (KeyBlock kb in rgKeyBlocks)
-                               kb.rgKeys = new ArrayList ();
+                       foreach (KeyBlock kb in key_blocks)
+                               kb.element_keys = new ArrayList ();
 
                        // fill the key lists
                        int iBlockCurr = 0;
-                       if (rgKeyBlocks.Count > 0) {
-                               kbCurr = (KeyBlock) rgKeyBlocks [0];
-                               foreach (object key in rgKeys)
+                       if (key_blocks.Count > 0) {
+                               current_kb = (KeyBlock) key_blocks [0];
+                               foreach (object key in element_keys)
                                {
-                                       bool fNextBlock = (key is UInt64) ? (ulong) key > (ulong) kbCurr.nLast :
-                                               System.Convert.ToInt64 (key) > kbCurr.nLast;
-                                       if (fNextBlock)
-                                               kbCurr = (KeyBlock) rgKeyBlocks [++iBlockCurr];
-                                       kbCurr.rgKeys.Add (key);
+                                       bool next_block = (key is UInt64) ? (ulong) key > (ulong) current_kb.last :
+                                               System.Convert.ToInt64 (key) > current_kb.last;
+                                       if (next_block)
+                                               current_kb = (KeyBlock) key_blocks [++iBlockCurr];
+                                       current_kb.element_keys.Add (key);
                                }
                        }
 
                        // sort the blocks so we can tackle the largest ones first
-                       rgKeyBlocks.Sort ();
+                       key_blocks.Sort ();
 
                        // okay now we can start...
                        ILGenerator ig = ec.ig;
-                       Label lblEnd = ig.DefineLabel ();       // at the end ;-)
-                       Label lblDefault = ig.DefineLabel ();
+                       Label lbl_end = ig.DefineLabel ();      // at the end ;-)
+                       Label lbl_default = ig.DefineLabel ();
 
-                       Type typeKeys = null;
-                       if (rgKeys.Length > 0)
-                               typeKeys = rgKeys [0].GetType ();       // used for conversions
+                       Type type_keys = null;
+                       if (element_keys.Length > 0)
+                               type_keys = element_keys [0].GetType ();        // used for conversions
 
                        Type compare_type;
                        
@@ -3230,13 +3287,13 @@ namespace Mono.CSharp {
                        else
                                compare_type = SwitchType;
                        
-                       for (int iBlock = rgKeyBlocks.Count - 1; iBlock >= 0; --iBlock)
+                       for (int iBlock = key_blocks.Count - 1; iBlock >= 0; --iBlock)
                        {
-                               KeyBlock kb = ((KeyBlock) rgKeyBlocks [iBlock]);
-                               lblDefault = (iBlock == 0) ? DefaultTarget : ig.DefineLabel ();
+                               KeyBlock kb = ((KeyBlock) key_blocks [iBlock]);
+                               lbl_default = (iBlock == 0) ? DefaultTarget : ig.DefineLabel ();
                                if (kb.Length <= 2)
                                {
-                                       foreach (object key in kb.rgKeys)
+                                       foreach (object key in kb.element_keys)
                                        {
                                                ig.Emit (OpCodes.Ldloc, val);
                                                EmitObjectInteger (ig, key);
@@ -3255,17 +3312,17 @@ namespace Mono.CSharp {
 
                                                // check block range (could be > 2^31)
                                                ig.Emit (OpCodes.Ldloc, val);
-                                               EmitObjectInteger (ig, System.Convert.ChangeType (kb.nFirst, typeKeys));
-                                               ig.Emit (OpCodes.Blt, lblDefault);
+                                               EmitObjectInteger (ig, System.Convert.ChangeType (kb.first, type_keys));
+                                               ig.Emit (OpCodes.Blt, lbl_default);
                                                ig.Emit (OpCodes.Ldloc, val);
-                                               EmitObjectInteger (ig, System.Convert.ChangeType (kb.nLast, typeKeys));
-                                               ig.Emit (OpCodes.Bgt, lblDefault);
+                                               EmitObjectInteger (ig, System.Convert.ChangeType (kb.last, type_keys));
+                                               ig.Emit (OpCodes.Bgt, lbl_default);
 
                                                // normalize range
                                                ig.Emit (OpCodes.Ldloc, val);
-                                               if (kb.nFirst != 0)
+                                               if (kb.first != 0)
                                                {
-                                                       EmitObjectInteger (ig, System.Convert.ChangeType (kb.nFirst, typeKeys));
+                                                       EmitObjectInteger (ig, System.Convert.ChangeType (kb.first, type_keys));
                                                        ig.Emit (OpCodes.Sub);
                                                }
                                                ig.Emit (OpCodes.Conv_I4);      // assumes < 2^31 labels!
@@ -3274,15 +3331,15 @@ namespace Mono.CSharp {
                                        {
                                                // normalize range
                                                ig.Emit (OpCodes.Ldloc, val);
-                                               int nFirst = (int) kb.nFirst;
-                                               if (nFirst > 0)
+                                               int first = (int) kb.first;
+                                               if (first > 0)
                                                {
-                                                       IntConstant.EmitInt (ig, nFirst);
+                                                       IntConstant.EmitInt (ig, first);
                                                        ig.Emit (OpCodes.Sub);
                                                }
-                                               else if (nFirst < 0)
+                                               else if (first < 0)
                                                {
-                                                       IntConstant.EmitInt (ig, -nFirst);
+                                                       IntConstant.EmitInt (ig, -first);
                                                        ig.Emit (OpCodes.Add);
                                                }
                                        }
@@ -3290,26 +3347,26 @@ namespace Mono.CSharp {
                                        // first, build the list of labels for the switch
                                        int iKey = 0;
                                        int cJumps = kb.Length;
-                                       Label [] rgLabels = new Label [cJumps];
+                                       Label [] switch_labels = new Label [cJumps];
                                        for (int iJump = 0; iJump < cJumps; iJump++)
                                        {
-                                               object key = kb.rgKeys [iKey];
-                                               if (System.Convert.ToInt64 (key) == kb.nFirst + iJump)
+                                               object key = kb.element_keys [iKey];
+                                               if (System.Convert.ToInt64 (key) == kb.first + iJump)
                                                {
                                                        SwitchLabel sl = (SwitchLabel) Elements [key];
-                                                       rgLabels [iJump] = sl.GetILLabel (ec);
+                                                       switch_labels [iJump] = sl.GetILLabel (ec);
                                                        iKey++;
                                                }
                                                else
-                                                       rgLabels [iJump] = lblDefault;
+                                                       switch_labels [iJump] = lbl_default;
                                        }
                                        // emit the switch opcode
-                                       ig.Emit (OpCodes.Switch, rgLabels);
+                                       ig.Emit (OpCodes.Switch, switch_labels);
                                }
 
                                // mark the default for this block
                                if (iBlock != 0)
-                                       ig.MarkLabel (lblDefault);
+                                       ig.MarkLabel (lbl_default);
                        }
 
                        // TODO: find the default case and emit it here,
@@ -3317,16 +3374,16 @@ namespace Mono.CSharp {
                        //       make sure to mark other labels in the default section
 
                        // the last default just goes to the end
-                       ig.Emit (OpCodes.Br, lblDefault);
+                       ig.Emit (OpCodes.Br, lbl_default);
 
                        // now emit the code for the sections
-                       bool fFoundDefault = false;
-                       bool fFoundNull = false;
+                       bool found_default = false;
+                       bool found_null = false;
                        foreach (SwitchSection ss in Sections)
                        {
                                foreach (SwitchLabel sl in ss.Labels)
                                        if (sl.Converted == SwitchLabel.NullStringCase)
-                                               fFoundNull = true;
+                                               found_null = true;
                        }
 
                        foreach (SwitchSection ss in Sections)
@@ -3338,23 +3395,23 @@ namespace Mono.CSharp {
                                        if (sl.Converted == SwitchLabel.NullStringCase)
                                                ig.MarkLabel (null_target);
                                        else if (sl.Label == null) {
-                                               ig.MarkLabel (lblDefault);
-                                               fFoundDefault = true;
-                                               if (!fFoundNull)
+                                               ig.MarkLabel (lbl_default);
+                                               found_default = true;
+                                               if (!found_null)
                                                        ig.MarkLabel (null_target);
                                        }
                                }
                                ss.Block.Emit (ec);
                        }
                        
-                       if (!fFoundDefault) {
-                               ig.MarkLabel (lblDefault);
-                               if (HaveUnwrap && !fFoundNull) {
+                       if (!found_default) {
+                               ig.MarkLabel (lbl_default);
+                               if (HaveUnwrap && !found_null) {
                                        ig.MarkLabel (null_target);
                                }
                        }
                        
-                       ig.MarkLabel (lblEnd);
+                       ig.MarkLabel (lbl_end);
                }
                //
                // This simple emit switch works, but does not take advantage of the
@@ -3496,7 +3553,7 @@ namespace Mono.CSharp {
                        SwitchType = new_expr.Type;
 
                        if (RootContext.Version == LanguageVersion.ISO_1 && SwitchType == TypeManager.bool_type) {
-                               Report.FeatureIsNotISO1 (loc, "switch expression of boolean type");
+                               Report.FeatureIsNotAvailable (loc, "switch expression of boolean type");
                                return false;
                        }
 
@@ -4017,6 +4074,17 @@ namespace Mono.CSharp {
                                                ec, array_ptr, vi.VariableType, loc);
                                        if (converted == null)
                                                return false;
+                                       
+                                       //
+                                       // fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0])
+                                       //
+                                       converted = new Conditional (new Binary (Binary.Operator.LogicalOr,
+                                               new Binary (Binary.Operator.Equality, e, new NullConstant (loc)),
+                                               new Binary (Binary.Operator.Equality, new MemberAccess (e, "Length"), new IntConstant (0, loc))),
+                                                       NullPointer.Null,
+                                                       converted);
+
+                                       converted = converted.Resolve (ec);                                     
 
                                        data [i] = new ExpressionEmitter (converted, vi);
                                        i++;
@@ -4034,22 +4102,10 @@ namespace Mono.CSharp {
                                }
 
                                // Case 4: fixed buffer
-                               FieldExpr fe = e as FieldExpr;
-                               if (fe != null) {
-                                       IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
-                                       if (ff != null) {
-                                               Expression fixed_buffer_ptr = new FixedBufferPtr (fe, ff.ElementType, loc);
-                                       
-                                               Expression converted = Convert.ImplicitConversionRequired (
-                                                       ec, fixed_buffer_ptr, vi.VariableType, loc);
-                                               if (converted == null)
-                                                       return false;
-
-                                               data [i] = new ExpressionEmitter (converted, vi);
-                                               i++;
-
-                                               continue;
-                                       }
+                               FixedBufferPtr fixed_buffer_ptr = e as FixedBufferPtr;
+                               if (fixed_buffer_ptr != null) {
+                                       data [i++] = new ExpressionEmitter (fixed_buffer_ptr, vi);
+                                       continue;
                                }
 
                                //
@@ -4098,9 +4154,15 @@ namespace Mono.CSharp {
                        Fixed target = (Fixed) t;
 
                        target.type = type.Clone (clonectx);
-                       target.declarators = new ArrayList ();
-                       foreach (LocalInfo var in declarators)
-                               target.declarators.Add (clonectx.LookupVariable (var));
+                       target.declarators = new ArrayList (declarators.Count);
+                       foreach (Pair p in declarators) {
+                               LocalInfo vi = (LocalInfo) p.First;
+                               Expression e = (Expression) p.Second;
+
+                               target.declarators.Add (
+                                       new Pair (clonectx.LookupVariable (vi), e.Clone (clonectx)));                           
+                       }
+                       
                        target.statement = statement.Clone (clonectx);
                }
        }
@@ -4199,9 +4261,11 @@ namespace Mono.CSharp {
                {
                        Catch target = (Catch) t;
 
-                       target.type_expr = type_expr.Clone (clonectx);
+                       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.VarBlock = clonectx.LookupBlock (VarBlock);
                }
        }
 
@@ -4243,7 +4307,7 @@ namespace Mono.CSharp {
 
                        Report.Debug (1, "START OF CATCH BLOCKS", vector);
 
-                       Type[] prevCatches = new Type [Specific.Count];
+                       Type[] prev_catches = new Type [Specific.Count];
                        int last_index = 0;
                        foreach (Catch c in Specific){
                                ec.CurrentBranching.CreateSibling (
@@ -4262,15 +4326,15 @@ namespace Mono.CSharp {
                                if (!c.Resolve (ec))
                                        return false;
 
-                               Type resolvedType = c.CatchType;
+                               Type resolved_type = c.CatchType;
                                for (int ii = 0; ii < last_index; ++ii) {
-                                       if (resolvedType == prevCatches [ii] || resolvedType.IsSubclassOf (prevCatches [ii])) {
-                                               Report.Error (160, c.loc, "A previous catch clause already catches all exceptions of this or a super type `{0}'", prevCatches [ii].FullName);
+                                       if (resolved_type == prev_catches [ii] || resolved_type.IsSubclassOf (prev_catches [ii])) {
+                                               Report.Error (160, c.loc, "A previous catch clause already catches all exceptions of this or a super type `{0}'", prev_catches [ii].FullName);
                                                return false;
                                        }
                                }
 
-                               prevCatches [last_index++] = resolvedType;
+                               prev_catches [last_index++] = resolved_type;
                                need_exc_block = true;
                        }
 
@@ -4388,7 +4452,7 @@ namespace Mono.CSharp {
                Type expr_type;
                Expression [] resolved_vars;
                Expression [] converted_vars;
-               ExpressionStatement [] assign;
+               Expression [] assign;
                TemporaryVariable local_copy;
                
                public Using (object expression_or_block, Statement stmt, Location l)
@@ -4403,97 +4467,52 @@ namespace Mono.CSharp {
                //
                bool ResolveLocalVariableDecls (EmitContext ec)
                {
-                       int i = 0;
-
-                       TypeExpr texpr = null;
-                       
-                       if (expr is VarExpr) {
-                               Expression e = ((Expression)((DictionaryEntry)var_list[0]).Value).Resolve (ec);
-                               if (e == null || e.Type == null)
-                                       return false;
-                               texpr = new TypeExpression (e.Type, loc);
-                       }
-                       else
-                               texpr = expr.ResolveAsTypeTerminal (ec, false);
-
-                       if (texpr == null)
-                               return false;
-
-                       expr_type = texpr.Type;
-
-                       //
-                       // The type must be an IDisposable or an implicit conversion
-                       // must exist.
-                       //
-                       converted_vars = new Expression [var_list.Count];
-                       resolved_vars = new Expression [var_list.Count];
-                       assign = new ExpressionStatement [var_list.Count];
+                       resolved_vars = new Expression[var_list.Count];
+                       assign = new Expression [var_list.Count];
+                       converted_vars = new Expression[var_list.Count];
 
-                       bool need_conv = !TypeManager.ImplementsInterface (
-                               expr_type, TypeManager.idisposable_type);
-
-                       foreach (DictionaryEntry e in var_list){
+                       for (int i = 0; i < assign.Length; ++i) {
+                               DictionaryEntry e = (DictionaryEntry) var_list [i];
                                Expression var = (Expression) e.Key;
-                               
-                               if (expr is VarExpr) {
-                                       LocalVariableReference l = var as LocalVariableReference;
-                                       ((LocalInfo)l.Block.Variables[l.Name]).VariableType = expr_type;
-                                       ((VarExpr)expr).Handled = true;
-                               }
+                               Expression new_expr = (Expression) e.Value;
 
-                               var = var.ResolveLValue (ec, new EmptyExpression (), loc);
-                               if (var == null)
+                               Expression a = new Assign (var, new_expr, loc);
+                               a = a.Resolve (ec);
+                               if (a == null)
                                        return false;
 
                                resolved_vars [i] = var;
+                               assign [i] = a;
 
-                               if (!need_conv) {
-                                       i++;
+                               if (TypeManager.ImplementsInterface (a.Type, TypeManager.idisposable_type)) {
+                                       converted_vars [i] = var;
                                        continue;
                                }
 
-                               converted_vars [i] = Convert.ImplicitConversion (
-                                       ec, var, TypeManager.idisposable_type, loc);
-
-                               if (converted_vars [i] == null) {
-                                       Error_IsNotConvertibleToIDisposable ();
+                               a = Convert.ImplicitConversionStandard (ec, a, TypeManager.idisposable_type, var.Location);
+                               if (a == null) {
+                                       Error_IsNotConvertibleToIDisposable (var);
                                        return false;
                                }
 
-                               i++;
-                       }
-
-                       i = 0;
-                       foreach (DictionaryEntry e in var_list){
-                               Expression var = resolved_vars [i];
-                               Expression new_expr = (Expression) e.Value;
-                               Expression a;
-
-                               a = new Assign (var, new_expr, loc);
-                               a = a.Resolve (ec);
-                               if (a == null)
-                                       return false;
-
-                               if (!need_conv)
-                                       converted_vars [i] = var;
-                               assign [i] = (ExpressionStatement) a;
-                               i++;
+                               converted_vars [i] = a;
                        }
 
                        return true;
                }
 
-               void Error_IsNotConvertibleToIDisposable ()
+               static void Error_IsNotConvertibleToIDisposable (Expression expr)
                {
-                       Report.Error (1674, loc, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
-                               TypeManager.CSharpName (expr_type));
+                       Report.SymbolRelatedToPreviousError (expr.Type);
+                       Report.Error (1674, expr.Location, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
+                               expr.GetSignatureForError ());
                }
 
                bool ResolveExpression (EmitContext ec)
                {
                        if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)){
                                if (Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) {
-                                       Error_IsNotConvertibleToIDisposable ();
+                                       Error_IsNotConvertibleToIDisposable (expr);
                                        return false;
                                }
                        }
@@ -4513,7 +4532,14 @@ namespace Mono.CSharp {
                        int i = 0;
 
                        for (i = 0; i < assign.Length; i++) {
-                               assign [i].EmitStatement (ec);
+                               ExpressionStatement es = assign [i] as ExpressionStatement;
+
+                               if (es != null)
+                                       es.EmitStatement (ec);
+                               else {
+                                       assign [i].Emit (ec);
+                                       ig.Emit (OpCodes.Pop);
+                               }
 
                                if (emit_finally)
                                        ig.BeginExceptionBlock ();
@@ -4737,58 +4763,11 @@ namespace Mono.CSharp {
                        if (expr == null)
                                return false;
 
-                       if (type is VarExpr) {
-                               Type element_type = null;
-                               if (TypeManager.HasElementType (expr.Type))
-                                       element_type = TypeManager.GetElementType (expr.Type);
-                               else {
-                                       MethodGroupExpr mg = Expression.MemberLookup (
-                                               ec.ContainerType, expr.Type, "GetEnumerator", MemberTypes.Method,
-                                               Expression.AllBindingFlags, loc) as MethodGroupExpr;
-                                       
-                                       if (mg == null)
-                                                       return false;
-                                       
-                                       MethodInfo get_enumerator = null;
-                                       foreach (MethodInfo mi in mg.Methods) {
-                                               if (TypeManager.GetParameterData (mi).Count != 0)
-                                                       continue;
-                                               if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
-                                                       continue;
-                                               if (CollectionForeach.IsOverride (mi))
-                                                       continue;
-                                               get_enumerator = mi;
-                                       }
-                                       
-                                       if (get_enumerator == null)
-                                               return false;
-                                       
-                                       PropertyInfo pi = TypeManager.GetProperty (get_enumerator.ReturnType, "Current");
-                                       
-                                       if (pi == null)
-                                               return false;
-                                               
-                                       element_type = pi.PropertyType;
-                               }
-
-                               type = new TypeLookupExpression (element_type.AssemblyQualifiedName);
-                
-                               LocalVariableReference lv = variable as LocalVariableReference;
-                               ((LocalInfo)lv.Block.Variables[lv.Name]).VariableType = element_type;
-                       }
-
-                       Constant c = expr as Constant;
-                       if (c != null && c.GetValue () == null) {
+                       if (expr.Type == TypeManager.null_type) {
                                Report.Error (186, loc, "Use of null is not valid in this context");
                                return false;
                        }
 
-                       TypeExpr texpr = type.ResolveAsTypeTerminal (ec, false);
-                       if (texpr == null)
-                               return false;
-
-                       Type var_type = texpr.Type;
-
                        if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
                                Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
                                        expr.ExprClassName);
@@ -4809,13 +4788,12 @@ namespace Mono.CSharp {
                        }
 
                        if (expr.Type.IsArray) {
-                               array = new ArrayForeach (var_type, variable, expr, statement, loc);
+                               array = new ArrayForeach (type, variable, expr, statement, loc);
                                return array.Resolve (ec);
-                       } else {
-                               collection = new CollectionForeach (
-                                       var_type, variable, expr, statement, loc);
-                               return collection.Resolve (ec);
                        }
+                       
+                       collection = new CollectionForeach (type, variable, expr, statement, loc);
+                       return collection.Resolve (ec);
                }
 
                protected override void DoEmit (EmitContext ec)
@@ -4863,7 +4841,7 @@ namespace Mono.CSharp {
                        Expression variable, expr, conv;
                        Statement statement;
                        Type array_type;
-                       Type var_type;
+                       Expression var_type;
                        TemporaryVariable[] lengths;
                        ArrayCounter[] counter;
                        int rank;
@@ -4871,7 +4849,7 @@ namespace Mono.CSharp {
                        TemporaryVariable copy;
                        Expression access;
 
-                       public ArrayForeach (Type var_type, Expression var,
+                       public ArrayForeach (Expression var_type, Expression var,
                                             Expression expr, Statement stmt, Location l)
                        {
                                this.var_type = var_type;
@@ -4907,7 +4885,17 @@ namespace Mono.CSharp {
                                if (access == null)
                                        return false;
 
-                               conv = Convert.ExplicitConversion (ec, access, var_type, loc);
+                               VarExpr ve = var_type as VarExpr;
+                               if (ve != null) {
+                                       // Infer implicitly typed local variable from foreach array type
+                                       var_type = new TypeExpression (access.Type, ve.Location);
+                               }
+
+                               var_type = var_type.ResolveAsTypeTerminal (ec, false);
+                               if (var_type == null)
+                                       return false;
+
+                               conv = Convert.ExplicitConversion (ec, access, var_type.Type, loc);
                                if (conv == null)
                                        return false;
 
@@ -4989,11 +4977,12 @@ namespace Mono.CSharp {
                        MethodGroupExpr get_enumerator;
                        PropertyExpr get_current;
                        MethodInfo move_next;
-                       Type var_type, enumerator_type;
+                       Expression var_type;
+                       Type enumerator_type;
                        bool is_disposable;
                        bool enumerator_found;
 
-                       public CollectionForeach (Type var_type, Expression var,
+                       public CollectionForeach (Expression var_type, Expression var,
                                                  Expression expr, Statement stmt, Location l)
                        {
                                this.var_type = var_type;
@@ -5161,7 +5150,7 @@ namespace Mono.CSharp {
                                        TypeManager.CSharpName (expr.Type));
                        }
 
-                       public static bool IsOverride (MethodInfo m)
+                       bool IsOverride (MethodInfo m)
                        {
                                m = (MethodInfo) TypeManager.DropGenericMethodArguments (m);
 
@@ -5241,7 +5230,7 @@ namespace Mono.CSharp {
                                        get_current = tmp_get_cur;
                                        enumerator_type = tmp_enumerator_type;
                                        MethodInfo[] mi = new MethodInfo[] { (MethodInfo) result };
-                                       get_enumerator = new MethodGroupExpr (mi, loc);
+                                       get_enumerator = new MethodGroupExpr (mi, enumerator_type, loc);
 
                                        if (t != expr.Type) {
                                                expr = Convert.ExplicitConversion (
@@ -5293,10 +5282,20 @@ namespace Mono.CSharp {
                                        return false;
                                }
 
+                               VarExpr ve = var_type as VarExpr;
+                               if (ve != null) {
+                                       // Infer implicitly typed local variable from foreach enumerable type
+                                       var_type = new TypeExpression (get_current.PropertyInfo.PropertyType, var_type.Location);
+                               }
+
+                               var_type = var_type.ResolveAsTypeTerminal (ec, false);
+                               if (var_type == null)
+                                       return false;
+                                                               
                                enumerator = new TemporaryVariable (enumerator_type, loc);
                                enumerator.Resolve (ec);
 
-                               init = new Invocation (get_enumerator, new ArrayList ());
+                               init = new Invocation (get_enumerator, null);
                                init = init.Resolve (ec);
                                if (init == null)
                                        return false;
@@ -5304,16 +5303,16 @@ namespace Mono.CSharp {
                                Expression move_next_expr;
                                {
                                        MemberInfo[] mi = new MemberInfo[] { move_next };
-                                       MethodGroupExpr mg = new MethodGroupExpr (mi, loc);
+                                       MethodGroupExpr mg = new MethodGroupExpr (mi, var_type.Type, loc);
                                        mg.InstanceExpression = enumerator;
 
-                                       move_next_expr = new Invocation (mg, new ArrayList ());
+                                       move_next_expr = new Invocation (mg, null);
                                }
 
                                get_current.InstanceExpression = enumerator;
 
                                Statement block = new CollectionForeachStatement (
-                                       var_type, variable, get_current, statement, loc);
+                                       var_type.Type, variable, get_current, statement, loc);
 
                                loop = new While (move_next_expr, block, loc);