2008-10-14 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / statement.cs
index 7849cb1450530c137c99b884a429f3747672c239..f3480c06ed1ee4676fcb784fa98a9685e2f05c1f 100644 (file)
@@ -1149,20 +1149,12 @@ namespace Mono.CSharp {
                                return ec.CurrentBranching.CheckRethrow (loc);
                        }
 
-                       expr = expr.Resolve (ec);
+                       expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
                        ec.CurrentBranching.CurrentUsageVector.Goto ();
 
                        if (expr == null)
                                return false;
 
-                       ExprClass eclass = expr.eclass;
-
-                       if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
-                             eclass == ExprClass.Value || eclass == ExprClass.IndexerAccess)) {
-                               expr.Error_UnexpectedKind (ec.DeclContainer, "value, variable, property or indexer access ", loc);
-                               return false;
-                       }
-
                        Type t = expr.Type;
 
                        if ((t != TypeManager.exception_type) &&
@@ -1397,11 +1389,6 @@ namespace Mono.CSharp {
                        if (TypeManager.IsGenericParameter (VariableType))
                                return true;
 
-                       if (VariableType == TypeManager.void_type) {
-                               Expression.Error_VoidInvalidInTheContext (Location);
-                               return false;
-                       }
-
                        if (VariableType.IsAbstract && VariableType.IsSealed) {
                                FieldBase.Error_VariableOfStaticClass (Location, Name, VariableType);
                                return false;
@@ -1455,12 +1442,12 @@ namespace Mono.CSharp {
                                throw new InternalErrorException ("Variable is not readonly");
 
                        switch (ro_context) {
-                               case ReadOnlyContext.Fixed:
-                                       return "fixed variable";
-                               case ReadOnlyContext.Foreach:
-                                       return "foreach iteration variable";
-                               case ReadOnlyContext.Using:
-                                       return "using variable";
+                       case ReadOnlyContext.Fixed:
+                               return "fixed variable";
+                       case ReadOnlyContext.Foreach:
+                               return "foreach iteration variable";
+                       case ReadOnlyContext.Using:
+                               return "using variable";
                        }
                        throw new NotImplementedException ();
                }
@@ -1520,7 +1507,7 @@ namespace Mono.CSharp {
        /// </remarks>
        public class Block : Statement {
                public Block    Parent;
-               public readonly Location  StartLocation;
+               public Location StartLocation;
                public Location EndLocation = Location.Null;
 
                public ExplicitBlock Explicit;
@@ -1541,7 +1528,7 @@ namespace Mono.CSharp {
 
                public bool Unchecked {
                        get { return (flags & Flags.Unchecked) != 0; }
-                       set { flags |= Flags.Unchecked; }
+                       set { flags = value ? flags | Flags.Unchecked : flags & ~Flags.Unchecked; }
                }
 
                public bool Unsafe {
@@ -2086,8 +2073,8 @@ namespace Mono.CSharp {
 
                                e = ce.ConvertImplicitly (variable_type);
                                if (e == null) {
-                                       if (!variable_type.IsValueType && variable_type != TypeManager.string_type && !ce.IsDefaultValue)
-                                               Const.Error_ConstantCanBeInitializedWithNullOnly (vi.Location, vi.Name);
+                                       if (TypeManager.IsReferenceType (variable_type))
+                                               Const.Error_ConstantCanBeInitializedWithNullOnly (variable_type, vi.Location, vi.Name);
                                        else
                                                ce.Error_ValueCannotBeConverted (ec, vi.Location, variable_type, false);
                                        continue;
@@ -2223,7 +2210,7 @@ namespace Mono.CSharp {
                                // Check possible empty statement (CS0642)
                                if (Report.WarningLevel >= 3 &&
                                        ix + 1 < statement_count &&
-                                               statements [ix + 1] is Block)
+                                               statements [ix + 1] is ExplicitBlock)
                                        CheckPossibleMistakenEmptyStatement (s);
 
                                //
@@ -2329,11 +2316,10 @@ namespace Mono.CSharp {
                        if (scope_initializers != null) {
                                SymbolWriter.OpenCompilerGeneratedBlock (ec.ig);
 
-                               bool omit_debug_info = ec.OmitDebuggingInfo;
-                               ec.OmitDebuggingInfo = true;
-                               foreach (StatementExpression s in scope_initializers)
-                                       s.Emit (ec);
-                               ec.OmitDebuggingInfo = omit_debug_info;
+                               using (ec.Set (EmitContext.Flags.OmitDebuggingInfo)) {
+                                       foreach (StatementExpression s in scope_initializers)
+                                               s.Emit (ec);
+                               }
 
                                SymbolWriter.CloseCompilerGeneratedBlock (ec.ig);
                        }
@@ -2360,6 +2346,11 @@ namespace Mono.CSharp {
                {
                        MutateVariables (storey);
 
+                       if (scope_initializers != null) {
+                               foreach (Statement s in scope_initializers)
+                                       s.MutateHoistedGenericType (storey);
+                       }
+
                        foreach (Statement s in statements)
                                s.MutateHoistedGenericType (storey);
                }
@@ -2523,21 +2514,13 @@ namespace Mono.CSharp {
 
                                am_storey.DefineType ();
                                am_storey.ResolveType ();                               
-                               am_storey.DefineMembers ();
+                               am_storey.Define ();
                                am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey);
                        }
 
                        base.EmitMeta (ec);
                }
 
-               protected override void EmitSymbolInfo (EmitContext ec)
-               {
-                       if (am_storey != null)
-                               SymbolWriter.DefineScopeVariable (am_storey.ID);
-
-                       base.EmitSymbolInfo (ec);
-               }
-
                internal IKnownVariable GetKnownVariable (string name)
                {
                        return known_variables == null ? null : (IKnownVariable) known_variables [name];
@@ -2587,6 +2570,11 @@ namespace Mono.CSharp {
                public Parameter Parameter {
                        get { return Block.Parameters [Index]; }
                }
+
+               public Type ParameterType {
+                       get { return Block.Parameters.Types [Index]; }
+               }
+
                public Location Location {
                        get { return Parameter.Location; }
                }
@@ -2668,7 +2656,7 @@ namespace Mono.CSharp {
                        if (parent != null)
                                parent.AddAnonymousChild (this);
 
-                       if (!this.parameters.Empty)
+                       if (!this.parameters.IsEmpty)
                                ProcessParameters ();
                }
 
@@ -2757,7 +2745,10 @@ namespace Mono.CSharp {
 
                public override Expression CreateExpressionTree (EmitContext ec)
                {
-                       return ((Statement) statements [0]).CreateExpressionTree (ec);
+                       if (statements.Count == 1)
+                               return ((Statement) statements [0]).CreateExpressionTree (ec);
+
+                       return base.CreateExpressionTree (ec);
                }
 
                //
@@ -2866,7 +2857,7 @@ namespace Mono.CSharp {
                        int offset = Parent == null ? 0 : Parent.AssignableSlots;
 
                        for (int i = 0; i < orig_count; ++i) {
-                               Parameter.Modifier mod = parameters.ParameterModifier (i);
+                               Parameter.Modifier mod = parameters.FixedParameters [i].ModFlags;
 
                                if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT)
                                        continue;
@@ -2918,6 +2909,15 @@ namespace Mono.CSharp {
                        base.EmitMeta (ec);
                }
 
+               protected override void EmitSymbolInfo (EmitContext ec)
+               {
+                       AnonymousExpression ae = ec.CurrentAnonymousMethod;
+                       if ((ae != null) && (ae.Storey != null))
+                               SymbolWriter.DefineScopeVariable (ae.Storey.ID);
+
+                       base.EmitSymbolInfo (ec);
+               }
+
                public override void Emit (EmitContext ec)
                {
                        base.Emit (ec);
@@ -3022,8 +3022,6 @@ namespace Mono.CSharp {
                                label = "default";
                        else if (converted == NullStringCase)
                                label = "null";
-                       else if (TypeManager.IsEnumType (switch_type)) 
-                               label = TypeManager.CSharpEnumValue (switch_type, converted);
                        else
                                label = converted.ToString ();
                        
@@ -3671,7 +3669,7 @@ namespace Mono.CSharp {
 #endif
                        Field field = new Field (ec.TypeContainer, string_dictionary_type,
                                Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
-                               CompilerGeneratedClass.MakeName (null, "f", "switch$map", unique_counter++), null, loc);
+                               new MemberName (CompilerGeneratedClass.MakeName (null, "f", "switch$map", unique_counter++), loc), null);
                        if (!field.Define ())
                                return;
                        ec.TypeContainer.PartialContainer.AddField (field);
@@ -4387,43 +4385,6 @@ namespace Mono.CSharp {
                                        Report.Error (254, loc, "The right hand side of a fixed statement assignment may not be a cast expression");
                                        return false;
                                }
-                               
-                               //
-                               // Case 1: & object.
-                               //
-                               if (e is Unary && ((Unary) e).Oper == Unary.Operator.AddressOf){
-                                       Expression child = ((Unary) e).Expr;
-
-                                       if (child is ParameterReference || child is LocalVariableReference){
-                                               Report.Error (
-                                                       213, loc, 
-                                                       "No need to use fixed statement for parameters or " +
-                                                       "local variable declarations (address is already " +
-                                                       "fixed)");
-                                               return false;
-                                       }
-
-                                       ec.InFixedInitializer = true;
-                                       e = e.Resolve (ec);
-                                       ec.InFixedInitializer = false;
-                                       if (e == null)
-                                               return false;
-
-                                       child = ((Unary) e).Expr;
-                                       
-                                       if (!TypeManager.VerifyUnManaged (child.Type, loc))
-                                               return false;
-
-                                       if (!Convert.ImplicitConversionExists (ec, e, expr_type)) {
-                                               e.Error_ValueCannotBeConverted (ec, e.Location, expr_type, false);
-                                               return false;
-                                       }
-
-                                       data [i] = new ExpressionEmitter (e, vi);
-                                       i++;
-
-                                       continue;
-                               }
 
                                ec.InFixedInitializer = true;
                                e = e.Resolve (ec);
@@ -4460,7 +4421,7 @@ namespace Mono.CSharp {
                                        converted = new Conditional (new Binary (Binary.Operator.LogicalOr,
                                                new Binary (Binary.Operator.Equality, e, new NullLiteral (loc)),
                                                new Binary (Binary.Operator.Equality, new MemberAccess (e, "Length"), new IntConstant (0, loc))),
-                                                       NullPointer.Null,
+                                                       new NullPointer (loc),
                                                        converted);
 
                                        converted = converted.Resolve (ec);                                     
@@ -4481,17 +4442,26 @@ namespace Mono.CSharp {
                                }
 
                                // Case 4: fixed buffer
-                               FixedBufferPtr fixed_buffer_ptr = e as FixedBufferPtr;
-                               if (fixed_buffer_ptr != null) {
-                                       data [i++] = new ExpressionEmitter (fixed_buffer_ptr, vi);
+                               if (e is FixedBufferPtr) {
+                                       data [i++] = new ExpressionEmitter (e, vi);
                                        continue;
                                }
 
                                //
-                               // For other cases, report an error
+                               // Case 1: & object.
                                //
-                               Convert.ImplicitConversionRequired (ec, e, vi.VariableType, loc);
-                               return false;
+                               Unary u = e as Unary;
+                               if (u != null && u.Oper == Unary.Operator.AddressOf) {
+                                       IVariableReference vr = u.Expr as IVariableReference;
+                                       if (vr == null || !vr.IsFixed) {
+                                               data [i] = new ExpressionEmitter (e, vi);
+                                       }
+                               }
+
+                               if (data [i++] == null)
+                                       Report.Error (213, vi.Location, "You cannot use the fixed statement to take the address of an already fixed expression");
+
+                               e = Convert.ImplicitConversionRequired (ec, e, expr_type, loc);
                        }
 
                        ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
@@ -5121,108 +5091,56 @@ namespace Mono.CSharp {
        ///   Implementation of the foreach C# statement
        /// </summary>
        public class Foreach : Statement {
-               Expression type;
-               Expression variable;
-               Expression expr;
-               Statement statement;
-               
-               public Foreach (Expression type, LocalVariableReference var, Expression expr,
-                               Statement stmt, Location l)
-               {
-                       this.type = type;
-                       this.variable = var;
-                       this.expr = expr;
-                       statement = stmt;
-                       loc = l;
-               }
-
-               public Statement Statement {
-                       get { return statement; }
-               }
-
-               public override bool Resolve (EmitContext ec)
-               {
-                       expr = expr.Resolve (ec);
-                       if (expr == null)
-                               return false;
-
-                       if (expr.IsNull) {
-                               Report.Error (186, loc, "Use of null is not valid in this context");
-                               return false;
-                       }
-
-                       if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
-                               Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
-                                       expr.ExprClassName);
-                               return false;
-                       }
-
-                       if (expr.Type.IsArray) {
-                               statement = new ArrayForeach (type, variable, expr, statement, loc);
-                       } else {
-                               statement = new CollectionForeach (type, variable, expr, statement, loc);
-                       }
-                       
-                       return statement.Resolve (ec);
-               }
 
-               protected override void DoEmit (EmitContext ec)
+               sealed class ArrayForeach : Statement
                {
-                       ILGenerator ig = ec.ig;
-                       
-                       Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
-                       ec.LoopBegin = ig.DefineLabel ();
-                       ec.LoopEnd = ig.DefineLabel ();
-
-                       statement.Emit (ec);
-                       
-                       ec.LoopBegin = old_begin;
-                       ec.LoopEnd = old_end;
-               }
+                       class ArrayCounter : TemporaryVariable
+                       {
+                               StatementExpression increment;
 
-               protected class ArrayCounter : TemporaryVariable
-               {
-                       StatementExpression increment;
+                               public ArrayCounter (Location loc)
+                                       : base (TypeManager.int32_type, loc)
+                               {
+                               }
 
-                       public ArrayCounter (Location loc)
-                               : base (TypeManager.int32_type, loc)
-                       {
-                       }
+                               public void ResolveIncrement (EmitContext ec)
+                               {
+                                       increment = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, this, loc));
+                                       increment.Resolve (ec);
+                               }
 
-                       public void ResolveIncrement (EmitContext ec)
-                       {
-                               increment = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, this, loc));
-                               increment.Resolve (ec);
+                               public void EmitIncrement (EmitContext ec)
+                               {
+                                       increment.Emit (ec);
+                               }
                        }
 
-                       public void EmitIncrement (EmitContext ec)
-                       {
-                               increment.Emit (ec);
-                       }
-               }
+                       readonly Foreach for_each;
+                       readonly Statement statement;
 
-               protected class ArrayForeach : Statement
-               {
-                       Expression variable, expr, conv;
-                       Statement statement;
-                       Type array_type;
-                       Expression var_type;
+                       Expression conv;
                        TemporaryVariable[] lengths;
+                       Expression [] length_exprs;
                        ArrayCounter[] counter;
-                       int rank;
 
                        TemporaryVariable copy;
                        Expression access;
-                       Expression[] length_exprs;
 
-                       public ArrayForeach (Expression var_type, Expression var,
-                                            Expression expr, Statement stmt, Location l)
+                       public ArrayForeach (Foreach @foreach, int rank)
                        {
-                               this.var_type = var_type;
-                               this.variable = var;
-                               this.expr = expr;
-                               statement = stmt;
-                               loc = l;
+                               for_each = @foreach;
+                               statement = for_each.statement;
+                               loc = @foreach.loc;
+
+                               counter = new ArrayCounter [rank];
+                               length_exprs = new Expression [rank];
+
+                               //
+                               // Only use temporary length variables when dealing with
+                               // multi-dimensional arrays
+                               //
+                               if (rank > 1)
+                                       lengths = new TemporaryVariable [rank];
                        }
 
                        protected override void CloneTo (CloneContext clonectx, Statement target)
@@ -5232,27 +5150,21 @@ namespace Mono.CSharp {
 
                        public override bool Resolve (EmitContext ec)
                        {
-                               array_type = expr.Type;
-                               rank = array_type.GetArrayRank ();
-
-                               copy = new TemporaryVariable (array_type, loc);
+                               copy = new TemporaryVariable (for_each.expr.Type, loc);
                                copy.Resolve (ec);
 
-                               counter = new ArrayCounter [rank];
-                               lengths = new TemporaryVariable [rank];
-                               length_exprs = new Expression [rank];
-
+                               int rank = length_exprs.Length;
                                ArrayList list = new ArrayList (rank);
                                for (int i = 0; i < rank; i++) {
                                        counter [i] = new ArrayCounter (loc);
                                        counter [i].ResolveIncrement (ec);                                      
 
-                                       lengths [i] = new TemporaryVariable (TypeManager.int32_type, loc);
-                                       lengths [i].Resolve (ec);
-
                                        if (rank == 1) {
                                                length_exprs [i] = new MemberAccess (copy, "Length").Resolve (ec);
                                        } else {
+                                               lengths [i] = new TemporaryVariable (TypeManager.int32_type, loc);
+                                               lengths [i].Resolve (ec);
+
                                                ArrayList args = new ArrayList (1);
                                                args.Add (new Argument (new IntConstant (i, loc)));
                                                length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec);
@@ -5265,6 +5177,7 @@ namespace Mono.CSharp {
                                if (access == null)
                                        return false;
 
+                               Expression var_type = for_each.type;
                                VarExpr ve = var_type as VarExpr;
                                if (ve != null) {
                                        // Infer implicitly typed local variable from foreach array type
@@ -5284,8 +5197,8 @@ namespace Mono.CSharp {
                                ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
                                ec.CurrentBranching.CreateSibling ();
 
-                               variable = variable.ResolveLValue (ec, conv, loc);
-                               if (variable == null)
+                               for_each.variable = for_each.variable.ResolveLValue (ec, conv, loc);
+                               if (for_each.variable == null)
                                        ok = false;
 
                                ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
@@ -5305,8 +5218,9 @@ namespace Mono.CSharp {
                        {
                                ILGenerator ig = ec.ig;
 
-                               copy.EmitAssign (ec, expr);
+                               copy.EmitAssign (ec, for_each.expr);
 
+                               int rank = length_exprs.Length;
                                Label[] test = new Label [rank];
                                Label[] loop = new Label [rank];
 
@@ -5314,7 +5228,8 @@ namespace Mono.CSharp {
                                        test [i] = ig.DefineLabel ();
                                        loop [i] = ig.DefineLabel ();
 
-                                       lengths [i].EmitAssign (ec, length_exprs [i]);
+                                       if (lengths != null)
+                                               lengths [i].EmitAssign (ec, length_exprs [i]);
                                }
 
                                IntConstant zero = new IntConstant (0, loc);
@@ -5325,7 +5240,7 @@ namespace Mono.CSharp {
                                        ig.MarkLabel (loop [i]);
                                }
 
-                               ((IAssignMethod) variable).EmitAssign (ec, conv, false, false);
+                               ((IAssignMethod) for_each.variable).EmitAssign (ec, conv, false, false);
 
                                statement.Emit (ec);
 
@@ -5336,7 +5251,12 @@ namespace Mono.CSharp {
 
                                        ig.MarkLabel (test [i]);
                                        counter [i].Emit (ec);
-                                       lengths [i].Emit (ec);
+
+                                       if (lengths != null)
+                                               lengths [i].Emit (ec);
+                                       else
+                                               length_exprs [i].Emit (ec);
+
                                        ig.Emit (OpCodes.Blt, loop [i]);
                                }
 
@@ -5345,20 +5265,78 @@ namespace Mono.CSharp {
 
                        public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
                        {
+                               for_each.expr.MutateHoistedGenericType (storey);
+
                                copy.MutateHoistedGenericType (storey);
                                conv.MutateHoistedGenericType (storey);
-                               variable.MutateHoistedGenericType (storey);
                                statement.MutateHoistedGenericType (storey);
 
-                               for (int i = 0; i < rank; i++) {
+                               for (int i = 0; i < counter.Length; i++) {
                                        counter [i].MutateHoistedGenericType (storey);
-                                       lengths [i].MutateHoistedGenericType (storey);
+                                       if (lengths != null)
+                                               lengths [i].MutateHoistedGenericType (storey);
                                }
                        }
                }
 
-               protected class CollectionForeach : Statement
+               sealed class CollectionForeach : Statement
                {
+                       class CollectionForeachStatement : Statement
+                       {
+                               Type type;
+                               Expression variable, current, conv;
+                               Statement statement;
+                               Assign assign;
+
+                               public CollectionForeachStatement (Type type, Expression variable,
+                                                                  Expression current, Statement statement,
+                                                                  Location loc)
+                               {
+                                       this.type = type;
+                                       this.variable = variable;
+                                       this.current = current;
+                                       this.statement = statement;
+                                       this.loc = loc;
+                               }
+
+                               protected override void CloneTo (CloneContext clonectx, Statement target)
+                               {
+                                       throw new NotImplementedException ();
+                               }
+
+                               public override bool Resolve (EmitContext ec)
+                               {
+                                       current = current.Resolve (ec);
+                                       if (current == null)
+                                               return false;
+
+                                       conv = Convert.ExplicitConversion (ec, current, type, loc);
+                                       if (conv == null)
+                                               return false;
+
+                                       assign = new SimpleAssign (variable, conv, loc);
+                                       if (assign.Resolve (ec) == null)
+                                               return false;
+
+                                       if (!statement.Resolve (ec))
+                                               return false;
+
+                                       return true;
+                               }
+
+                               protected override void DoEmit (EmitContext ec)
+                               {
+                                       assign.EmitStatement (ec);
+                                       statement.Emit (ec);
+                               }
+
+                               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+                               {
+                                       assign.MutateHoistedGenericType (storey);
+                                       statement.MutateHoistedGenericType (storey);
+                               }
+                       }
+
                        Expression variable, expr;
                        Statement statement;
 
@@ -5393,15 +5371,6 @@ namespace Mono.CSharp {
                        {
                                Type return_type = mi.ReturnType;
 
-                               if ((return_type == TypeManager.ienumerator_type) && (mi.DeclaringType == TypeManager.string_type))
-                                       //
-                                       // Apply the same optimization as MS: skip the GetEnumerator
-                                       // returning an IEnumerator, and use the one returning a 
-                                       // CharEnumerator instead. This allows us to avoid the 
-                                       // try-finally block and the boxing.
-                                       //
-                                       return false;
-
                                //
                                // Ok, we can access it, now make sure that we can do something
                                // with this `GetEnumerator'
@@ -5871,60 +5840,65 @@ namespace Mono.CSharp {
                        }
                }
 
-               protected class CollectionForeachStatement : Statement
+               Expression type;
+               Expression variable;
+               Expression expr;
+               Statement statement;
+
+               public Foreach (Expression type, LocalVariableReference var, Expression expr,
+                               Statement stmt, Location l)
                {
-                       Type type;
-                       Expression variable, current, conv;
-                       Statement statement;
-                       Assign assign;
+                       this.type = type;
+                       this.variable = var;
+                       this.expr = expr;
+                       statement = stmt;
+                       loc = l;
+               }
 
-                       public CollectionForeachStatement (Type type, Expression variable,
-                                                          Expression current, Statement statement,
-                                                          Location loc)
-                       {
-                               this.type = type;
-                               this.variable = variable;
-                               this.current = current;
-                               this.statement = statement;
-                               this.loc = loc;
-                       }
+               public Statement Statement {
+                       get { return statement; }
+               }
 
-                       protected override void CloneTo (CloneContext clonectx, Statement target)
-                       {
-                               throw new NotImplementedException ();
+               public override bool Resolve (EmitContext ec)
+               {
+                       expr = expr.Resolve (ec);
+                       if (expr == null)
+                               return false;
+
+                       if (expr.IsNull) {
+                               Report.Error (186, loc, "Use of null is not valid in this context");
+                               return false;
                        }
 
-                       public override bool Resolve (EmitContext ec)
-                       {
-                               current = current.Resolve (ec);
-                               if (current == null)
+                       if (expr.Type == TypeManager.string_type) {
+                               statement = new ArrayForeach (this, 1);
+                       } else if (expr.Type.IsArray) {
+                               statement = new ArrayForeach (this, expr.Type.GetArrayRank ());
+                       } else {
+                               if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
+                                       Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
+                                               expr.ExprClassName);
                                        return false;
+                               }
 
-                               conv = Convert.ExplicitConversion (ec, current, type, loc);
-                               if (conv == null)
-                                       return false;
+                               statement = new CollectionForeach (type, variable, expr, statement, loc);
+                       }
 
-                               assign = new SimpleAssign (variable, conv, loc);
-                               if (assign.Resolve (ec) == null)
-                                       return false;
+                       return statement.Resolve (ec);
+               }
 
-                               if (!statement.Resolve (ec))
-                                       return false;
+               protected override void DoEmit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
 
-                               return true;
-                       }
+                       Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
+                       ec.LoopBegin = ig.DefineLabel ();
+                       ec.LoopEnd = ig.DefineLabel ();
 
-                       protected override void DoEmit (EmitContext ec)
-                       {
-                               assign.EmitStatement (ec);
-                               statement.Emit (ec);
-                       }
+                       statement.Emit (ec);
 
-                       public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
-                       {
-                               assign.MutateHoistedGenericType (storey);
-                               statement.MutateHoistedGenericType (storey);
-                       }
+                       ec.LoopBegin = old_begin;
+                       ec.LoopEnd = old_end;
                }
 
                protected override void CloneTo (CloneContext clonectx, Statement t)