2006-11-16 Martin Baulig <martin@ximian.com>
authorMartin Baulig <martin@novell.com>
Thu, 16 Nov 2006 16:01:07 +0000 (16:01 -0000)
committerMartin Baulig <martin@novell.com>
Thu, 16 Nov 2006 16:01:07 +0000 (16:01 -0000)
* anonymous.cs (IAnonymousMethodHost): New public interface; use
this outside anonymous.cs instead of accessing AnonymousMethodHost
directly.

svn path=/branches/martin/anonymous-methods2/mcs/; revision=68005

mcs/mcs/ChangeLog
mcs/mcs/anonymous.cs
mcs/mcs/expression.cs [new file with mode: 0644]
mcs/mcs/statement.cs [new file with mode: 0644]

index 93be991e7f8507e77e90cd133eedc2b85d853520..ef05eba46681bb54690b47c04e505efb05dc9e10 100644 (file)
@@ -1,3 +1,9 @@
+2006-11-16  Martin Baulig  <martin@ximian.com>
+
+       * anonymous.cs (IAnonymousMethodHost): New public interface; use
+       this outside anonymous.cs instead of accessing AnonymousMethodHost
+       directly.       
+
 2006-11-16  Martin Baulig  <martin@ximian.com>
 
        **** The anonymous methods branch starts here ****
index 7b0a145a313cb4d417ee56970e42cc2aae15cc14..435401d0508f1d5c9e1d2e45937e7535cd833fb2 100644 (file)
@@ -160,16 +160,16 @@ namespace Mono.CSharp {
 
        public class ScopeInfo : CompilerGeneratedClass
        {
-               public readonly AnonymousMethodHost RootScope;
+               protected readonly AnonymousMethodHost RootScope;
                public readonly int ID = ++next_id;
                public Block ScopeBlock;
 
                static int next_id;
 
-               public ScopeInfo (AnonymousMethodHost root, Block block)
-                       : base (root, null, Modifiers.PUBLIC, block.StartLocation)
+               public ScopeInfo (IAnonymousMethodHost root, Block block)
+                       : base ((AnonymousMethodHost) root, null, 0, block.StartLocation)
                {
-                       this.RootScope = root;
+                       this.RootScope = (AnonymousMethodHost) root;
                        ScopeBlock = block;
 
                        Report.Debug (64, "NEW SCOPE", this, root, block);
@@ -192,7 +192,7 @@ namespace Mono.CSharp {
 
                Hashtable locals = new Hashtable ();
 
-               public virtual AnonymousMethodHost Host {
+               protected virtual AnonymousMethodHost Host {
                        get { return RootScope; }
                }
 
@@ -252,13 +252,54 @@ namespace Mono.CSharp {
                        return te.Type;
                }
 
+               public static void EmitScopeInstance (EmitContext ec, ScopeInfo scope,
+                                                     ToplevelBlock toplevel)
+               {
+                       AnonymousMethodHost root_scope = (AnonymousMethodHost) toplevel.AnonymousMethodHost;
+
+                       root_scope.EmitScopeInstance (ec);
+                       while (root_scope != scope.Host) {
+                               ec.ig.Emit (OpCodes.Ldfld, root_scope.ParentLink.FieldBuilder);
+                               root_scope = root_scope.ParentHost;
+
+                               if (root_scope == null)
+                                       throw new InternalErrorException (
+                                               "Never found scope {0} starting at block {1}",
+                                               scope, ec.CurrentBlock.ID);
+                       }
+
+                       if (scope != (ScopeInfo) scope.Host)
+                               scope.ScopeInstance.Emit (ec);
+               }
+
+               public static bool CompleteContexts (IAnonymousMethodHost amh, Block container)
+               {
+                       AnonymousMethodHost host = (AnonymousMethodHost) amh;
+
+                       if (host != null)
+                               host.LinkScopes ();
+
+                       if ((container == null) && (host != null)) {
+                               if (host.DefineType () == null)
+                                       return false;
+                               if (!host.ResolveType ())
+                                       return false;
+                               if (!host.ResolveMembers ())
+                                       return false;
+                               if (!host.DefineMembers ())
+                                       return false;
+                       }
+
+                       return true;
+               }
+
                protected override bool DoResolveMembers ()
                {
                        Report.Debug (64, "SCOPE INFO RESOLVE MEMBERS", this, GetType (), IsGeneric,
                                      Parent.IsGeneric, GenericMethod);
 
-                       if (Host != this)
-                               scope_instance = new CapturedScope (Host, this);
+                       if ((ScopeInfo) Host != this)
+                               scope_instance = new CapturedScope ((ScopeInfo) Host, this);
 
                        return base.DoResolveMembers ();
                }
@@ -556,7 +597,26 @@ namespace Mono.CSharp {
                }
        }
 
-       public class AnonymousMethodHost : ScopeInfo
+       public interface IAnonymousMethodHost
+       {
+               bool IsIterator {
+                       get;
+               }
+
+               void AddScope (ScopeInfo scope);
+
+               Variable CaptureThis ();
+
+               Variable AddParameter (Parameter par, int idx);
+
+               Variable GetCapturedParameter (Parameter par);
+
+               bool IsParameterCaptured (string name);
+
+               void EmitScopeInstance (EmitContext ec);
+       }
+
+       public class AnonymousMethodHost : ScopeInfo, IAnonymousMethodHost
        {
                public AnonymousMethodHost (ToplevelBlock toplevel, TypeContainer parent,
                                            GenericMethod generic, Location loc)
@@ -571,7 +631,7 @@ namespace Mono.CSharp {
                CapturedThis this_variable;
                Hashtable captured_params;
 
-               public override AnonymousMethodHost Host {
+               protected override AnonymousMethodHost Host {
                        get { return this; }
                }
 
diff --git a/mcs/mcs/expression.cs b/mcs/mcs/expression.cs
new file mode 100644 (file)
index 0000000..391001b
--- /dev/null
@@ -0,0 +1,8834 @@
+//
+// expression.cs: Expression representation for the IL tree.
+//
+// Author:
+//   Miguel de Icaza (miguel@ximian.com)
+//   Marek Safar (marek.safar@seznam.cz)
+//
+// (C) 2001, 2002, 2003 Ximian, Inc.
+// (C) 2003, 2004 Novell, Inc.
+//
+#define USE_OLD
+
+namespace Mono.CSharp {
+       using System;
+       using System.Collections;
+       using System.Reflection;
+       using System.Reflection.Emit;
+       using System.Text;
+
+       /// <summary>
+       ///   This is just a helper class, it is generated by Unary, UnaryMutator
+       ///   when an overloaded method has been found.  It just emits the code for a
+       ///   static call.
+       /// </summary>
+       public class StaticCallExpr : ExpressionStatement {
+               ArrayList args;
+               MethodInfo mi;
+
+               public StaticCallExpr (MethodInfo m, ArrayList a, Location l)
+               {
+                       mi = m;
+                       args = a;
+
+                       type = m.ReturnType;
+                       eclass = ExprClass.Value;
+                       loc = l;
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       //
+                       // We are born fully resolved
+                       //
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       if (args != null) 
+                               Invocation.EmitArguments (ec, mi, args, false, null);
+
+                       ec.ig.Emit (OpCodes.Call, mi);
+                       return;
+               }
+               
+               static public StaticCallExpr MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
+                                                        Expression e, Location loc)
+               {
+                       ArrayList args;
+                       MethodBase method;
+                       
+                       args = new ArrayList (1);
+                       Argument a = new Argument (e, Argument.AType.Expression);
+
+                        // We need to resolve the arguments before sending them in !
+                        if (!a.Resolve (ec, loc))
+                                return null;
+
+                        args.Add (a);
+                       method = Invocation.OverloadResolve (
+                               ec, (MethodGroupExpr) mg, args, false, loc);
+
+                       if (method == null)
+                               return null;
+
+                       return new StaticCallExpr ((MethodInfo) method, args, loc);
+               }
+
+               public override void EmitStatement (EmitContext ec)
+               {
+                       Emit (ec);
+                       if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
+                               ec.ig.Emit (OpCodes.Pop);
+               }
+               
+               public MethodInfo Method {
+                       get { return mi; }
+               }
+       }
+
+       public class ParenthesizedExpression : Expression
+       {
+               public Expression Expr;
+
+               public ParenthesizedExpression (Expression expr)
+               {
+                       this.Expr = expr;
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       Expr = Expr.Resolve (ec);
+                       return Expr;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       throw new Exception ("Should not happen");
+               }
+
+               public override Location Location
+               {
+                       get {
+                               return Expr.Location;
+                       }
+               }
+       }
+       
+       /// <summary>
+       ///   Unary expressions.  
+       /// </summary>
+       ///
+       /// <remarks>
+       ///   Unary implements unary expressions.   It derives from
+       ///   ExpressionStatement becuase the pre/post increment/decrement
+       ///   operators can be used in a statement context.
+       /// </remarks>
+       public class Unary : Expression {
+               public enum Operator : byte {
+                       UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
+                       Indirection, AddressOf,  TOP
+               }
+
+               public Operator Oper;
+               public Expression Expr;
+               
+               public Unary (Operator op, Expression expr, Location loc)
+               {
+                       this.Oper = op;
+                       this.Expr = expr;
+                       this.loc = loc;
+               }
+
+               /// <summary>
+               ///   Returns a stringified representation of the Operator
+               /// </summary>
+               static public string OperName (Operator oper)
+               {
+                       switch (oper){
+                       case Operator.UnaryPlus:
+                               return "+";
+                       case Operator.UnaryNegation:
+                               return "-";
+                       case Operator.LogicalNot:
+                               return "!";
+                       case Operator.OnesComplement:
+                               return "~";
+                       case Operator.AddressOf:
+                               return "&";
+                       case Operator.Indirection:
+                               return "*";
+                       }
+
+                       return oper.ToString ();
+               }
+
+               public static readonly string [] oper_names;
+
+               static Unary ()
+               {
+                       oper_names = new string [(int)Operator.TOP];
+
+                       oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
+                       oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
+                       oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
+                       oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
+                       oper_names [(int) Operator.Indirection] = "op_Indirection";
+                       oper_names [(int) Operator.AddressOf] = "op_AddressOf";
+               }
+
+               public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
+               {
+                       Error_OperatorCannotBeApplied (loc, oper, TypeManager.CSharpName (t));
+               }
+
+               public static void Error_OperatorCannotBeApplied (Location loc, string oper, string type)
+               {
+                       Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
+                               oper, type);
+               }
+
+               void Error23 (Type t)
+               {
+                       Error_OperatorCannotBeApplied (loc, OperName (Oper), t);
+               }
+
+               /// <remarks>
+               ///   The result has been already resolved:
+               ///
+               ///   FIXME: a minus constant -128 sbyte cant be turned into a
+               ///   constant byte.
+               /// </remarks>
+               static Expression TryReduceNegative (Constant expr)
+               {
+                       Expression e = null;
+
+                       if (expr is IntConstant)
+                               e = new IntConstant (-((IntConstant) expr).Value, expr.Location);
+                       else if (expr is UIntConstant){
+                               uint value = ((UIntConstant) expr).Value;
+
+                               if (value < 2147483649)
+                                       return new IntConstant (-(int)value, expr.Location);
+                               else
+                                       e = new LongConstant (-value, expr.Location);
+                       }
+                       else if (expr is LongConstant)
+                               e = new LongConstant (-((LongConstant) expr).Value, expr.Location);
+                       else if (expr is ULongConstant){
+                               ulong value = ((ULongConstant) expr).Value;
+
+                               if (value < 9223372036854775809)
+                                       return new LongConstant(-(long)value, expr.Location);
+                       }
+                       else if (expr is FloatConstant)
+                               e = new FloatConstant (-((FloatConstant) expr).Value, expr.Location);
+                       else if (expr is DoubleConstant)
+                               e = new DoubleConstant (-((DoubleConstant) expr).Value, expr.Location);
+                       else if (expr is DecimalConstant)
+                               e = new DecimalConstant (-((DecimalConstant) expr).Value, expr.Location);
+                       else if (expr is ShortConstant)
+                               e = new IntConstant (-((ShortConstant) expr).Value, expr.Location);
+                       else if (expr is UShortConstant)
+                               e = new IntConstant (-((UShortConstant) expr).Value, expr.Location);
+                       else if (expr is SByteConstant)
+                               e = new IntConstant (-((SByteConstant) expr).Value, expr.Location);
+                       else if (expr is ByteConstant)
+                               e = new IntConstant (-((ByteConstant) expr).Value, expr.Location);
+                       return e;
+               }
+
+               // <summary>
+               //   This routine will attempt to simplify the unary expression when the
+               //   argument is a constant.  The result is returned in `result' and the
+               //   function returns true or false depending on whether a reduction
+               //   was performed or not
+               // </summary>
+               bool Reduce (EmitContext ec, Constant e, out Expression result)
+               {
+                       Type expr_type = e.Type;
+                       
+                       switch (Oper){
+                       case Operator.UnaryPlus:
+                               if (expr_type == TypeManager.bool_type){
+                                       result = null;
+                                       Error23 (expr_type);
+                                       return false;
+                               }
+                               
+                               result = e;
+                               return true;
+                               
+                       case Operator.UnaryNegation:
+                               result = TryReduceNegative (e);
+                               return result != null;
+                               
+                       case Operator.LogicalNot:
+                               if (expr_type != TypeManager.bool_type) {
+                                       result = null;
+                                       Error23 (expr_type);
+                                       return false;
+                               }
+                               
+                               BoolConstant b = (BoolConstant) e;
+                               result = new BoolConstant (!(b.Value), b.Location);
+                               return true;
+                               
+                       case Operator.OnesComplement:
+                               if (!((expr_type == TypeManager.int32_type) ||
+                                     (expr_type == TypeManager.uint32_type) ||
+                                     (expr_type == TypeManager.int64_type) ||
+                                     (expr_type == TypeManager.uint64_type) ||
+                                     (expr_type.IsSubclassOf (TypeManager.enum_type)))){
+
+                                       result = null;
+                                       if (Convert.ImplicitConversionExists (ec, e, TypeManager.int32_type)){
+                                               result = new Cast (new TypeExpression (TypeManager.int32_type, loc), e, loc);
+                                               result = result.Resolve (ec);
+                                       } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.uint32_type)){
+                                               result = new Cast (new TypeExpression (TypeManager.uint32_type, loc), e, loc);
+                                               result = result.Resolve (ec);
+                                       } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.int64_type)){
+                                               result = new Cast (new TypeExpression (TypeManager.int64_type, loc), e, loc);
+                                               result = result.Resolve (ec);
+                                       } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.uint64_type)){
+                                               result = new Cast (new TypeExpression (TypeManager.uint64_type, loc), e, loc);
+                                               result = result.Resolve (ec);
+                                       }
+
+                                       if (result == null || !(result is Constant)){
+                                               result = null;
+                                               Error23 (expr_type);
+                                               return false;
+                                       }
+
+                                       expr_type = result.Type;
+                                       e = (Constant) result;
+                               }
+
+                               if (e is EnumConstant){
+                                       EnumConstant enum_constant = (EnumConstant) e;
+                                       Expression reduced;
+                                       
+                                       if (Reduce (ec, enum_constant.Child, out reduced)){
+                                               result = new EnumConstant ((Constant) reduced, enum_constant.Type);
+                                               return true;
+                                       } else {
+                                               result = null;
+                                               return false;
+                                       }
+                               }
+
+                               if (expr_type == TypeManager.int32_type){
+                                       result = new IntConstant (~ ((IntConstant) e).Value, e.Location);
+                               } else if (expr_type == TypeManager.uint32_type){
+                                       result = new UIntConstant (~ ((UIntConstant) e).Value, e.Location);
+                               } else if (expr_type == TypeManager.int64_type){
+                                       result = new LongConstant (~ ((LongConstant) e).Value, e.Location);
+                               } else if (expr_type == TypeManager.uint64_type){
+                                       result = new ULongConstant (~ ((ULongConstant) e).Value, e.Location);
+                               } else {
+                                       result = null;
+                                       Error23 (expr_type);
+                                       return false;
+                               }
+                               return true;
+
+                       case Operator.AddressOf:
+                               result = this;
+                               return false;
+
+                       case Operator.Indirection:
+                               result = this;
+                               return false;
+                       }
+                       throw new Exception ("Can not constant fold: " + Oper.ToString());
+               }
+
+               Expression ResolveOperator (EmitContext ec)
+               {
+                       //
+                       // Step 1: Default operations on CLI native types.
+                       //
+
+                       // Attempt to use a constant folding operation.
+                       if (Expr is Constant){
+                               Expression result;
+                               
+                               if (Reduce (ec, (Constant) Expr, out result))
+                                       return result;
+                       }
+
+                       //
+                       // Step 2: Perform Operator Overload location
+                       //
+                       Type expr_type = Expr.Type;
+                       Expression mg;
+                       string op_name;
+                       
+                       op_name = oper_names [(int) Oper];
+
+                       mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
+                       
+                       if (mg != null) {
+                               Expression e = StaticCallExpr.MakeSimpleCall (
+                                       ec, (MethodGroupExpr) mg, Expr, loc);
+
+                               if (e == null){
+                                       Error23 (expr_type);
+                                       return null;
+                               }
+                               
+                               return e;
+                       }
+
+                       // Only perform numeric promotions on:
+                       // +, - 
+
+                       if (expr_type == null)
+                               return null;
+                       
+                       switch (Oper){
+                       case Operator.LogicalNot:
+                               if (expr_type != TypeManager.bool_type) {
+                                       Expr = ResolveBoolean (ec, Expr, loc);
+                                       if (Expr == null){
+                                               Error23 (expr_type);
+                                               return null;
+                                       }
+                               }
+                               
+                               type = TypeManager.bool_type;
+                               return this;
+
+                       case Operator.OnesComplement:
+                               if (!((expr_type == TypeManager.int32_type) ||
+                                     (expr_type == TypeManager.uint32_type) ||
+                                     (expr_type == TypeManager.int64_type) ||
+                                     (expr_type == TypeManager.uint64_type) ||
+                                     (expr_type.IsSubclassOf (TypeManager.enum_type)))){
+                                       Expression e;
+
+                                       e = Convert.ImplicitConversion (ec, Expr, TypeManager.int32_type, loc);
+                                       if (e != null)
+                                               goto ok;
+                                       e = Convert.ImplicitConversion (ec, Expr, TypeManager.uint32_type, loc);
+                                       if (e != null)
+                                               goto ok;
+                                       e = Convert.ImplicitConversion (ec, Expr, TypeManager.int64_type, loc);
+                                       if (e != null)
+                                               goto ok;
+                                       e = Convert.ImplicitConversion (ec, Expr, TypeManager.uint64_type, loc);
+                                       if (e != null)
+                                               goto ok;
+                                       Error23 (expr_type);
+                                       return null;
+                               ok:
+                                       Expr = e;
+                                       expr_type = e.Type;
+                               }
+
+                               type = expr_type;
+                               return this;
+
+                       case Operator.AddressOf:
+                               if (!ec.InUnsafe) {
+                                       UnsafeError (loc); 
+                                       return null;
+                               }
+                               
+                               if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
+                                       return null;
+                               }
+
+                               IVariable variable = Expr as IVariable;
+                               bool is_fixed = variable != null && variable.VerifyFixed ();
+
+                               if (!ec.InFixedInitializer && !is_fixed) {
+                                       Error (212, "You can only take the address of unfixed expression inside " +
+                                              "of a fixed statement initializer");
+                                       return null;
+                               }
+
+                               if (ec.InFixedInitializer && is_fixed) {
+                                       Error (213, "You cannot use the fixed statement to take the address of an already fixed expression");
+                                       return null;
+                               }
+
+                               LocalVariableReference lr = Expr as LocalVariableReference;
+                               if (lr != null){
+                                       if (lr.local_info.IsCaptured){
+                                               AnonymousMethod.Error_AddressOfCapturedVar (lr.Name, loc);
+                                               return null;
+                                       }
+                                       lr.local_info.AddressTaken = true;
+                                       lr.local_info.Used = true;
+                               }
+
+                               ParameterReference pr = Expr as ParameterReference;
+                               if ((pr != null) && pr.Parameter.IsCaptured) {
+                                       AnonymousMethod.Error_AddressOfCapturedVar (pr.Name, loc);
+                                       return null;
+                               }
+
+                               // According to the specs, a variable is considered definitely assigned if you take
+                               // its address.
+                               if ((variable != null) && (variable.VariableInfo != null)){
+                                       variable.VariableInfo.SetAssigned (ec);
+                               }
+
+                               type = TypeManager.GetPointerType (Expr.Type);
+                               return this;
+
+                       case Operator.Indirection:
+                               if (!ec.InUnsafe){
+                                       UnsafeError (loc);
+                                       return null;
+                               }
+                               
+                               if (!expr_type.IsPointer){
+                                       Error (193, "The * or -> operator must be applied to a pointer");
+                                       return null;
+                               }
+                               
+                               //
+                               // We create an Indirection expression, because
+                               // it can implement the IMemoryLocation.
+                               // 
+                               return new Indirection (Expr, loc);
+                       
+                       case Operator.UnaryPlus:
+                               //
+                               // A plus in front of something is just a no-op, so return the child.
+                               //
+                               return Expr;
+
+                       case Operator.UnaryNegation:
+                               //
+                               // Deals with -literals
+                               // int     operator- (int x)
+                               // long    operator- (long x)
+                               // float   operator- (float f)
+                               // double  operator- (double d)
+                               // decimal operator- (decimal d)
+                               //
+                               Expression expr = null;
+
+                               //
+                               // transform - - expr into expr
+                               //
+                               if (Expr is Unary){
+                                       Unary unary = (Unary) Expr;
+                                       
+                                       if (unary.Oper == Operator.UnaryNegation)
+                                               return unary.Expr;
+                               }
+
+                               //
+                               // perform numeric promotions to int,
+                               // long, double.
+                               //
+                               //
+                               // The following is inneficient, because we call
+                               // ImplicitConversion too many times.
+                               //
+                               // It is also not clear if we should convert to Float
+                               // or Double initially.
+                               //
+                               if (expr_type == TypeManager.uint32_type){
+                                       //
+                                       // FIXME: handle exception to this rule that
+                                       // permits the int value -2147483648 (-2^31) to
+                                       // bt wrote as a decimal interger literal
+                                       //
+                                       type = TypeManager.int64_type;
+                                       Expr = Convert.ImplicitConversion (ec, Expr, type, loc);
+                                       return this;
+                               }
+
+                               if (expr_type == TypeManager.uint64_type){
+                                       //
+                                       // FIXME: Handle exception of `long value'
+                                       // -92233720368547758087 (-2^63) to be wrote as
+                                       // decimal integer literal.
+                                       //
+                                       Error23 (expr_type);
+                                       return null;
+                               }
+
+                               if (expr_type == TypeManager.float_type){
+                                       type = expr_type;
+                                       return this;
+                               }
+                               
+                               expr = Convert.ImplicitConversion (ec, Expr, TypeManager.int32_type, loc);
+                               if (expr != null){
+                                       Expr = expr;
+                                       type = expr.Type;
+                                       return this;
+                               } 
+
+                               expr = Convert.ImplicitConversion (ec, Expr, TypeManager.int64_type, loc);
+                               if (expr != null){
+                                       Expr = expr;
+                                       type = expr.Type;
+                                       return this;
+                               }
+
+                               expr = Convert.ImplicitConversion (ec, Expr, TypeManager.double_type, loc);
+                               if (expr != null){
+                                       Expr = expr;
+                                       type = expr.Type;
+                                       return this;
+                               }
+                               
+                               Error23 (expr_type);
+                               return null;
+                       }
+
+                       Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
+                              TypeManager.CSharpName (expr_type) + "'");
+                       return null;
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       if (Oper == Operator.AddressOf) {
+                               Expr = Expr.DoResolveLValue (ec, new EmptyExpression ());
+
+                               if (Expr == null || Expr.eclass != ExprClass.Variable){
+                                       Error (211, "Cannot take the address of the given expression");
+                                       return null;
+                               }
+                       }
+                       else
+                               Expr = Expr.Resolve (ec);
+                       
+                       if (Expr == null)
+                               return null;
+
+#if GMCS_SOURCE
+                       if (TypeManager.IsNullableValueType (Expr.Type))
+                               return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
+#endif
+
+                       eclass = ExprClass.Value;
+                       return ResolveOperator (ec);
+               }
+
+               public override Expression DoResolveLValue (EmitContext ec, Expression right)
+               {
+                       if (Oper == Operator.Indirection)
+                               return DoResolve (ec);
+
+                       return null;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+                       
+                       switch (Oper) {
+                       case Operator.UnaryPlus:
+                               throw new Exception ("This should be caught by Resolve");
+                               
+                       case Operator.UnaryNegation:
+                               if (ec.CheckState && type != TypeManager.float_type && type != TypeManager.double_type) {
+                                       ig.Emit (OpCodes.Ldc_I4_0);
+                                       if (type == TypeManager.int64_type)
+                                               ig.Emit (OpCodes.Conv_U8);
+                                       Expr.Emit (ec);
+                                       ig.Emit (OpCodes.Sub_Ovf);
+                               } else {
+                                       Expr.Emit (ec);
+                                       ig.Emit (OpCodes.Neg);
+                               }
+                               
+                               break;
+                               
+                       case Operator.LogicalNot:
+                               Expr.Emit (ec);
+                               ig.Emit (OpCodes.Ldc_I4_0);
+                               ig.Emit (OpCodes.Ceq);
+                               break;
+                               
+                       case Operator.OnesComplement:
+                               Expr.Emit (ec);
+                               ig.Emit (OpCodes.Not);
+                               break;
+                               
+                       case Operator.AddressOf:
+                               ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
+                               break;
+                               
+                       default:
+                               throw new Exception ("This should not happen: Operator = "
+                                                    + Oper.ToString ());
+                       }
+               }
+
+               public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
+               {
+                       if (Oper == Operator.LogicalNot)
+                               Expr.EmitBranchable (ec, target, !onTrue);
+                       else
+                               base.EmitBranchable (ec, target, onTrue);
+               }
+
+               public override string ToString ()
+               {
+                       return "Unary (" + Oper + ", " + Expr + ")";
+               }
+               
+       }
+
+       //
+       // Unary operators are turned into Indirection expressions
+       // after semantic analysis (this is so we can take the address
+       // of an indirection).
+       //
+       public class Indirection : Expression, IMemoryLocation, IAssignMethod, IVariable {
+               Expression expr;
+               LocalTemporary temporary;
+               bool prepared;
+               
+               public Indirection (Expression expr, Location l)
+               {
+                       this.expr = expr;
+                       type = TypeManager.HasElementType (expr.Type) ? TypeManager.GetElementType (expr.Type) : expr.Type;
+                       eclass = ExprClass.Variable;
+                       loc = l;
+               }
+               
+               public override void Emit (EmitContext ec)
+               {
+                       if (!prepared)
+                               expr.Emit (ec);
+                       
+                       LoadFromPtr (ec.ig, Type);
+               }
+
+               public void Emit (EmitContext ec, bool leave_copy)
+               {
+                       Emit (ec);
+                       if (leave_copy) {
+                               ec.ig.Emit (OpCodes.Dup);
+                               temporary = new LocalTemporary (expr.Type);
+                               temporary.Store (ec);
+                       }
+               }
+               
+               public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
+               {
+                       prepared = prepare_for_load;
+                       
+                       expr.Emit (ec);
+
+                       if (prepare_for_load)
+                               ec.ig.Emit (OpCodes.Dup);
+                       
+                       source.Emit (ec);
+                       if (leave_copy) {
+                               ec.ig.Emit (OpCodes.Dup);
+                               temporary = new LocalTemporary (expr.Type);
+                               temporary.Store (ec);
+                       }
+                       
+                       StoreFromPtr (ec.ig, type);
+                       
+                       if (temporary != null) {
+                               temporary.Emit (ec);
+                               temporary.Release (ec);
+                       }
+               }
+               
+               public void AddressOf (EmitContext ec, AddressOp Mode)
+               {
+                       expr.Emit (ec);
+               }
+
+               public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
+               {
+                       return DoResolve (ec);
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       //
+                       // Born fully resolved
+                       //
+                       return this;
+               }
+               
+               public override string ToString ()
+               {
+                       return "*(" + expr + ")";
+               }
+
+               #region IVariable Members
+
+               public VariableInfo VariableInfo {
+                       get { return null; }
+               }
+
+               public bool VerifyFixed ()
+               {
+                       // A pointer-indirection is always fixed.
+                       return true;
+               }
+
+               #endregion
+       }
+       
+       /// <summary>
+       ///   Unary Mutator expressions (pre and post ++ and --)
+       /// </summary>
+       ///
+       /// <remarks>
+       ///   UnaryMutator implements ++ and -- expressions.   It derives from
+       ///   ExpressionStatement becuase the pre/post increment/decrement
+       ///   operators can be used in a statement context.
+       ///
+       /// FIXME: Idea, we could split this up in two classes, one simpler
+       /// for the common case, and one with the extra fields for more complex
+       /// classes (indexers require temporary access;  overloaded require method)
+       ///
+       /// </remarks>
+       public class UnaryMutator : ExpressionStatement {
+               [Flags]
+               public enum Mode : byte {
+                       IsIncrement    = 0,
+                       IsDecrement    = 1,
+                       IsPre          = 0,
+                       IsPost         = 2,
+                       
+                       PreIncrement   = 0,
+                       PreDecrement   = IsDecrement,
+                       PostIncrement  = IsPost,
+                       PostDecrement  = IsPost | IsDecrement
+               }
+
+               Mode mode;
+               bool is_expr = false;
+               bool recurse = false;
+
+               Expression expr;
+
+               //
+               // This is expensive for the simplest case.
+               //
+               StaticCallExpr method;
+
+               public UnaryMutator (Mode m, Expression e, Location l)
+               {
+                       mode = m;
+                       loc = l;
+                       expr = e;
+               }
+
+               static string OperName (Mode mode)
+               {
+                       return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
+                               "++" : "--";
+               }
+
+               /// <summary>
+               ///   Returns whether an object of type `t' can be incremented
+               ///   or decremented with add/sub (ie, basically whether we can
+               ///   use pre-post incr-decr operations on it, but it is not a
+               ///   System.Decimal, which we require operator overloading to catch)
+               /// </summary>
+               static bool IsIncrementableNumber (Type t)
+               {
+                       return (t == TypeManager.sbyte_type) ||
+                               (t == TypeManager.byte_type) ||
+                               (t == TypeManager.short_type) ||
+                               (t == TypeManager.ushort_type) ||
+                               (t == TypeManager.int32_type) ||
+                               (t == TypeManager.uint32_type) ||
+                               (t == TypeManager.int64_type) ||
+                               (t == TypeManager.uint64_type) ||
+                               (t == TypeManager.char_type) ||
+                               (t.IsSubclassOf (TypeManager.enum_type)) ||
+                               (t == TypeManager.float_type) ||
+                               (t == TypeManager.double_type) ||
+                               (t.IsPointer && t != TypeManager.void_ptr_type);
+               }
+
+               Expression ResolveOperator (EmitContext ec)
+               {
+                       Type expr_type = expr.Type;
+
+                       //
+                       // Step 1: Perform Operator Overload location
+                       //
+                       Expression mg;
+                       string op_name;
+                       
+                       if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
+                               op_name = "op_Increment";
+                       else 
+                               op_name = "op_Decrement";
+
+                       mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
+
+                       if (mg != null) {
+                               method = StaticCallExpr.MakeSimpleCall (
+                                       ec, (MethodGroupExpr) mg, expr, loc);
+
+                               type = method.Type;
+                       } else if (!IsIncrementableNumber (expr_type)) {
+                               Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
+                                      TypeManager.CSharpName (expr_type) + "'");
+                                  return null;
+                       }
+
+                       //
+                       // The operand of the prefix/postfix increment decrement operators
+                       // should be an expression that is classified as a variable,
+                       // a property access or an indexer access
+                       //
+                       type = expr_type;
+                       if (expr.eclass == ExprClass.Variable){
+                               LocalVariableReference var = expr as LocalVariableReference;
+                               if ((var != null) && var.IsReadOnly) {
+                                       Error (1604, "cannot assign to `" + var.Name + "' because it is readonly");
+                                       return null;
+                               }
+                       } else if (expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess){
+                               expr = expr.ResolveLValue (ec, this, Location);
+                               if (expr == null)
+                                       return null;
+                       } else {
+                               if (expr.eclass == ExprClass.Value) {
+                                       Error_ValueAssignment (loc);
+                               } else {
+                                       expr.Error_UnexpectedKind (ec.DeclContainer, "variable, indexer or property access", loc);
+                               }
+                               return null;
+                       }
+
+                       return this;
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       expr = expr.Resolve (ec);
+                       
+                       if (expr == null)
+                               return null;
+
+                       eclass = ExprClass.Value;
+
+#if GMCS_SOURCE
+                       if (TypeManager.IsNullableValueType (expr.Type))
+                               return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
+#endif
+
+                       return ResolveOperator (ec);
+               }
+
+               static int PtrTypeSize (Type t)
+               {
+                       return GetTypeSize (TypeManager.GetElementType (t));
+               }
+
+               //
+               // Loads the proper "1" into the stack based on the type, then it emits the
+               // opcode for the operation requested
+               //
+               void LoadOneAndEmitOp (EmitContext ec, Type t)
+               {
+                       //
+                       // Measure if getting the typecode and using that is more/less efficient
+                       // that comparing types.  t.GetTypeCode() is an internal call.
+                       //
+                       ILGenerator ig = ec.ig;
+                                                    
+                       if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
+                               LongConstant.EmitLong (ig, 1);
+                       else if (t == TypeManager.double_type)
+                               ig.Emit (OpCodes.Ldc_R8, 1.0);
+                       else if (t == TypeManager.float_type)
+                               ig.Emit (OpCodes.Ldc_R4, 1.0F);
+                       else if (t.IsPointer){
+                               int n = PtrTypeSize (t);
+                               
+                               if (n == 0)
+                                       ig.Emit (OpCodes.Sizeof, t);
+                               else
+                                       IntConstant.EmitInt (ig, n);
+                       } else 
+                               ig.Emit (OpCodes.Ldc_I4_1);
+
+                       //
+                       // Now emit the operation
+                       //
+                       if (ec.CheckState){
+                               if (t == TypeManager.int32_type ||
+                                   t == TypeManager.int64_type){
+                                       if ((mode & Mode.IsDecrement) != 0)
+                                               ig.Emit (OpCodes.Sub_Ovf);
+                                       else
+                                               ig.Emit (OpCodes.Add_Ovf);
+                               } else if (t == TypeManager.uint32_type ||
+                                          t == TypeManager.uint64_type){
+                                       if ((mode & Mode.IsDecrement) != 0)
+                                               ig.Emit (OpCodes.Sub_Ovf_Un);
+                                       else
+                                               ig.Emit (OpCodes.Add_Ovf_Un);
+                               } else {
+                                       if ((mode & Mode.IsDecrement) != 0)
+                                               ig.Emit (OpCodes.Sub_Ovf);
+                                       else
+                                               ig.Emit (OpCodes.Add_Ovf);
+                               }
+                       } else {
+                               if ((mode & Mode.IsDecrement) != 0)
+                                       ig.Emit (OpCodes.Sub);
+                               else
+                                       ig.Emit (OpCodes.Add);
+                       }
+
+                       if (t == TypeManager.sbyte_type){
+                               if (ec.CheckState)
+                                       ig.Emit (OpCodes.Conv_Ovf_I1);
+                               else
+                                       ig.Emit (OpCodes.Conv_I1);
+                       } else if (t == TypeManager.byte_type){
+                               if (ec.CheckState)
+                                       ig.Emit (OpCodes.Conv_Ovf_U1);
+                               else
+                                       ig.Emit (OpCodes.Conv_U1);
+                       } else if (t == TypeManager.short_type){
+                               if (ec.CheckState)
+                                       ig.Emit (OpCodes.Conv_Ovf_I2);
+                               else
+                                       ig.Emit (OpCodes.Conv_I2);
+                       } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
+                               if (ec.CheckState)
+                                       ig.Emit (OpCodes.Conv_Ovf_U2);
+                               else
+                                       ig.Emit (OpCodes.Conv_U2);
+                       }
+                       
+               }
+
+               void EmitCode (EmitContext ec, bool is_expr)
+               {
+                       recurse = true;
+                       this.is_expr = is_expr;
+                       ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       //
+                       // We use recurse to allow ourselfs to be the source
+                       // of an assignment. This little hack prevents us from
+                       // having to allocate another expression
+                       //
+                       if (recurse) {
+                               ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
+                               if (method == null)
+                                       LoadOneAndEmitOp (ec, expr.Type);
+                               else
+                                       ec.ig.Emit (OpCodes.Call, method.Method);
+                               recurse = false;
+                               return;
+                       }
+
+                       EmitCode (ec, true);
+               }
+
+               public override void EmitStatement (EmitContext ec)
+               {
+                       EmitCode (ec, false);
+               }
+       }
+
+       /// <summary>
+       ///   Base class for the `Is' and `As' classes. 
+       /// </summary>
+       ///
+       /// <remarks>
+       ///   FIXME: Split this in two, and we get to save the `Operator' Oper
+       ///   size. 
+       /// </remarks>
+       public abstract class Probe : Expression {
+               public Expression ProbeType;
+               protected Expression expr;
+               protected TypeExpr probe_type_expr;
+               
+               public Probe (Expression expr, Expression probe_type, Location l)
+               {
+                       ProbeType = probe_type;
+                       loc = l;
+                       this.expr = expr;
+               }
+
+               public Expression Expr {
+                       get {
+                               return expr;
+                       }
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
+                       if (probe_type_expr == null)
+                               return null;
+
+                       expr = expr.Resolve (ec);
+                       if (expr == null)
+                               return null;
+                       
+                       if (expr.Type.IsPointer) {
+                               Report.Error (244, loc, "\"is\" or \"as\" are not valid on pointer types");
+                               return null;
+                       }
+                       return this;
+               }
+       }
+
+       /// <summary>
+       ///   Implementation of the `is' operator.
+       /// </summary>
+       public class Is : Probe {
+               public Is (Expression expr, Expression probe_type, Location l)
+                       : base (expr, probe_type, l)
+               {
+               }
+
+               enum Action {
+                       AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
+               }
+
+               Action action;
+               
+               public override void Emit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+
+                       expr.Emit (ec);
+
+                       switch (action){
+                       case Action.AlwaysFalse:
+                               ig.Emit (OpCodes.Pop);
+                               IntConstant.EmitInt (ig, 0);
+                               return;
+                       case Action.AlwaysTrue:
+                               ig.Emit (OpCodes.Pop);
+                               IntConstant.EmitInt (ig, 1);
+                               return;
+                       case Action.LeaveOnStack:
+                               // the `e != null' rule.
+                               ig.Emit (OpCodes.Ldnull);
+                               ig.Emit (OpCodes.Ceq);
+                               ig.Emit (OpCodes.Ldc_I4_0);
+                               ig.Emit (OpCodes.Ceq);
+                               return;
+                       case Action.Probe:
+                               ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
+                               ig.Emit (OpCodes.Ldnull);
+                               ig.Emit (OpCodes.Cgt_Un);
+                               return;
+                       }
+                       throw new Exception ("never reached");
+               }
+
+               public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
+               {
+                       ILGenerator ig = ec.ig;
+
+                       switch (action){
+                       case Action.AlwaysFalse:
+                               if (! onTrue)
+                                       ig.Emit (OpCodes.Br, target);
+                               
+                               return;
+                       case Action.AlwaysTrue:
+                               if (onTrue)
+                                       ig.Emit (OpCodes.Br, target);
+                               
+                               return;
+                       case Action.LeaveOnStack:
+                               // the `e != null' rule.
+                               expr.Emit (ec);
+                               ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
+                               return;
+                       case Action.Probe:
+                               expr.Emit (ec);
+                               ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
+                               ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
+                               return;
+                       }
+                       throw new Exception ("never reached");
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       Expression e = base.DoResolve (ec);
+
+                       if ((e == null) || (expr == null))
+                               return null;
+
+                       Type etype = expr.Type;
+                       type = TypeManager.bool_type;
+                       eclass = ExprClass.Value;
+
+                       //
+                       // First case, if at compile time, there is an implicit conversion
+                       // then e != null (objects) or true (value types)
+                       //
+                       Type probe_type = probe_type_expr.Type;
+                       e = Convert.ImplicitConversionStandard (ec, expr, probe_type, loc);
+                       if (e != null){
+                               expr = e;
+                               if (etype.IsValueType)
+                                       action = Action.AlwaysTrue;
+                               else
+                                       action = Action.LeaveOnStack;
+
+                               Constant c = e as Constant;
+                               if (c != null && c.GetValue () == null) {
+                                       action = Action.AlwaysFalse;
+                                       Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
+                                               TypeManager.CSharpName (probe_type));
+                               } else {
+                                       Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
+                                               TypeManager.CSharpName (probe_type));
+                               }
+                               return this;
+                       }
+                       
+                       if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){
+                               if (TypeManager.IsGenericParameter (etype))
+                                       expr = new BoxedCast (expr, etype);
+
+                               //
+                               // Second case: explicit reference convresion
+                               //
+                               if (expr is NullLiteral)
+                                       action = Action.AlwaysFalse;
+                               else
+                                       action = Action.Probe;
+                       } else if (TypeManager.ContainsGenericParameters (etype) ||
+                                  TypeManager.ContainsGenericParameters (probe_type)) {
+                               expr = new BoxedCast (expr, etype);
+                               action = Action.Probe;
+                       } else {
+                               action = Action.AlwaysFalse;
+                               if (!(probe_type.IsInterface || expr.Type.IsInterface))
+                                       Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type", TypeManager.CSharpName (probe_type));
+                       }
+
+                       return this;
+               }
+       }
+
+       /// <summary>
+       ///   Implementation of the `as' operator.
+       /// </summary>
+       public class As : Probe {
+               public As (Expression expr, Expression probe_type, Location l)
+                       : base (expr, probe_type, l)
+               {
+               }
+
+               bool do_isinst = false;
+               Expression resolved_type;
+               
+               public override void Emit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+
+                       expr.Emit (ec);
+
+                       if (do_isinst)
+                               ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
+               }
+
+               static void Error_CannotConvertType (Type source, Type target, Location loc)
+               {
+                       Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
+                               TypeManager.CSharpName (source),
+                               TypeManager.CSharpName (target));
+               }
+               
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       if (resolved_type == null) {
+                               resolved_type = base.DoResolve (ec);
+
+                               if (resolved_type == null)
+                                       return null;
+                       }
+
+                       type = probe_type_expr.Type;
+                       eclass = ExprClass.Value;
+                       Type etype = expr.Type;
+
+                       if (type.IsValueType) {
+                               Report.Error (77, loc, "The as operator must be used with a reference type (`" +
+                                             TypeManager.CSharpName (type) + "' is a value type)");
+                               return null;
+                       
+                       }
+
+#if GMCS_SOURCE
+                       //
+                       // If the type is a type parameter, ensure
+                       // that it is constrained by a class
+                       //
+                       TypeParameterExpr tpe = probe_type_expr as TypeParameterExpr;
+                       if (tpe != null){
+                               Constraints constraints = tpe.TypeParameter.Constraints;
+                               bool error = false;
+                               
+                               if (constraints == null)
+                                       error = true;
+                               else {
+                                       if (!constraints.HasClassConstraint)
+                                               if ((constraints.Attributes & GenericParameterAttributes.ReferenceTypeConstraint) == 0)
+                                                       error = true;
+                               }
+                               if (error){
+                                       Report.Error (413, loc,
+                                                     "The as operator requires that the `{0}' type parameter be constrained by a class",
+                                                     probe_type_expr.GetSignatureForError ());
+                                       return null;
+                               }
+                       }
+#endif
+                       
+                       Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
+                       if (e != null){
+                               expr = e;
+                               do_isinst = false;
+                               return this;
+                       }
+
+                       if (Convert.ExplicitReferenceConversionExists (etype, type)){
+                               if (TypeManager.IsGenericParameter (etype))
+                                       expr = new BoxedCast (expr, etype);
+
+                               do_isinst = true;
+                               return this;
+                       }
+
+                       if (TypeManager.ContainsGenericParameters (etype) ||
+                           TypeManager.ContainsGenericParameters (type)) {
+                               expr = new BoxedCast (expr, etype);
+                               do_isinst = true;
+                               return this;
+                       }
+
+                       Error_CannotConvertType (etype, type, loc);
+                       return null;
+               }
+       
+               public override bool GetAttributableValue (Type valueType, out object value)
+               {
+                       return expr.GetAttributableValue (valueType, out value);
+               }
+       }
+       
+       /// <summary>
+       ///   This represents a typecast in the source language.
+       ///
+       ///   FIXME: Cast expressions have an unusual set of parsing
+       ///   rules, we need to figure those out.
+       /// </summary>
+       public class Cast : Expression {
+               Expression target_type;
+               Expression expr;
+                       
+               public Cast (Expression cast_type, Expression expr)
+                       : this (cast_type, expr, cast_type.Location)
+               {
+               }
+
+               public Cast (Expression cast_type, Expression expr, Location loc)
+               {
+                       this.target_type = cast_type;
+                       this.expr = expr;
+                       this.loc = loc;
+
+                       if (target_type == TypeManager.system_void_expr)
+                               Error_VoidInvalidInTheContext (loc);
+               }
+
+               public Expression TargetType {
+                       get { return target_type; }
+               }
+
+               public Expression Expr {
+                       get { return expr; }
+                       set { expr = value; }
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       expr = expr.Resolve (ec);
+                       if (expr == null)
+                               return null;
+
+                       TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
+                       if (target == null)
+                               return null;
+
+                       type = target.Type;
+
+                       if (type.IsAbstract && type.IsSealed) {
+                               Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
+                               return null;
+                       }
+
+                       eclass = ExprClass.Value;
+
+                       Constant c = expr as Constant;
+                       if (c != null) {
+                               try {
+                                       c = c.TryReduce (ec, type, loc);
+                                       if (c != null)
+                                               return c;
+                               }
+                               catch (OverflowException) {
+                                       return null;
+                               }
+                       }
+
+                       if (type.IsPointer && !ec.InUnsafe) {
+                               UnsafeError (loc);
+                               return null;
+                       }
+                       expr = Convert.ExplicitConversion (ec, expr, type, loc);
+                       return expr;
+               }
+               
+               public override void Emit (EmitContext ec)
+               {
+                       throw new Exception ("Should not happen");
+               }
+       }
+
+       /// <summary>
+       ///   Binary operators
+       /// </summary>
+       public class Binary : Expression {
+               public enum Operator : byte {
+                       Multiply, Division, Modulus,
+                       Addition, Subtraction,
+                       LeftShift, RightShift,
+                       LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual, 
+                       Equality, Inequality,
+                       BitwiseAnd,
+                       ExclusiveOr,
+                       BitwiseOr,
+                       LogicalAnd,
+                       LogicalOr,
+                       TOP
+               }
+
+               Operator oper;
+               Expression left, right;
+
+               // This must be kept in sync with Operator!!!
+               public static readonly string [] oper_names;
+               
+               static Binary ()
+               {
+                       oper_names = new string [(int) Operator.TOP];
+
+                       oper_names [(int) Operator.Multiply] = "op_Multiply";
+                       oper_names [(int) Operator.Division] = "op_Division";
+                       oper_names [(int) Operator.Modulus] = "op_Modulus";
+                       oper_names [(int) Operator.Addition] = "op_Addition";
+                       oper_names [(int) Operator.Subtraction] = "op_Subtraction";
+                       oper_names [(int) Operator.LeftShift] = "op_LeftShift";
+                       oper_names [(int) Operator.RightShift] = "op_RightShift";
+                       oper_names [(int) Operator.LessThan] = "op_LessThan";
+                       oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
+                       oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
+                       oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
+                       oper_names [(int) Operator.Equality] = "op_Equality";
+                       oper_names [(int) Operator.Inequality] = "op_Inequality";
+                       oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
+                       oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
+                       oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
+                       oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
+                       oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
+               }
+
+               public Binary (Operator oper, Expression left, Expression right)
+               {
+                       this.oper = oper;
+                       this.left = left;
+                       this.right = right;
+                       this.loc = left.Location;
+               }
+
+               public Operator Oper {
+                       get {
+                               return oper;
+                       }
+                       set {
+                               oper = value;
+                       }
+               }
+               
+               public Expression Left {
+                       get {
+                               return left;
+                       }
+                       set {
+                               left = value;
+                       }
+               }
+
+               public Expression Right {
+                       get {
+                               return right;
+                       }
+                       set {
+                               right = value;
+                       }
+               }
+
+
+               /// <summary>
+               ///   Returns a stringified representation of the Operator
+               /// </summary>
+               public static string OperName (Operator oper)
+               {
+                       switch (oper){
+                       case Operator.Multiply:
+                               return "*";
+                       case Operator.Division:
+                               return "/";
+                       case Operator.Modulus:
+                               return "%";
+                       case Operator.Addition:
+                               return "+";
+                       case Operator.Subtraction:
+                               return "-";
+                       case Operator.LeftShift:
+                               return "<<";
+                       case Operator.RightShift:
+                               return ">>";
+                       case Operator.LessThan:
+                               return "<";
+                       case Operator.GreaterThan:
+                               return ">";
+                       case Operator.LessThanOrEqual:
+                               return "<=";
+                       case Operator.GreaterThanOrEqual:
+                               return ">=";
+                       case Operator.Equality:
+                               return "==";
+                       case Operator.Inequality:
+                               return "!=";
+                       case Operator.BitwiseAnd:
+                               return "&";
+                       case Operator.BitwiseOr:
+                               return "|";
+                       case Operator.ExclusiveOr:
+                               return "^";
+                       case Operator.LogicalOr:
+                               return "||";
+                       case Operator.LogicalAnd:
+                               return "&&";
+                       }
+
+                       return oper.ToString ();
+               }
+
+               public override string ToString ()
+               {
+                       return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
+                               right.ToString () + ")";
+               }
+               
+               Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
+               {
+                       if (expr.Type == target_type)
+                               return expr;
+
+                       return Convert.ImplicitConversion (ec, expr, target_type, loc);
+               }
+
+               public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
+               {
+                       Report.Error (
+                               34, loc, "Operator `" + OperName (oper) 
+                               + "' is ambiguous on operands of type `"
+                               + TypeManager.CSharpName (l) + "' "
+                               + "and `" + TypeManager.CSharpName (r)
+                               + "'");
+               }
+
+               bool IsConvertible (EmitContext ec, Expression le, Expression re, Type t)
+               {
+                       return Convert.ImplicitConversionExists (ec, le, t) && Convert.ImplicitConversionExists (ec, re, t);
+               }
+
+               bool VerifyApplicable_Predefined (EmitContext ec, Type t)
+               {
+                       if (!IsConvertible (ec, left, right, t))
+                               return false;
+                       left = ForceConversion (ec, left, t);
+                       right = ForceConversion (ec, right, t);
+                       type = t;
+                       return true;
+               }
+
+               bool IsApplicable_String (EmitContext ec, Expression le, Expression re, Operator oper)
+               {
+                       bool l = Convert.ImplicitConversionExists (ec, le, TypeManager.string_type);
+                       bool r = Convert.ImplicitConversionExists (ec, re, TypeManager.string_type);
+
+                       if (oper == Operator.Equality || oper == Operator.Inequality)
+                               return l && r;
+                       if (oper == Operator.Addition)
+                               return l || r;
+                       return false;
+               }
+
+               bool OverloadResolve_PredefinedString (EmitContext ec, Operator oper)
+               {
+                       if (!IsApplicable_String (ec, left, right, oper))
+                               return false;
+                       Type t = TypeManager.string_type;
+                       if (Convert.ImplicitConversionExists (ec, left, t))
+                               left = ForceConversion (ec, left, t);
+                       if (Convert.ImplicitConversionExists (ec, right, t))
+                               right = ForceConversion (ec, right, t);
+                       type = t;
+                       return true;
+               }
+
+               bool OverloadResolve_PredefinedIntegral (EmitContext ec)
+               {
+                       return VerifyApplicable_Predefined (ec, TypeManager.int32_type) ||
+                               VerifyApplicable_Predefined (ec, TypeManager.uint32_type) ||
+                               VerifyApplicable_Predefined (ec, TypeManager.int64_type) ||
+                               VerifyApplicable_Predefined (ec, TypeManager.uint64_type) ||
+                               false;
+               }
+
+               bool OverloadResolve_PredefinedFloating (EmitContext ec)
+               {
+                       return VerifyApplicable_Predefined (ec, TypeManager.float_type) ||
+                               VerifyApplicable_Predefined (ec, TypeManager.double_type) ||
+                               false;
+               }
+
+               static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
+               {
+                       Error_OperatorCannotBeApplied (loc, name, TypeManager.CSharpName (l), TypeManager.CSharpName (r));
+               }
+
+               public static void Error_OperatorCannotBeApplied (Location loc, string name, string left, string right)
+               {
+                       Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
+                               name, left, right);
+               }
+               
+               void Error_OperatorCannotBeApplied ()
+               {
+                       Error_OperatorCannotBeApplied (Location, OperName (oper), TypeManager.CSharpName (left.Type),
+                               TypeManager.CSharpName(right.Type));
+               }
+
+               static bool is_unsigned (Type t)
+               {
+                       return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
+                               t == TypeManager.short_type || t == TypeManager.byte_type);
+               }
+
+               Expression Make32or64 (EmitContext ec, Expression e)
+               {
+                       Type t= e.Type;
+                       
+                       if (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
+                           t == TypeManager.int64_type || t == TypeManager.uint64_type)
+                               return e;
+                       Expression ee = Convert.ImplicitConversion (ec, e, TypeManager.int32_type, loc);
+                       if (ee != null)
+                               return ee;
+                       ee = Convert.ImplicitConversion (ec, e, TypeManager.uint32_type, loc);
+                       if (ee != null)
+                               return ee;
+                       ee = Convert.ImplicitConversion (ec, e, TypeManager.int64_type, loc);
+                       if (ee != null)
+                               return ee;
+                       ee = Convert.ImplicitConversion (ec, e, TypeManager.uint64_type, loc);
+                       if (ee != null)
+                               return ee;
+                       return null;
+               }
+                                       
+               Expression CheckShiftArguments (EmitContext ec)
+               {
+                       Expression new_left = Make32or64 (ec, left);
+                       Expression new_right = ForceConversion (ec, right, TypeManager.int32_type);
+                       if (new_left == null || new_right == null) {
+                               Error_OperatorCannotBeApplied ();
+                               return null;
+                       }
+                       type = new_left.Type;
+                       int shiftmask = (type == TypeManager.int32_type || type == TypeManager.uint32_type) ? 31 : 63;
+                       left = new_left;
+                       right = new Binary (Binary.Operator.BitwiseAnd, new_right, new IntConstant (shiftmask, loc)).DoResolve (ec);
+                       return this;
+               }
+
+               //
+               // This is used to check if a test 'x == null' can be optimized to a reference equals,
+               // i.e., not invoke op_Equality.
+               //
+               static bool EqualsNullIsReferenceEquals (Type t)
+               {
+                       return t == TypeManager.object_type || t == TypeManager.string_type ||
+                               t == TypeManager.delegate_type || t.IsSubclassOf (TypeManager.delegate_type);
+               }
+
+               static void Warning_UnintendedReferenceComparison (Location loc, string side, Type type)
+               {
+                       Report.Warning ((side == "left" ? 252 : 253), 2, loc,
+                               "Possible unintended reference comparison; to get a value comparison, " +
+                               "cast the {0} hand side to type `{1}'.", side, TypeManager.CSharpName (type));
+               }
+
+               Expression ResolveOperator (EmitContext ec)
+               {
+                       Type l = left.Type;
+                       Type r = right.Type;
+
+                       if (oper == Operator.Equality || oper == Operator.Inequality){
+                               if (TypeManager.IsGenericParameter (l) && (right is NullLiteral)) {
+                                       if (l.BaseType == TypeManager.value_type) {
+                                               Error_OperatorCannotBeApplied ();
+                                               return null;
+                                       }
+
+                                       left = new BoxedCast (left, TypeManager.object_type);
+                                       Type = TypeManager.bool_type;
+                                       return this;
+                               }
+
+                               if (TypeManager.IsGenericParameter (r) && (left is NullLiteral)) {
+                                       if (r.BaseType == TypeManager.value_type) {
+                                               Error_OperatorCannotBeApplied ();
+                                               return null;
+                                       }
+
+                                       right = new BoxedCast (right, TypeManager.object_type);
+                                       Type = TypeManager.bool_type;
+                                       return this;
+                               }
+
+                               //
+                               // Optimize out call to op_Equality in a few cases.
+                               //
+                               if ((l == TypeManager.null_type && EqualsNullIsReferenceEquals (r)) ||
+                                   (r == TypeManager.null_type && EqualsNullIsReferenceEquals (l))) {
+                                       Type = TypeManager.bool_type;
+                                       return this;
+                               }
+
+                               // IntPtr equality
+                               if (l == TypeManager.intptr_type && r == TypeManager.intptr_type) {
+                                       Type = TypeManager.bool_type;
+                                       return this;
+                               }
+                       }
+
+                       //
+                       // Do not perform operator overload resolution when both sides are
+                       // built-in types
+                       //
+                       Expression left_operators = null, right_operators = null;
+                       if (!(TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r))) {
+                               //
+                               // Step 1: Perform Operator Overload location
+                               //
+                               string op = oper_names [(int) oper];
+
+                               MethodGroupExpr union;
+                               left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc);
+                               if (r != l){
+                                       right_operators = MemberLookup (
+                                               ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc);
+                                       union = Invocation.MakeUnionSet (left_operators, right_operators, loc);
+                               } else
+                                       union = (MethodGroupExpr) left_operators;
+
+                               if (union != null) {
+                                       ArrayList args = new ArrayList (2);
+                                       args.Add (new Argument (left, Argument.AType.Expression));
+                                       args.Add (new Argument (right, Argument.AType.Expression));
+
+                                       MethodBase method = Invocation.OverloadResolve (ec, union, args, true, Location.Null);
+
+                                       if (method != null) {
+                                               MethodInfo mi = (MethodInfo) method;
+                                               return new BinaryMethod (mi.ReturnType, method, args);
+                                       }
+                               }
+                       }
+
+                       //
+                       // Step 0: String concatenation (because overloading will get this wrong)
+                       //
+                       if (oper == Operator.Addition){
+                               //
+                               // If any of the arguments is a string, cast to string
+                               //
+                               
+                               // Simple constant folding
+                               if (left is StringConstant && right is StringConstant)
+                                       return new StringConstant (((StringConstant) left).Value + ((StringConstant) right).Value, left.Location);
+                               
+                               if (l == TypeManager.string_type || r == TypeManager.string_type) {
+
+                                       if (r == TypeManager.void_type || l == TypeManager.void_type) {
+                                               Error_OperatorCannotBeApplied ();
+                                               return null;
+                                       }
+
+                                       // try to fold it in on the left
+                                       if (left is StringConcat) {
+
+                                               //
+                                               // We have to test here for not-null, since we can be doubly-resolved
+                                               // take care of not appending twice
+                                               //
+                                               if (type == null){
+                                                       type = TypeManager.string_type;
+                                                       ((StringConcat) left).Append (ec, right);
+                                                       return left.Resolve (ec);
+                                               } else {
+                                                       return left;
+                                               }
+                                       }
+
+                                       // Otherwise, start a new concat expression
+                                       return new StringConcat (ec, loc, left, right).Resolve (ec);
+                               }
+
+                               //
+                               // Transform a + ( - b) into a - b
+                               //
+                               if (right is Unary){
+                                       Unary right_unary = (Unary) right;
+
+                                       if (right_unary.Oper == Unary.Operator.UnaryNegation){
+                                               oper = Operator.Subtraction;
+                                               right = right_unary.Expr;
+                                               r = right.Type;
+                                       }
+                               }
+                       }
+
+                       if (oper == Operator.Equality || oper == Operator.Inequality){
+                               if (l == TypeManager.bool_type || r == TypeManager.bool_type){
+                                       if (r != TypeManager.bool_type || l != TypeManager.bool_type){
+                                               Error_OperatorCannotBeApplied ();
+                                               return null;
+                                       }
+
+                                       type = TypeManager.bool_type;
+                                       return this;
+                               }
+
+                               if (l.IsPointer || r.IsPointer) {
+                                       if (l.IsPointer && r.IsPointer) {
+                                               type = TypeManager.bool_type;
+                                               return this;
+                                       }
+
+                                       if (l.IsPointer && r == TypeManager.null_type) {
+                                               right = new EmptyCast (NullPointer.Null, l);
+                                               type = TypeManager.bool_type;
+                                               return this;
+                                       }
+
+                                       if (r.IsPointer && l == TypeManager.null_type) {
+                                               left = new EmptyCast (NullPointer.Null, r);
+                                               type = TypeManager.bool_type;
+                                               return this;
+                                       }
+                               }
+
+#if GMCS_SOURCE
+                               if (l.IsGenericParameter && r.IsGenericParameter) {
+                                       GenericConstraints l_gc, r_gc;
+
+                                       l_gc = TypeManager.GetTypeParameterConstraints (l);
+                                       r_gc = TypeManager.GetTypeParameterConstraints (r);
+
+                                       if ((l_gc == null) || (r_gc == null) ||
+                                           !(l_gc.HasReferenceTypeConstraint || l_gc.HasClassConstraint) ||
+                                           !(r_gc.HasReferenceTypeConstraint || r_gc.HasClassConstraint)) {
+                                               Error_OperatorCannotBeApplied ();
+                                               return null;
+                                       }
+
+                               }
+#endif
+
+                               //
+                               // operator != (object a, object b)
+                               // operator == (object a, object b)
+                               //
+                               // For this to be used, both arguments have to be reference-types.
+                               // Read the rationale on the spec (14.9.6)
+                               //
+                               if (!(l.IsValueType || r.IsValueType)){
+                                       type = TypeManager.bool_type;
+
+                                       if (l == r)
+                                               return this;
+                                       
+                                       //
+                                       // Also, a standard conversion must exist from either one
+                                       //
+                                       bool left_to_right =
+                                               Convert.ImplicitStandardConversionExists (left, r);
+                                       bool right_to_left = !left_to_right &&
+                                               Convert.ImplicitStandardConversionExists (right, l);
+
+                                       if (!left_to_right && !right_to_left) {
+                                               Error_OperatorCannotBeApplied ();
+                                               return null;
+                                       }
+
+                                       if (left_to_right && left_operators != null &&
+                                           RootContext.WarningLevel >= 2) {
+                                               ArrayList args = new ArrayList (2);
+                                               args.Add (new Argument (left, Argument.AType.Expression));
+                                               args.Add (new Argument (left, Argument.AType.Expression));
+                                               MethodBase method = Invocation.OverloadResolve (
+                                                       ec, (MethodGroupExpr) left_operators, args, true, Location.Null);
+                                               if (method != null)
+                                                       Warning_UnintendedReferenceComparison (loc, "right", l);
+                                       }
+
+                                       if (right_to_left && right_operators != null &&
+                                           RootContext.WarningLevel >= 2) {
+                                               ArrayList args = new ArrayList (2);
+                                               args.Add (new Argument (right, Argument.AType.Expression));
+                                               args.Add (new Argument (right, Argument.AType.Expression));
+                                               MethodBase method = Invocation.OverloadResolve (
+                                                       ec, (MethodGroupExpr) right_operators, args, true, Location.Null);
+                                               if (method != null)
+                                                       Warning_UnintendedReferenceComparison (loc, "left", r);
+                                       }
+
+                                       //
+                                       // We are going to have to convert to an object to compare
+                                       //
+                                       if (l != TypeManager.object_type)
+                                               left = new EmptyCast (left, TypeManager.object_type);
+                                       if (r != TypeManager.object_type)
+                                               right = new EmptyCast (right, TypeManager.object_type);
+
+                                       return this;
+                               }
+                       }
+
+                       // Only perform numeric promotions on:
+                       // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
+                       //
+                       if (oper == Operator.Addition || oper == Operator.Subtraction) {
+                               if (TypeManager.IsDelegateType (l)){
+                                       if (((right.eclass == ExprClass.MethodGroup) ||
+                                            (r == TypeManager.anonymous_method_type))){
+                                               if ((RootContext.Version != LanguageVersion.ISO_1)){
+                                                       Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
+                                                       if (tmp == null)
+                                                               return null;
+                                                       right = tmp;
+                                                       r = right.Type;
+                                               }
+                                       }
+
+                                       if (TypeManager.IsDelegateType (r) || right is NullLiteral){
+                                               MethodInfo method;
+                                               ArrayList args = new ArrayList (2);
+                                       
+                                               args = new ArrayList (2);
+                                               args.Add (new Argument (left, Argument.AType.Expression));
+                                               args.Add (new Argument (right, Argument.AType.Expression));
+                                       
+                                               if (oper == Operator.Addition)
+                                                       method = TypeManager.delegate_combine_delegate_delegate;
+                                               else
+                                                       method = TypeManager.delegate_remove_delegate_delegate;
+
+                                               if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral)) {
+                                                       Error_OperatorCannotBeApplied ();
+                                                       return null;
+                                               }
+
+                                               return new BinaryDelegate (l, method, args);
+                                       }
+                               }
+
+                               //
+                               // Pointer arithmetic:
+                               //
+                               // T* operator + (T* x, int y);
+                               // T* operator + (T* x, uint y);
+                               // T* operator + (T* x, long y);
+                               // T* operator + (T* x, ulong y);
+                               //
+                               // T* operator + (int y,   T* x);
+                               // T* operator + (uint y,  T *x);
+                               // T* operator + (long y,  T *x);
+                               // T* operator + (ulong y, T *x);
+                               //
+                               // T* operator - (T* x, int y);
+                               // T* operator - (T* x, uint y);
+                               // T* operator - (T* x, long y);
+                               // T* operator - (T* x, ulong y);
+                               //
+                               // long operator - (T* x, T *y)
+                               //
+                               if (l.IsPointer){
+                                       if (r.IsPointer && oper == Operator.Subtraction){
+                                               if (r == l)
+                                                       return new PointerArithmetic (
+                                                               false, left, right, TypeManager.int64_type,
+                                                               loc).Resolve (ec);
+                                       } else {
+                                               Expression t = Make32or64 (ec, right);
+                                               if (t != null)
+                                                       return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc).Resolve (ec);
+                                       }
+                               } else if (r.IsPointer && oper == Operator.Addition){
+                                       Expression t = Make32or64 (ec, left);
+                                       if (t != null)
+                                               return new PointerArithmetic (true, right, t, r, loc).Resolve (ec);
+                               }
+                       }
+                       
+                       //
+                       // Enumeration operators
+                       //
+                       bool lie = TypeManager.IsEnumType (l);
+                       bool rie = TypeManager.IsEnumType (r);
+                       if (lie || rie){
+                               Expression temp;
+
+                               // U operator - (E e, E f)
+                               if (lie && rie){
+                                       if (oper == Operator.Subtraction){
+                                               if (l == r){
+                                                       type = TypeManager.EnumToUnderlying (l);
+                                                       return this;
+                                               }
+                                               Error_OperatorCannotBeApplied ();
+                                               return null;
+                                       }
+                               }
+                                       
+                               //
+                               // operator + (E e, U x)
+                               // operator - (E e, U x)
+                               //
+                               if (oper == Operator.Addition || oper == Operator.Subtraction){
+                                       Type enum_type = lie ? l : r;
+                                       Type other_type = lie ? r : l;
+                                       Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
+                                       
+                                       if (underlying_type != other_type){
+                                               temp = Convert.ImplicitConversion (ec, lie ? right : left, underlying_type, loc);
+                                               if (temp != null){
+                                                       if (lie)
+                                                               right = temp;
+                                                       else
+                                                               left = temp;
+                                                       type = enum_type;
+                                                       return this;
+                                               }
+                                                       
+                                               Error_OperatorCannotBeApplied ();
+                                               return null;
+                                       }
+
+                                       type = enum_type;
+                                       return this;
+                               }
+                               
+                               if (!rie){
+                                       temp = Convert.ImplicitConversion (ec, right, l, loc);
+                                       if (temp != null)
+                                               right = temp;
+                                       else {
+                                               Error_OperatorCannotBeApplied ();
+                                               return null;
+                                       }
+                               } if (!lie){
+                                       temp = Convert.ImplicitConversion (ec, left, r, loc);
+                                       if (temp != null){
+                                               left = temp;
+                                               l = r;
+                                       } else {
+                                               Error_OperatorCannotBeApplied ();
+                                               return null;
+                                       }
+                               }
+
+                               if (oper == Operator.Equality || oper == Operator.Inequality ||
+                                   oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
+                                   oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
+                                       if (left.Type != right.Type){
+                                               Error_OperatorCannotBeApplied ();
+                                               return null;
+                                       }
+                                       type = TypeManager.bool_type;
+                                       return this;
+                               }
+
+                               if (oper == Operator.BitwiseAnd ||
+                                   oper == Operator.BitwiseOr ||
+                                   oper == Operator.ExclusiveOr){
+                                       if (left.Type != right.Type){
+                                               Error_OperatorCannotBeApplied ();
+                                               return null;
+                                       }
+                                       type = l;
+                                       return this;
+                               }
+                               Error_OperatorCannotBeApplied ();
+                               return null;
+                       }
+                       
+                       if (oper == Operator.LeftShift || oper == Operator.RightShift)
+                               return CheckShiftArguments (ec);
+
+                       if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
+                               if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
+                                       type = TypeManager.bool_type;
+                                       return this;
+                               }
+
+                               if (l != r) {
+                                       Error_OperatorCannotBeApplied ();
+                                       return null;
+                               }
+
+                               Expression e = new ConditionalLogicalOperator (
+                                       oper == Operator.LogicalAnd, left, right, l, loc);
+                               return e.Resolve (ec);
+                       } 
+
+                       Expression orig_left = left;
+                       Expression orig_right = right;
+
+                       //
+                       // operator & (bool x, bool y)
+                       // operator | (bool x, bool y)
+                       // operator ^ (bool x, bool y)
+                       //
+                       if (oper == Operator.BitwiseAnd ||
+                           oper == Operator.BitwiseOr ||
+                           oper == Operator.ExclusiveOr) {
+                               if (OverloadResolve_PredefinedIntegral (ec)) {
+                                       if (IsConvertible (ec, orig_left, orig_right, TypeManager.bool_type)) {
+                                               Error_OperatorAmbiguous (loc, oper, l, r);
+                                               return null;
+                                       }
+
+                                       if (oper == Operator.BitwiseOr && l != r && !(orig_right is Constant) && right is OpcodeCast &&
+                                               (r == TypeManager.sbyte_type || r == TypeManager.short_type ||
+                                                r == TypeManager.int32_type || r == TypeManager.int64_type)) {
+                                                       Report.Warning (675, 3, loc, "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
+                                                               TypeManager.CSharpName (r));
+                                       }
+                                       
+                               } else if (!VerifyApplicable_Predefined (ec, TypeManager.bool_type)) {
+                                       Error_OperatorCannotBeApplied ();
+                                       return null;
+                               }
+                               return this;
+                       }
+                       
+                       //
+                       // Pointer comparison
+                       //
+                       if (l.IsPointer && r.IsPointer){
+                               if (oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
+                                   oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
+                                       type = TypeManager.bool_type;
+                                       return this;
+                               }
+                       }
+
+                       if (OverloadResolve_PredefinedIntegral (ec)) {
+                               if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
+                                       Error_OperatorAmbiguous (loc, oper, l, r);
+                                       return null;
+                               }
+                       } else if (OverloadResolve_PredefinedFloating (ec)) {
+                               if (IsConvertible (ec, orig_left, orig_right, TypeManager.decimal_type) ||
+                                   IsApplicable_String (ec, orig_left, orig_right, oper)) {
+                                       Error_OperatorAmbiguous (loc, oper, l, r);
+                                       return null;
+                               }
+                       } else if (VerifyApplicable_Predefined (ec, TypeManager.decimal_type)) {
+                               if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
+                                       Error_OperatorAmbiguous (loc, oper, l, r);
+                                       return null;
+                               }
+                       } else if (!OverloadResolve_PredefinedString (ec, oper)) {
+                               Error_OperatorCannotBeApplied ();
+                               return null;
+                       }
+
+                       if (oper == Operator.Equality ||
+                           oper == Operator.Inequality ||
+                           oper == Operator.LessThanOrEqual ||
+                           oper == Operator.LessThan ||
+                           oper == Operator.GreaterThanOrEqual ||
+                           oper == Operator.GreaterThan)
+                               type = TypeManager.bool_type;
+
+                       l = left.Type;
+                       r = right.Type;
+
+                       if (l == TypeManager.decimal_type || l == TypeManager.string_type || r == TypeManager.string_type) {
+                               Type lookup = l;
+                               if (r == TypeManager.string_type)
+                                       lookup = r;
+                               MethodGroupExpr ops = (MethodGroupExpr) MemberLookup (
+                                       ec.ContainerType, lookup, oper_names [(int) oper],
+                                       MemberTypes.Method, AllBindingFlags, loc);
+                               ArrayList args = new ArrayList (2);
+                               args.Add (new Argument (left, Argument.AType.Expression));
+                               args.Add (new Argument (right, Argument.AType.Expression));
+                               MethodBase method = Invocation.OverloadResolve (ec, ops, args, true, Location.Null);
+                               return new BinaryMethod (type, method, args);
+                       }
+
+                       return this;
+               }
+
+               Constant EnumLiftUp (Constant left, Constant right)
+               {
+                       switch (oper) {
+                               case Operator.BitwiseOr:
+                               case Operator.BitwiseAnd:
+                               case Operator.ExclusiveOr:
+                               case Operator.Equality:
+                               case Operator.Inequality:
+                               case Operator.LessThan:
+                               case Operator.LessThanOrEqual:
+                               case Operator.GreaterThan:
+                               case Operator.GreaterThanOrEqual:
+                                       if (left is EnumConstant)
+                                               return left;
+
+                                       if (left.IsZeroInteger)
+                                               return new EnumConstant (left, right.Type);
+
+                                       break;
+
+                               case Operator.Addition:
+                               case Operator.Subtraction:
+                                       return left;
+
+                               case Operator.Multiply:
+                               case Operator.Division:
+                               case Operator.Modulus:
+                               case Operator.LeftShift:
+                               case Operator.RightShift:
+                                       if (right is EnumConstant || left is EnumConstant)
+                                               break;
+                                       return left;
+                       }
+                       Error_OperatorCannotBeApplied (loc, Binary.OperName (oper), left.Type, right.Type);
+                       return null;
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       if (left == null)
+                               return null;
+
+                       if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
+                               left = ((ParenthesizedExpression) left).Expr;
+                               left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
+                               if (left == null)
+                                       return null;
+
+                               if (left.eclass == ExprClass.Type) {
+                                       Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
+                                       return null;
+                               }
+                       } else
+                               left = left.Resolve (ec);
+
+                       if (left == null)
+                               return null;
+
+                       Constant lc = left as Constant;
+                       if (lc != null && lc.Type == TypeManager.bool_type && 
+                               ((oper == Operator.LogicalAnd && (bool)lc.GetValue () == false) ||
+                                (oper == Operator.LogicalOr && (bool)lc.GetValue () == true))) {
+
+                               // TODO: make a sense to resolve unreachable expression as we do for statement
+                               Report.Warning (429, 4, loc, "Unreachable expression code detected");
+                               return left;
+                       }
+
+                       right = right.Resolve (ec);
+                       if (right == null)
+                               return null;
+
+                       eclass = ExprClass.Value;
+                       Constant rc = right as Constant;
+
+                       // The conversion rules are ignored in enum context but why
+                       if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
+                               left = lc = EnumLiftUp (lc, rc);
+                               if (lc == null)
+                                       return null;
+
+                               right = rc = EnumLiftUp (rc, lc);
+                               if (rc == null)
+                                       return null;
+                       }
+
+                       if (oper == Operator.BitwiseAnd) {
+                               if (rc != null && rc.IsZeroInteger) {
+                                       return lc is EnumConstant ?
+                                               new EnumConstant (rc, lc.Type):
+                                               rc;
+                               }
+
+                               if (lc != null && lc.IsZeroInteger) {
+                                       return rc is EnumConstant ?
+                                               new EnumConstant (lc, rc.Type):
+                                               lc;
+                               }
+                       }
+                       else if (oper == Operator.BitwiseOr) {
+                               if (lc is EnumConstant &&
+                                   rc != null && rc.IsZeroInteger)
+                                       return lc;
+                               if (rc is EnumConstant &&
+                                   lc != null && lc.IsZeroInteger)
+                                       return rc;
+                       } else if (oper == Operator.LogicalAnd) {
+                               if (rc != null && rc.IsDefaultValue && rc.Type == TypeManager.bool_type)
+                                       return rc;
+                               if (lc != null && lc.IsDefaultValue && lc.Type == TypeManager.bool_type)
+                                       return lc;
+                       }
+
+                       if (rc != null && lc != null){
+                               int prev_e = Report.Errors;
+                               Expression e = ConstantFold.BinaryFold (
+                                       ec, oper, lc, rc, loc);
+                               if (e != null || Report.Errors != prev_e)
+                                       return e;
+                       }
+
+#if GMCS_SOURCE
+                       if ((left is NullLiteral || left.Type.IsValueType) &&
+                           (right is NullLiteral || right.Type.IsValueType) &&
+                           !(left is NullLiteral && right is NullLiteral) &&
+                           (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type)))
+                               return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
+#endif
+
+                       // Comparison warnings
+                       if (oper == Operator.Equality || oper == Operator.Inequality ||
+                           oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
+                           oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
+                               if (left.Equals (right)) {
+                                       Report.Warning (1718, 3, loc, "Comparison made to same variable; did you mean to compare something else?");
+                               }
+                               CheckUselessComparison (lc, right.Type);
+                               CheckUselessComparison (rc, left.Type);
+                       }
+
+                       return ResolveOperator (ec);
+               }
+
+               public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
+               {
+                       return null;
+               }
+
+               private void CheckUselessComparison (Constant c, Type type)
+               {
+                       if (c == null || !IsTypeIntegral (type)
+                               || c is StringConstant
+                               || c is BoolConstant
+                               || c is CharConstant
+                               || c is FloatConstant
+                               || c is DoubleConstant
+                               || c is DecimalConstant
+                               )
+                               return;
+
+                       long value = 0;
+
+                       if (c is ULongConstant) {
+                               ulong uvalue = ((ULongConstant) c).Value;
+                               if (uvalue > long.MaxValue) {
+                                       if (type == TypeManager.byte_type ||
+                                           type == TypeManager.sbyte_type ||
+                                           type == TypeManager.short_type ||
+                                           type == TypeManager.ushort_type ||
+                                           type == TypeManager.int32_type ||
+                                           type == TypeManager.uint32_type ||
+                                           type == TypeManager.int64_type)
+                                               WarnUselessComparison (type);
+                                       return;
+                               }
+                               value = (long) uvalue;
+                       }
+                       else if (c is ByteConstant)
+                               value = ((ByteConstant) c).Value;
+                       else if (c is SByteConstant)
+                               value = ((SByteConstant) c).Value;
+                       else if (c is ShortConstant)
+                               value = ((ShortConstant) c).Value;
+                       else if (c is UShortConstant)
+                               value = ((UShortConstant) c).Value;
+                       else if (c is IntConstant)
+                               value = ((IntConstant) c).Value;
+                       else if (c is UIntConstant)
+                               value = ((UIntConstant) c).Value;
+                       else if (c is LongConstant)
+                               value = ((LongConstant) c).Value;
+
+                       if (value != 0) {
+                               if (IsValueOutOfRange (value, type))
+                                       WarnUselessComparison (type);
+                               return;
+                       }
+               }
+
+               private bool IsValueOutOfRange (long value, Type type)
+               {
+                       if (IsTypeUnsigned (type) && value < 0)
+                               return true;
+                       return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
+                               type == TypeManager.byte_type && value >= 0x100 ||
+                               type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
+                               type == TypeManager.ushort_type && value >= 0x10000 ||
+                               type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
+                               type == TypeManager.uint32_type && value >= 0x100000000;
+               }
+
+               private static bool IsTypeIntegral (Type type)
+               {
+                       return type == TypeManager.uint64_type ||
+                               type == TypeManager.int64_type ||
+                               type == TypeManager.uint32_type ||
+                               type == TypeManager.int32_type ||
+                               type == TypeManager.ushort_type ||
+                               type == TypeManager.short_type ||
+                               type == TypeManager.sbyte_type ||
+                               type == TypeManager.byte_type;
+               }
+
+               private static bool IsTypeUnsigned (Type type)
+               {
+                       return type == TypeManager.uint64_type ||
+                               type == TypeManager.uint32_type ||
+                               type == TypeManager.ushort_type ||
+                               type == TypeManager.byte_type;
+               }
+
+               private void WarnUselessComparison (Type type)
+               {
+                       Report.Warning (652, 2, loc, "Comparison to integral constant is useless; the constant is outside the range of type `{0}'",
+                               TypeManager.CSharpName (type));
+               }
+
+               /// <remarks>
+               ///   EmitBranchable is called from Statement.EmitBoolExpression in the
+               ///   context of a conditional bool expression.  This function will return
+               ///   false if it is was possible to use EmitBranchable, or true if it was.
+               ///
+               ///   The expression's code is generated, and we will generate a branch to `target'
+               ///   if the resulting expression value is equal to isTrue
+               /// </remarks>
+               public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
+               {
+                       ILGenerator ig = ec.ig;
+
+                       //
+                       // This is more complicated than it looks, but its just to avoid
+                       // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
+                       // but on top of that we want for == and != to use a special path
+                       // if we are comparing against null
+                       //
+                       if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
+                               bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
+                               
+                               //
+                               // put the constant on the rhs, for simplicity
+                               //
+                               if (left is Constant) {
+                                       Expression swap = right;
+                                       right = left;
+                                       left = swap;
+                               }
+                               
+                               if (((Constant) right).IsZeroInteger) {
+                                       left.Emit (ec);
+                                       if (my_on_true)
+                                               ig.Emit (OpCodes.Brtrue, target);
+                                       else
+                                               ig.Emit (OpCodes.Brfalse, target);
+                                       
+                                       return;
+                               } else if (right is BoolConstant) {
+                                       left.Emit (ec);
+                                       if (my_on_true != ((BoolConstant) right).Value)
+                                               ig.Emit (OpCodes.Brtrue, target);
+                                       else
+                                               ig.Emit (OpCodes.Brfalse, target);
+                                       
+                                       return;
+                               }
+
+                       } else if (oper == Operator.LogicalAnd) {
+
+                               if (onTrue) {
+                                       Label tests_end = ig.DefineLabel ();
+                                       
+                                       left.EmitBranchable (ec, tests_end, false);
+                                       right.EmitBranchable (ec, target, true);
+                                       ig.MarkLabel (tests_end);                                       
+                               } else {
+                                       left.EmitBranchable (ec, target, false);
+                                       right.EmitBranchable (ec, target, false);
+                               }
+                               
+                               return;
+                               
+                       } else if (oper == Operator.LogicalOr){
+                               if (onTrue) {
+                                       left.EmitBranchable (ec, target, true);
+                                       right.EmitBranchable (ec, target, true);
+                                       
+                               } else {
+                                       Label tests_end = ig.DefineLabel ();
+                                       left.EmitBranchable (ec, tests_end, true);
+                                       right.EmitBranchable (ec, target, false);
+                                       ig.MarkLabel (tests_end);
+                               }
+                               
+                               return;
+                               
+                       } else if (!(oper == Operator.LessThan        || oper == Operator.GreaterThan ||
+                                    oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
+                                    oper == Operator.Equality        || oper == Operator.Inequality)) {
+                               base.EmitBranchable (ec, target, onTrue);
+                               return;
+                       }
+                       
+                       left.Emit (ec);
+                       right.Emit (ec);
+
+                       Type t = left.Type;
+                       bool isUnsigned = is_unsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
+                       
+                       switch (oper){
+                       case Operator.Equality:
+                               if (onTrue)
+                                       ig.Emit (OpCodes.Beq, target);
+                               else
+                                       ig.Emit (OpCodes.Bne_Un, target);
+                               break;
+
+                       case Operator.Inequality:
+                               if (onTrue)
+                                       ig.Emit (OpCodes.Bne_Un, target);
+                               else
+                                       ig.Emit (OpCodes.Beq, target);
+                               break;
+
+                       case Operator.LessThan:
+                               if (onTrue)
+                                       if (isUnsigned)
+                                               ig.Emit (OpCodes.Blt_Un, target);
+                                       else
+                                               ig.Emit (OpCodes.Blt, target);
+                               else
+                                       if (isUnsigned)
+                                               ig.Emit (OpCodes.Bge_Un, target);
+                                       else
+                                               ig.Emit (OpCodes.Bge, target);
+                               break;
+
+                       case Operator.GreaterThan:
+                               if (onTrue)
+                                       if (isUnsigned)
+                                               ig.Emit (OpCodes.Bgt_Un, target);
+                                       else
+                                               ig.Emit (OpCodes.Bgt, target);
+                               else
+                                       if (isUnsigned)
+                                               ig.Emit (OpCodes.Ble_Un, target);
+                                       else
+                                               ig.Emit (OpCodes.Ble, target);
+                               break;
+
+                       case Operator.LessThanOrEqual:
+                               if (onTrue)
+                                       if (isUnsigned)
+                                               ig.Emit (OpCodes.Ble_Un, target);
+                                       else
+                                               ig.Emit (OpCodes.Ble, target);
+                               else
+                                       if (isUnsigned)
+                                               ig.Emit (OpCodes.Bgt_Un, target);
+                                       else
+                                               ig.Emit (OpCodes.Bgt, target);
+                               break;
+
+
+                       case Operator.GreaterThanOrEqual:
+                               if (onTrue)
+                                       if (isUnsigned)
+                                               ig.Emit (OpCodes.Bge_Un, target);
+                                       else
+                                               ig.Emit (OpCodes.Bge, target);
+                               else
+                                       if (isUnsigned)
+                                               ig.Emit (OpCodes.Blt_Un, target);
+                                       else
+                                               ig.Emit (OpCodes.Blt, target);
+                               break;
+                       default:
+                               Console.WriteLine (oper);
+                               throw new Exception ("what is THAT");
+                       }
+               }
+               
+               public override void Emit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+                       Type l = left.Type;
+                       OpCode opcode;
+
+                       //
+                       // Handle short-circuit operators differently
+                       // than the rest
+                       //
+                       if (oper == Operator.LogicalAnd) {
+                               Label load_zero = ig.DefineLabel ();
+                               Label end = ig.DefineLabel ();
+                                                               
+                               left.EmitBranchable (ec, load_zero, false);
+                               right.Emit (ec);
+                               ig.Emit (OpCodes.Br, end);
+                               
+                               ig.MarkLabel (load_zero);
+                               ig.Emit (OpCodes.Ldc_I4_0);
+                               ig.MarkLabel (end);
+                               return;
+                       } else if (oper == Operator.LogicalOr) {
+                               Label load_one = ig.DefineLabel ();
+                               Label end = ig.DefineLabel ();
+
+                               left.EmitBranchable (ec, load_one, true);
+                               right.Emit (ec);
+                               ig.Emit (OpCodes.Br, end);
+                               
+                               ig.MarkLabel (load_one);
+                               ig.Emit (OpCodes.Ldc_I4_1);
+                               ig.MarkLabel (end);
+                               return;
+                       }
+
+                       left.Emit (ec);
+                       right.Emit (ec);
+
+                       bool isUnsigned = is_unsigned (left.Type);
+                       
+                       switch (oper){
+                       case Operator.Multiply:
+                               if (ec.CheckState){
+                                       if (l == TypeManager.int32_type || l == TypeManager.int64_type)
+                                               opcode = OpCodes.Mul_Ovf;
+                                       else if (isUnsigned)
+                                               opcode = OpCodes.Mul_Ovf_Un;
+                                       else
+                                               opcode = OpCodes.Mul;
+                               } else
+                                       opcode = OpCodes.Mul;
+
+                               break;
+
+                       case Operator.Division:
+                               if (isUnsigned)
+                                       opcode = OpCodes.Div_Un;
+                               else
+                                       opcode = OpCodes.Div;
+                               break;
+
+                       case Operator.Modulus:
+                               if (isUnsigned)
+                                       opcode = OpCodes.Rem_Un;
+                               else
+                                       opcode = OpCodes.Rem;
+                               break;
+
+                       case Operator.Addition:
+                               if (ec.CheckState){
+                                       if (l == TypeManager.int32_type || l == TypeManager.int64_type)
+                                               opcode = OpCodes.Add_Ovf;
+                                       else if (isUnsigned)
+                                               opcode = OpCodes.Add_Ovf_Un;
+                                       else
+                                               opcode = OpCodes.Add;
+                               } else
+                                       opcode = OpCodes.Add;
+                               break;
+
+                       case Operator.Subtraction:
+                               if (ec.CheckState){
+                                       if (l == TypeManager.int32_type || l == TypeManager.int64_type)
+                                               opcode = OpCodes.Sub_Ovf;
+                                       else if (isUnsigned)
+                                               opcode = OpCodes.Sub_Ovf_Un;
+                                       else
+                                               opcode = OpCodes.Sub;
+                               } else
+                                       opcode = OpCodes.Sub;
+                               break;
+
+                       case Operator.RightShift:
+                               if (isUnsigned)
+                                       opcode = OpCodes.Shr_Un;
+                               else
+                                       opcode = OpCodes.Shr;
+                               break;
+                               
+                       case Operator.LeftShift:
+                               opcode = OpCodes.Shl;
+                               break;
+
+                       case Operator.Equality:
+                               opcode = OpCodes.Ceq;
+                               break;
+
+                       case Operator.Inequality:
+                               ig.Emit (OpCodes.Ceq);
+                               ig.Emit (OpCodes.Ldc_I4_0);
+                               
+                               opcode = OpCodes.Ceq;
+                               break;
+
+                       case Operator.LessThan:
+                               if (isUnsigned)
+                                       opcode = OpCodes.Clt_Un;
+                               else
+                                       opcode = OpCodes.Clt;
+                               break;
+
+                       case Operator.GreaterThan:
+                               if (isUnsigned)
+                                       opcode = OpCodes.Cgt_Un;
+                               else
+                                       opcode = OpCodes.Cgt;
+                               break;
+
+                       case Operator.LessThanOrEqual:
+                               Type lt = left.Type;
+                               
+                               if (isUnsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
+                                       ig.Emit (OpCodes.Cgt_Un);
+                               else
+                                       ig.Emit (OpCodes.Cgt);
+                               ig.Emit (OpCodes.Ldc_I4_0);
+                               
+                               opcode = OpCodes.Ceq;
+                               break;
+
+                       case Operator.GreaterThanOrEqual:
+                               Type le = left.Type;
+                               
+                               if (isUnsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
+                                       ig.Emit (OpCodes.Clt_Un);
+                               else
+                                       ig.Emit (OpCodes.Clt);
+                               
+                               ig.Emit (OpCodes.Ldc_I4_0);
+                               
+                               opcode = OpCodes.Ceq;
+                               break;
+
+                       case Operator.BitwiseOr:
+                               opcode = OpCodes.Or;
+                               break;
+
+                       case Operator.BitwiseAnd:
+                               opcode = OpCodes.And;
+                               break;
+
+                       case Operator.ExclusiveOr:
+                               opcode = OpCodes.Xor;
+                               break;
+
+                       default:
+                               throw new Exception ("This should not happen: Operator = "
+                                                    + oper.ToString ());
+                       }
+
+                       ig.Emit (opcode);
+               }
+       }
+
+       //
+       // Object created by Binary when the binary operator uses an method instead of being
+       // a binary operation that maps to a CIL binary operation.
+       //
+       public class BinaryMethod : Expression {
+               public MethodBase method;
+               public ArrayList  Arguments;
+               
+               public BinaryMethod (Type t, MethodBase m, ArrayList args)
+               {
+                       method = m;
+                       Arguments = args;
+                       type = t;
+                       eclass = ExprClass.Value;
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+                       
+                       if (Arguments != null) 
+                               Invocation.EmitArguments (ec, method, Arguments, false, null);
+                       
+                       if (method is MethodInfo)
+                               ig.Emit (OpCodes.Call, (MethodInfo) method);
+                       else
+                               ig.Emit (OpCodes.Call, (ConstructorInfo) method);
+               }
+       }
+       
+       //
+       // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
+       // b, c, d... may be strings or objects.
+       //
+       public class StringConcat : Expression {
+               ArrayList operands;
+               bool invalid = false;
+               bool emit_conv_done = false;
+               //
+               // Are we also concating objects?
+               //
+               bool is_strings_only = true;
+               
+               public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
+               {
+                       this.loc = loc;
+                       type = TypeManager.string_type;
+                       eclass = ExprClass.Value;
+               
+                       operands = new ArrayList (2);
+                       Append (ec, left);
+                       Append (ec, right);
+               }
+               
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       if (invalid)
+                               return null;
+                       
+                       return this;
+               }
+               
+               public void Append (EmitContext ec, Expression operand)
+               {
+                       //
+                       // Constant folding
+                       //
+                       StringConstant sc = operand as StringConstant;
+                       if (sc != null) {
+// TODO: it will be better to do this silently as an optimalization
+// int i = 0;
+// string s = "" + i;
+// because this code has poor performace
+//                             if (sc.Value.Length == 0)
+//                                     Report.Warning (-300, 3, Location, "Appending an empty string has no effect. Did you intend to append a space string?");
+
+                               if (operands.Count != 0) {
+                                       StringConstant last_operand = operands [operands.Count - 1] as StringConstant;
+                                       if (last_operand != null) {
+                                               operands [operands.Count - 1] = new StringConstant (last_operand.Value + ((StringConstant) operand).Value, last_operand.Location);
+                                               return;
+                                       }
+                               }
+                       }
+                       
+                       //
+                       // Conversion to object
+                       //
+                       if (operand.Type != TypeManager.string_type) {
+                               Expression no = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
+                               
+                               if (no == null) {
+                                       Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
+                                       invalid = true;
+                               }
+                               operand = no;
+                       }
+                       
+                       operands.Add (operand);
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       MethodInfo concat_method = null;
+                       
+                       //
+                       // Do conversion to arguments; check for strings only
+                       //
+                       
+                       // This can get called multiple times, so we have to deal with that.
+                       if (!emit_conv_done) {
+                               emit_conv_done = true;
+                               for (int i = 0; i < operands.Count; i ++) {
+                                       Expression e = (Expression) operands [i];
+                                       is_strings_only &= e.Type == TypeManager.string_type;
+                               }
+                               
+                               for (int i = 0; i < operands.Count; i ++) {
+                                       Expression e = (Expression) operands [i];
+                                       
+                                       if (! is_strings_only && e.Type == TypeManager.string_type) {
+                                               // need to make sure this is an object, because the EmitParams
+                                               // method might look at the type of this expression, see it is a
+                                               // string and emit a string [] when we want an object [];
+                                               
+                                               e = new EmptyCast (e, TypeManager.object_type);
+                                       }
+                                       operands [i] = new Argument (e, Argument.AType.Expression);
+                               }
+                       }
+                       
+                       //
+                       // Find the right method
+                       //
+                       switch (operands.Count) {
+                       case 1:
+                               //
+                               // This should not be possible, because simple constant folding
+                               // is taken care of in the Binary code.
+                               //
+                               throw new Exception ("how did you get here?");
+                       
+                       case 2:
+                               concat_method = is_strings_only ? 
+                                       TypeManager.string_concat_string_string :
+                                       TypeManager.string_concat_object_object ;
+                               break;
+                       case 3:
+                               concat_method = is_strings_only ? 
+                                       TypeManager.string_concat_string_string_string :
+                                       TypeManager.string_concat_object_object_object ;
+                               break;
+                       case 4:
+                               //
+                               // There is not a 4 param overlaod for object (the one that there is
+                               // is actually a varargs methods, and is only in corlib because it was
+                               // introduced there before.).
+                               //
+                               if (!is_strings_only)
+                                       goto default;
+                               
+                               concat_method = TypeManager.string_concat_string_string_string_string;
+                               break;
+                       default:
+                               concat_method = is_strings_only ? 
+                                       TypeManager.string_concat_string_dot_dot_dot :
+                                       TypeManager.string_concat_object_dot_dot_dot ;
+                               break;
+                       }
+                       
+                       Invocation.EmitArguments (ec, concat_method, operands, false, null);
+                       ec.ig.Emit (OpCodes.Call, concat_method);
+               }
+       }
+
+       //
+       // Object created with +/= on delegates
+       //
+       public class BinaryDelegate : Expression {
+               MethodInfo method;
+               ArrayList  args;
+
+               public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
+               {
+                       method = mi;
+                       this.args = args;
+                       type = t;
+                       eclass = ExprClass.Value;
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+                       
+                       Invocation.EmitArguments (ec, method, args, false, null);
+                       
+                       ig.Emit (OpCodes.Call, (MethodInfo) method);
+                       ig.Emit (OpCodes.Castclass, type);
+               }
+
+               public Expression Right {
+                       get {
+                               Argument arg = (Argument) args [1];
+                               return arg.Expr;
+                       }
+               }
+
+               public bool IsAddition {
+                       get {
+                               return method == TypeManager.delegate_combine_delegate_delegate;
+                       }
+               }
+       }
+       
+       //
+       // User-defined conditional logical operator
+       public class ConditionalLogicalOperator : Expression {
+               Expression left, right;
+               bool is_and;
+
+               public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
+               {
+                       type = t;
+                       eclass = ExprClass.Value;
+                       this.loc = loc;
+                       this.left = left;
+                       this.right = right;
+                       this.is_and = is_and;
+               }
+
+               protected void Error19 ()
+               {
+                       Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", left.GetSignatureForError (), right.GetSignatureForError ());
+               }
+
+               protected void Error218 ()
+               {
+                       Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
+                              "declarations of operator true and operator false");
+               }
+
+               Expression op_true, op_false, op;
+               LocalTemporary left_temp;
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       MethodInfo method;
+                       Expression operator_group;
+
+                       operator_group = MethodLookup (ec, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc);
+                       if (operator_group == null) {
+                               Error19 ();
+                               return null;
+                       }
+
+                       left_temp = new LocalTemporary (type);
+
+                       ArrayList arguments = new ArrayList ();
+                       arguments.Add (new Argument (left_temp, Argument.AType.Expression));
+                       arguments.Add (new Argument (right, Argument.AType.Expression));
+                       method = Invocation.OverloadResolve (
+                               ec, (MethodGroupExpr) operator_group, arguments, false, loc)
+                               as MethodInfo;
+                       if (method == null) {
+                               Error19 ();
+                               return null;
+                       }
+
+                       if (method.ReturnType != type) {
+                               Report.Error (217, loc, "In order to be applicable as a short circuit operator a user-defined logical operator `{0}' " +
+                                               "must have the same return type as the type of its 2 parameters", TypeManager.CSharpSignature (method));
+                               return null;
+                       }
+
+                       op = new StaticCallExpr (method, arguments, loc);
+
+                       op_true = GetOperatorTrue (ec, left_temp, loc);
+                       op_false = GetOperatorFalse (ec, left_temp, loc);
+                       if ((op_true == null) || (op_false == null)) {
+                               Error218 ();
+                               return null;
+                       }
+
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+                       Label false_target = ig.DefineLabel ();
+                       Label end_target = ig.DefineLabel ();
+
+                       left.Emit (ec);
+                       left_temp.Store (ec);
+
+                       (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
+                       left_temp.Emit (ec);
+                       ig.Emit (OpCodes.Br, end_target);
+                       ig.MarkLabel (false_target);
+                       op.Emit (ec);
+                       ig.MarkLabel (end_target);
+
+                       // We release 'left_temp' here since 'op' may refer to it too
+                       left_temp.Release (ec);
+               }
+       }
+
+       public class PointerArithmetic : Expression {
+               Expression left, right;
+               bool is_add;
+
+               //
+               // We assume that `l' is always a pointer
+               //
+               public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
+               {
+                       type = t;
+                       this.loc = loc;
+                       left = l;
+                       right = r;
+                       is_add = is_addition;
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       eclass = ExprClass.Variable;
+                       
+                       if (left.Type == TypeManager.void_ptr_type) {
+                               Error (242, "The operation in question is undefined on void pointers");
+                               return null;
+                       }
+                       
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       Type op_type = left.Type;
+                       ILGenerator ig = ec.ig;
+                       
+                       // It must be either array or fixed buffer
+                       Type element = TypeManager.HasElementType (op_type) ?
+                               element = TypeManager.GetElementType (op_type) :
+                               element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
+
+                       int size = GetTypeSize (element);
+                       Type rtype = right.Type;
+                       
+                       if (rtype.IsPointer){
+                               //
+                               // handle (pointer - pointer)
+                               //
+                               left.Emit (ec);
+                               right.Emit (ec);
+                               ig.Emit (OpCodes.Sub);
+
+                               if (size != 1){
+                                       if (size == 0)
+                                               ig.Emit (OpCodes.Sizeof, element);
+                                       else 
+                                               IntLiteral.EmitInt (ig, size);
+                                       ig.Emit (OpCodes.Div);
+                               }
+                               ig.Emit (OpCodes.Conv_I8);
+                       } else {
+                               //
+                               // handle + and - on (pointer op int)
+                               //
+                               left.Emit (ec);
+                               ig.Emit (OpCodes.Conv_I);
+
+                               Constant right_const = right as Constant;
+                               if (right_const != null && size != 0) {
+                                       Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
+                                       if (ex == null)
+                                               return;
+                                       ex.Emit (ec);
+                               } else {
+                                       right.Emit (ec);
+                                       if (size != 1){
+                                               if (size == 0)
+                                                       ig.Emit (OpCodes.Sizeof, element);
+                                               else 
+                                                       IntLiteral.EmitInt (ig, size);
+                                               if (rtype == TypeManager.int64_type)
+                                                       ig.Emit (OpCodes.Conv_I8);
+                                               else if (rtype == TypeManager.uint64_type)
+                                                       ig.Emit (OpCodes.Conv_U8);
+                                               ig.Emit (OpCodes.Mul);
+                                       }
+                               }
+                               
+                               if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
+                                       ig.Emit (OpCodes.Conv_I);
+                               
+                               if (is_add)
+                                       ig.Emit (OpCodes.Add);
+                               else
+                                       ig.Emit (OpCodes.Sub);
+                       }
+               }
+       }
+       
+       /// <summary>
+       ///   Implements the ternary conditional operator (?:)
+       /// </summary>
+       public class Conditional : Expression {
+               Expression expr, trueExpr, falseExpr;
+               
+               public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
+               {
+                       this.expr = expr;
+                       this.trueExpr = trueExpr;
+                       this.falseExpr = falseExpr;
+                       this.loc = expr.Location;
+               }
+
+               public Expression Expr {
+                       get {
+                               return expr;
+                       }
+               }
+
+               public Expression TrueExpr {
+                       get {
+                               return trueExpr;
+                       }
+               }
+
+               public Expression FalseExpr {
+                       get {
+                               return falseExpr;
+                       }
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       expr = expr.Resolve (ec);
+
+                       if (expr == null)
+                               return null;
+
+#if GMCS_SOURCE
+                       if (TypeManager.IsNullableValueType (expr.Type))
+                               return new Nullable.LiftedConditional (expr, trueExpr, falseExpr, loc).Resolve (ec);
+#endif
+                       
+                       if (expr.Type != TypeManager.bool_type){
+                               expr = Expression.ResolveBoolean (
+                                       ec, expr, loc);
+                               
+                               if (expr == null)
+                                       return null;
+                       }
+                       
+                       Assign ass = expr as Assign;
+                       if (ass != null && ass.Source is Constant) {
+                               Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
+                       }
+
+                       trueExpr = trueExpr.Resolve (ec);
+                       falseExpr = falseExpr.Resolve (ec);
+
+                       if (trueExpr == null || falseExpr == null)
+                               return null;
+
+                       eclass = ExprClass.Value;
+                       if (trueExpr.Type == falseExpr.Type) {
+                               type = trueExpr.Type;
+                               if (type == TypeManager.null_type) {
+                                       // TODO: probably will have to implement ConditionalConstant
+                                       // to call method without return constant as well
+                                       Report.Warning (-101, 1, loc, "Conditional expression will always return same value");
+                                       return trueExpr;
+                               }
+                       } else {
+                               Expression conv;
+                               Type true_type = trueExpr.Type;
+                               Type false_type = falseExpr.Type;
+
+                               //
+                               // First, if an implicit conversion exists from trueExpr
+                               // to falseExpr, then the result type is of type falseExpr.Type
+                               //
+                               conv = Convert.ImplicitConversion (ec, trueExpr, false_type, loc);
+                               if (conv != null){
+                                       //
+                                       // Check if both can convert implicitl to each other's type
+                                       //
+                                       if (Convert.ImplicitConversion (ec, falseExpr, true_type, loc) != null){
+                                               Error (172,
+                                                      "Can not compute type of conditional expression " +
+                                                      "as `" + TypeManager.CSharpName (trueExpr.Type) +
+                                                      "' and `" + TypeManager.CSharpName (falseExpr.Type) +
+                                                      "' convert implicitly to each other");
+                                               return null;
+                                       }
+                                       type = false_type;
+                                       trueExpr = conv;
+                               } else if ((conv = Convert.ImplicitConversion(ec, falseExpr, true_type,loc))!= null){
+                                       type = true_type;
+                                       falseExpr = conv;
+                               } else {
+                                       Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
+                                               trueExpr.GetSignatureForError (), falseExpr.GetSignatureForError ());
+                                       return null;
+                               }
+                       }
+
+                       // Dead code optimalization
+                       if (expr is BoolConstant){
+                               BoolConstant bc = (BoolConstant) expr;
+
+                               Report.Warning (429, 4, bc.Value ? falseExpr.Location : trueExpr.Location, "Unreachable expression code detected");
+                               return bc.Value ? trueExpr : falseExpr;
+                       }
+
+                       return this;
+               }
+
+               public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
+               {
+                       return null;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+                       Label false_target = ig.DefineLabel ();
+                       Label end_target = ig.DefineLabel ();
+
+                       expr.EmitBranchable (ec, false_target, false);
+                       trueExpr.Emit (ec);
+                       ig.Emit (OpCodes.Br, end_target);
+                       ig.MarkLabel (false_target);
+                       falseExpr.Emit (ec);
+                       ig.MarkLabel (end_target);
+               }
+
+       }
+
+       public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation {
+               bool prepared;
+               LocalTemporary temp;
+
+               public abstract Variable Variable {
+                       get;
+               }
+
+               public abstract bool IsRef {
+                       get;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       Emit (ec, false);
+               }
+
+               //
+               // This method is used by parameters that are references, that are
+               // being passed as references:  we only want to pass the pointer (that
+               // is already stored in the parameter, not the address of the pointer,
+               // and not the value of the variable).
+               //
+               public void EmitLoad (EmitContext ec)
+               {
+                       Report.Debug (64, "VARIABLE EMIT LOAD", this, Variable, type, loc);
+                       if (!prepared)
+                               Variable.EmitInstance (ec);
+                       Variable.Emit (ec);
+               }
+               
+               public void Emit (EmitContext ec, bool leave_copy)
+               {
+                       Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
+
+                       EmitLoad (ec);
+
+                       if (IsRef) {
+                               if (prepared)
+                                       ec.ig.Emit (OpCodes.Dup);
+       
+                               //
+                               // If we are a reference, we loaded on the stack a pointer
+                               // Now lets load the real value
+                               //
+                               LoadFromPtr (ec.ig, type);
+                       }
+
+                       if (leave_copy) {
+                               ec.ig.Emit (OpCodes.Dup);
+
+                               if (IsRef || Variable.NeedsTemporary) {
+                                       temp = new LocalTemporary (Type);
+                                       temp.Store (ec);
+                               }
+                       }
+               }
+
+               public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
+                                       bool prepare_for_load)
+               {
+                       Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
+                                     source, loc);
+
+                       ILGenerator ig = ec.ig;
+                       prepared = prepare_for_load;
+
+                       Variable.EmitInstance (ec);
+                       if (prepare_for_load && Variable.HasInstance)
+                               ig.Emit (OpCodes.Dup);
+                       else if (IsRef && !prepared)
+                               Variable.Emit (ec);
+
+                       source.Emit (ec);
+
+                       if (leave_copy) {
+                               ig.Emit (OpCodes.Dup);
+                               if (IsRef || Variable.NeedsTemporary) {
+                                       temp = new LocalTemporary (Type);
+                                       temp.Store (ec);
+                               }
+                       }
+
+                       if (IsRef)
+                               StoreFromPtr (ig, type);
+                       else
+                               Variable.EmitAssign (ec);
+
+                       if (temp != null) {
+                               temp.Emit (ec);
+                               temp.Release (ec);
+                       }
+               }
+               
+               public void AddressOf (EmitContext ec, AddressOp mode)
+               {
+                       Variable.EmitInstance (ec);
+                       Variable.EmitAddressOf (ec);
+               }
+       }
+
+       /// <summary>
+       ///   Local variables
+       /// </summary>
+       public class LocalVariableReference : VariableReference, IVariable {
+               public readonly string Name;
+               public readonly Block Block;
+               public LocalInfo local_info;
+               bool is_readonly;
+               Variable variable;
+
+               public LocalVariableReference (Block block, string name, Location l)
+               {
+                       Block = block;
+                       Name = name;
+                       loc = l;
+                       eclass = ExprClass.Variable;
+               }
+
+               //
+               // Setting `is_readonly' to false will allow you to create a writable
+               // reference to a read-only variable.  This is used by foreach and using.
+               //
+               public LocalVariableReference (Block block, string name, Location l,
+                                              LocalInfo local_info, bool is_readonly)
+                       : this (block, name, l)
+               {
+                       this.local_info = local_info;
+                       this.is_readonly = is_readonly;
+               }
+
+               public VariableInfo VariableInfo {
+                       get { return local_info.VariableInfo; }
+               }
+
+               public override bool IsRef {
+                       get { return false; }
+               }
+
+               public bool IsReadOnly {
+                       get { return is_readonly; }
+               }
+
+               public bool VerifyAssigned (EmitContext ec)
+               {
+                       VariableInfo variable_info = local_info.VariableInfo;
+                       return variable_info == null || variable_info.IsAssigned (ec, loc);
+               }
+
+               void ResolveLocalInfo ()
+               {
+                       if (local_info == null) {
+                               local_info = Block.GetLocalInfo (Name);
+                               is_readonly = local_info.ReadOnly;
+                       }
+               }
+
+               protected Expression DoResolveBase (EmitContext ec)
+               {
+                       type = local_info.VariableType;
+
+                       Expression e = Block.GetConstantExpression (Name);
+                       if (e != null)
+                               return e.Resolve (ec);
+
+                       if (!VerifyAssigned (ec))
+                               return null;
+
+                       //
+                       // If we are referencing a variable from the external block
+                       // flag it for capturing
+                       //
+                       if (ec.MustCaptureVariable (local_info)) {
+                               if (local_info.AddressTaken){
+                                       AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
+                                       return null;
+                               }
+
+                               ScopeInfo scope = local_info.Block.CreateScopeInfo ();
+                               variable = scope.AddLocal (local_info);
+                               type = variable.Type;
+                       }
+
+                       return this;
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       ResolveLocalInfo ();
+                       local_info.Used = true;
+                       return DoResolveBase (ec);
+               }
+
+               override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
+               {
+                       ResolveLocalInfo ();
+
+                       if (is_readonly) {
+                               int code;
+                               string msg;
+                               if (right_side == EmptyExpression.OutAccess) {
+                                       code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
+                               } else if (right_side == EmptyExpression.LValueMemberAccess) {
+                                       code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
+                               } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
+                                       code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
+                               } else {
+                                       code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
+                               }
+                               Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
+                               return null;
+                       }
+
+                       // is out param
+                       if (right_side == EmptyExpression.OutAccess)
+                               local_info.Used = true;
+
+                       if (VariableInfo != null)
+                               VariableInfo.SetAssigned (ec);
+
+                       return DoResolveBase (ec);
+               }
+
+               public bool VerifyFixed ()
+               {
+                       // A local Variable is always fixed.
+                       return true;
+               }
+
+               public override int GetHashCode ()
+               {
+                       return Name.GetHashCode ();
+               }
+
+               public override bool Equals (object obj)
+               {
+                       LocalVariableReference lvr = obj as LocalVariableReference;
+                       if (lvr == null)
+                               return false;
+
+                       return Name == lvr.Name && Block == lvr.Block;
+               }
+
+               public override Variable Variable {
+                       get { return variable != null ? variable : local_info.Variable; }
+               }
+
+               public override string ToString ()
+               {
+                       return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
+               }
+       }
+
+       /// <summary>
+       ///   This represents a reference to a parameter in the intermediate
+       ///   representation.
+       /// </summary>
+       public class ParameterReference : VariableReference, IVariable {
+               Parameter par;
+               string name;
+               int idx;
+               Block block;
+               VariableInfo vi;
+               public bool is_ref, is_out;
+
+               public bool IsOut {
+                       get {
+                               return is_out;
+                       }
+               }
+
+               public override bool IsRef {
+                       get {
+                               return is_ref;
+                       }
+               }
+
+               public string Name {
+                       get {
+                               return name;
+                       }
+               }
+
+               public Parameter Parameter {
+                       get {
+                               return par;
+                       }
+               }
+
+               Variable variable;
+               
+               public ParameterReference (Parameter par, Block block, int idx, Location loc)
+               {
+                       this.par = par;
+                       this.name = par.Name;
+                       this.block = block;
+                       this.idx  = idx;
+                       this.loc = loc;
+                       eclass = ExprClass.Variable;
+               }
+
+               public VariableInfo VariableInfo {
+                       get { return vi; }
+               }
+
+               public override Variable Variable {
+                       get { return variable != null ? variable : par.Variable; }
+               }
+
+               public bool VerifyFixed ()
+               {
+                       // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
+                       return par.ModFlags == Parameter.Modifier.NONE;
+               }
+
+               public bool IsAssigned (EmitContext ec, Location loc)
+               {
+                       if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (vi))
+                               return true;
+
+                       Report.Error (269, loc,
+                                     "Use of unassigned out parameter `{0}'", par.Name);
+                       return false;
+               }
+
+               public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
+               {
+                       if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (vi, field_name))
+                               return true;
+
+                       Report.Error (170, loc,
+                                     "Use of possibly unassigned field `" + field_name + "'");
+                       return false;
+               }
+
+               public void SetAssigned (EmitContext ec)
+               {
+                       if (is_out && ec.DoFlowAnalysis)
+                               ec.CurrentBranching.SetAssigned (vi);
+               }
+
+               public void SetFieldAssigned (EmitContext ec, string field_name)
+               {
+                       if (is_out && ec.DoFlowAnalysis)
+                               ec.CurrentBranching.SetFieldAssigned (vi, field_name);
+               }
+
+               protected bool DoResolveBase (EmitContext ec)
+               {
+                       if (!par.Resolve (ec)) {
+                               //TODO:
+                       }
+
+                       type = par.ParameterType;
+                       Parameter.Modifier mod = par.ModFlags;
+                       is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
+                       is_out = (mod & Parameter.Modifier.OUT) == Parameter.Modifier.OUT;
+                       eclass = ExprClass.Variable;
+
+                       if (is_out)
+                               vi = block.ParameterMap [idx];
+
+                       AnonymousContainer am = ec.CurrentAnonymousMethod;
+                       if (am == null)
+                               return true;
+
+                       if (is_ref && !block.Toplevel.IsLocalParameter (name)){
+                               Report.Error (1628, Location,
+                                             "Cannot use ref or out parameter `{0}' inside an " +
+                                             "anonymous method block", par.Name);
+                               return false;
+                       }
+
+                       if (!am.IsIterator && block.Toplevel.IsLocalParameter (name))
+                               return true;
+
+                       IAnonymousMethodHost host = null;
+                       ToplevelBlock toplevel = block.Toplevel;
+                       while (toplevel != null) {
+                               if (toplevel.IsLocalParameter (name)) {
+                                       host = toplevel.AnonymousMethodHost;
+                                       break;
+                               }
+
+                               toplevel = toplevel.Container;
+                       }
+
+                       variable = host.AddParameter (par, idx);
+                       type = variable.Type;
+                       return true;
+               }
+
+               public override int GetHashCode()
+               {
+                       return name.GetHashCode ();
+               }
+
+               public override bool Equals (object obj)
+               {
+                       ParameterReference pr = obj as ParameterReference;
+                       if (pr == null)
+                               return false;
+
+                       return name == pr.name && block == pr.block;
+               }
+
+               //
+               // Notice that for ref/out parameters, the type exposed is not the
+               // same type exposed externally.
+               //
+               // for "ref int a":
+               //   externally we expose "int&"
+               //   here we expose       "int".
+               //
+               // We record this in "is_ref".  This means that the type system can treat
+               // the type as it is expected, but when we generate the code, we generate
+               // the alternate kind of code.
+               //
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       if (!DoResolveBase (ec))
+                               return null;
+
+                       if (is_out && ec.DoFlowAnalysis &&
+                           (!ec.OmitStructFlowAnalysis || !vi.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
+                               return null;
+
+                       return this;
+               }
+
+               override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
+               {
+                       if (!DoResolveBase (ec))
+                               return null;
+
+                       SetAssigned (ec);
+
+                       return this;
+               }
+
+               static public void EmitLdArg (ILGenerator ig, int x)
+               {
+                       if (x <= 255){
+                               switch (x){
+                               case 0: ig.Emit (OpCodes.Ldarg_0); break;
+                               case 1: ig.Emit (OpCodes.Ldarg_1); break;
+                               case 2: ig.Emit (OpCodes.Ldarg_2); break;
+                               case 3: ig.Emit (OpCodes.Ldarg_3); break;
+                               default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
+                               }
+                       } else
+                               ig.Emit (OpCodes.Ldarg, x);
+               }
+               
+               public override string ToString ()
+               {
+                       return "ParameterReference[" + name + "]";
+               }
+       }
+       
+       /// <summary>
+       ///   Used for arguments to New(), Invocation()
+       /// </summary>
+       public class Argument {
+               public enum AType : byte {
+                       Expression,
+                       Ref,
+                       Out,
+                       ArgList
+               };
+
+               public readonly AType ArgType;
+               public Expression Expr;
+               
+               public Argument (Expression expr, AType type)
+               {
+                       this.Expr = expr;
+                       this.ArgType = type;
+               }
+
+               public Argument (Expression expr)
+               {
+                       this.Expr = expr;
+                       this.ArgType = AType.Expression;
+               }
+
+               public Type Type {
+                       get {
+                               if (ArgType == AType.Ref || ArgType == AType.Out)
+                                       return TypeManager.GetReferenceType (Expr.Type);
+                               else
+                                       return Expr.Type;
+                       }
+               }
+
+               public Parameter.Modifier Modifier
+               {
+                       get {
+                               switch (ArgType) {
+                                       case AType.Out:
+                                               return Parameter.Modifier.OUT;
+
+                                       case AType.Ref:
+                                               return Parameter.Modifier.REF;
+
+                                       default:
+                                               return Parameter.Modifier.NONE;
+                               }
+                       }
+               }
+
+               public static string FullDesc (Argument a)
+               {
+                       if (a.ArgType == AType.ArgList)
+                               return "__arglist";
+
+                       return (a.ArgType == AType.Ref ? "ref " :
+                               (a.ArgType == AType.Out ? "out " : "")) +
+                               TypeManager.CSharpName (a.Expr.Type);
+               }
+
+               public bool ResolveMethodGroup (EmitContext ec)
+               {
+                       SimpleName sn = Expr as SimpleName;
+                       if (sn != null)
+                               Expr = sn.GetMethodGroup ();
+
+                       // FIXME: csc doesn't report any error if you try to use `ref' or
+                       //        `out' in a delegate creation expression.
+                       Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
+                       if (Expr == null)
+                               return false;
+
+                       return true;
+               }
+
+               public bool Resolve (EmitContext ec, Location loc)
+               {
+                       using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
+                               // Verify that the argument is readable
+                               if (ArgType != AType.Out)
+                                       Expr = Expr.Resolve (ec);
+
+                               // Verify that the argument is writeable
+                               if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
+                                       Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
+
+                               return Expr != null;
+                       }
+               }
+
+               public void Emit (EmitContext ec)
+               {
+                       if (ArgType != AType.Ref && ArgType != AType.Out) {
+                               Expr.Emit (ec);
+                               return;
+                       }
+
+                       AddressOp mode = AddressOp.Store;
+                       if (ArgType == AType.Ref)
+                               mode |= AddressOp.Load;
+                               
+                       IMemoryLocation ml = (IMemoryLocation) Expr;
+                       ParameterReference pr = ml as ParameterReference;
+
+                       //
+                       // ParameterReferences might already be references, so we want
+                       // to pass just the value
+                       //
+                       if (pr != null && pr.IsRef)
+                               pr.EmitLoad (ec);
+                       else
+                               ml.AddressOf (ec, mode);
+               }
+       }
+
+       /// <summary>
+       ///   Invocation of methods or delegates.
+       /// </summary>
+       public class Invocation : ExpressionStatement {
+               public readonly ArrayList Arguments;
+
+               Expression expr;
+               MethodBase method = null;
+               
+               //
+               // arguments is an ArrayList, but we do not want to typecast,
+               // as it might be null.
+               //
+               // FIXME: only allow expr to be a method invocation or a
+               // delegate invocation (7.5.5)
+               //
+               public Invocation (Expression expr, ArrayList arguments)
+               {
+                       this.expr = expr;
+                       Arguments = arguments;
+                       loc = expr.Location;
+               }
+
+               public Expression Expr {
+                       get {
+                               return expr;
+                       }
+               }
+
+               /// <summary>
+               ///   Determines "better conversion" as specified in 14.4.2.3
+               ///
+                ///    Returns : p    if a->p is better,
+               ///              q    if a->q is better,
+               ///              null if neither is better
+               /// </summary>
+               static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q)
+               {
+                       Type argument_type = TypeManager.TypeToCoreType (a.Type);
+                       Expression argument_expr = a.Expr;
+
+                       if (argument_type == null)
+                               throw new Exception ("Expression of type " + a.Expr +
+                                                     " does not resolve its type");
+
+                       if (p == null || q == null)
+                               throw new InternalErrorException ("BetterConversion Got a null conversion");
+
+                       if (p == q)
+                               return null;
+
+                       if (argument_expr is NullLiteral) {
+                               //
+                               // If the argument is null and one of the types to compare is 'object' and
+                               // the other is a reference type, we prefer the other.
+                               //
+                               // This follows from the usual rules:
+                               //   * There is an implicit conversion from 'null' to type 'object'
+                               //   * There is an implicit conversion from 'null' to any reference type
+                               //   * There is an implicit conversion from any reference type to type 'object'
+                               //   * There is no implicit conversion from type 'object' to other reference types
+                               //  => Conversion of 'null' to a reference type is better than conversion to 'object'
+                               //
+                               //  FIXME: This probably isn't necessary, since the type of a NullLiteral is the 
+                               //         null type. I think it used to be 'object' and thus needed a special 
+                               //         case to avoid the immediately following two checks.
+                               //
+                               if (!p.IsValueType && q == TypeManager.object_type)
+                                       return p;
+                               if (!q.IsValueType && p == TypeManager.object_type)
+                                       return q;
+                       }
+                                
+                       if (argument_type == p)
+                               return p;
+
+                       if (argument_type == q)
+                               return q;
+
+                       Expression p_tmp = new EmptyExpression (p);
+                       Expression q_tmp = new EmptyExpression (q);
+
+                       bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
+                       bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
+
+                       if (p_to_q && !q_to_p)
+                               return p;
+
+                       if (q_to_p && !p_to_q)
+                               return q;
+
+                       if (p == TypeManager.sbyte_type)
+                               if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
+                                   q == TypeManager.uint32_type || q == TypeManager.uint64_type)
+                                       return p;
+                       if (q == TypeManager.sbyte_type)
+                               if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
+                                   p == TypeManager.uint32_type || p == TypeManager.uint64_type)
+                                       return q;
+
+                       if (p == TypeManager.short_type)
+                               if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
+                                   q == TypeManager.uint64_type)
+                                       return p;
+                       if (q == TypeManager.short_type)
+                               if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
+                                   p == TypeManager.uint64_type)
+                                       return q;
+
+                       if (p == TypeManager.int32_type)
+                               if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
+                                       return p;
+                       if (q == TypeManager.int32_type)
+                               if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
+                                       return q;
+
+                       if (p == TypeManager.int64_type)
+                               if (q == TypeManager.uint64_type)
+                                       return p;
+                       if (q == TypeManager.int64_type)
+                               if (p == TypeManager.uint64_type)
+                                       return q;
+
+                       return null;
+               }
+
+               static Type MoreSpecific (Type p, Type q)
+               {
+                       if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
+                               return q;
+                       if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
+                               return p;
+
+                       if (TypeManager.HasElementType (p)) {
+                               Type pe = TypeManager.GetElementType (p);
+                               Type qe = TypeManager.GetElementType (q);
+                               Type specific = MoreSpecific (pe, qe);
+                               if (specific == pe)
+                                       return p;
+                               if (specific == qe)
+                                       return q;
+                       } else if (TypeManager.IsGenericType (p)) {
+                               Type[] pargs = TypeManager.GetTypeArguments (p);
+                               Type[] qargs = TypeManager.GetTypeArguments (q);
+
+                               bool p_specific_at_least_once = false;
+                               bool q_specific_at_least_once = false;
+
+                               for (int i = 0; i < pargs.Length; i++) {
+                                       Type specific = MoreSpecific (pargs [i], qargs [i]);
+                                       if (specific == pargs [i])
+                                               p_specific_at_least_once = true;
+                                       if (specific == qargs [i])
+                                               q_specific_at_least_once = true;
+                               }
+
+                               if (p_specific_at_least_once && !q_specific_at_least_once)
+                                       return p;
+                               if (!p_specific_at_least_once && q_specific_at_least_once)
+                                       return q;
+                       }
+
+                       return null;
+               }
+               
+               /// <summary>
+               ///   Determines "Better function" between candidate
+                ///   and the current best match
+               /// </summary>
+               /// <remarks>
+               ///    Returns a boolean indicating :
+               ///     false if candidate ain't better
+               ///     true  if candidate is better than the current best match
+               /// </remarks>
+               static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
+                                           MethodBase candidate, bool candidate_params,
+                                           MethodBase best, bool best_params)
+               {
+                       ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
+                       ParameterData best_pd = TypeManager.GetParameterData (best);
+               
+                       bool better_at_least_one = false;
+                       bool same = true;
+                       for (int j = 0; j < argument_count; ++j) {
+                               Argument a = (Argument) args [j];
+
+                               Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (j));
+                               Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (j));
+
+                               if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
+                                       if (candidate_params)
+                                               ct = TypeManager.GetElementType (ct);
+
+                               if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
+                                       if (best_params)
+                                               bt = TypeManager.GetElementType (bt);
+
+                               if (ct.Equals (bt))
+                                       continue;
+
+                               same = false;
+                               Type better = BetterConversion (ec, a, ct, bt);
+
+                               // for each argument, the conversion to 'ct' should be no worse than 
+                               // the conversion to 'bt'.
+                               if (better == bt)
+                                       return false;
+
+                               // for at least one argument, the conversion to 'ct' should be better than 
+                               // the conversion to 'bt'.
+                               if (better == ct)
+                                       better_at_least_one = true;
+                       }
+
+                       if (better_at_least_one)
+                               return true;
+
+                       //
+                       // This handles the case
+                       //
+                       //   Add (float f1, float f2, float f3);
+                       //   Add (params decimal [] foo);
+                       //
+                       // The call Add (3, 4, 5) should be ambiguous.  Without this check, the
+                       // first candidate would've chosen as better.
+                       //
+                       if (!same)
+                               return false;
+
+                       //
+                       // The two methods have equal parameter types.  Now apply tie-breaking rules
+                       //
+                       if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
+                               return true;
+                       if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
+                               return false;
+
+                       //
+                       // This handles the following cases:
+                       //
+                       //   Trim () is better than Trim (params char[] chars)
+                       //   Concat (string s1, string s2, string s3) is better than
+                       //     Concat (string s1, params string [] srest)
+                       //   Foo (int, params int [] rest) is better than Foo (params int [] rest)
+                       //
+                       if (!candidate_params && best_params)
+                               return true;
+                       if (candidate_params && !best_params)
+                               return false;
+
+                       int candidate_param_count = candidate_pd.Count;
+                       int best_param_count = best_pd.Count;
+
+                       if (candidate_param_count != best_param_count)
+                               // can only happen if (candidate_params && best_params)
+                               return candidate_param_count > best_param_count;
+
+                       //
+                       // now, both methods have the same number of parameters, and the parameters have the same types
+                       // Pick the "more specific" signature
+                       //
+
+                       MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
+                       MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
+
+                       ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
+                       ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
+
+                       bool specific_at_least_once = false;
+                       for (int j = 0; j < candidate_param_count; ++j) {
+                               Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
+                               Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
+                               if (ct.Equals (bt))
+                                       continue;
+                               Type specific = MoreSpecific (ct, bt);
+                               if (specific == bt)
+                                       return false;
+                               if (specific == ct)
+                                       specific_at_least_once = true;
+                       }
+
+                       if (specific_at_least_once)
+                               return true;
+
+                       // FIXME: handle lifted operators
+                       // ...
+
+                       return false;
+               }
+
+               internal static bool IsOverride (MethodBase cand_method, MethodBase base_method)
+               {
+                       if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
+                               return false;
+
+                       ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
+                       ParameterData base_pd = TypeManager.GetParameterData (base_method);
+               
+                       if (cand_pd.Count != base_pd.Count)
+                               return false;
+
+                       for (int j = 0; j < cand_pd.Count; ++j) {
+                               Parameter.Modifier cm = cand_pd.ParameterModifier (j);
+                               Parameter.Modifier bm = base_pd.ParameterModifier (j);
+                               Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
+                               Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
+
+                               if (cm != bm || ct != bt)
+                                       return false;
+                       }
+
+                       return true;
+               }
+
+               public static string FullMethodDesc (MethodBase mb)
+               {
+                       if (mb == null)
+                               return "";
+
+                       StringBuilder sb;
+                       if (mb is MethodInfo) {
+                               sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
+                               sb.Append (" ");
+                       }
+                       else
+                               sb = new StringBuilder ();
+
+                       sb.Append (TypeManager.CSharpSignature (mb));
+                       return sb.ToString ();
+               }
+
+               public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
+               {
+                       MemberInfo [] miset;
+                       MethodGroupExpr union;
+
+                       if (mg1 == null) {
+                               if (mg2 == null)
+                                       return null;
+                               return (MethodGroupExpr) mg2;
+                       } else {
+                               if (mg2 == null)
+                                       return (MethodGroupExpr) mg1;
+                       }
+                       
+                       MethodGroupExpr left_set = null, right_set = null;
+                       int length1 = 0, length2 = 0;
+                       
+                       left_set = (MethodGroupExpr) mg1;
+                       length1 = left_set.Methods.Length;
+                       
+                       right_set = (MethodGroupExpr) mg2;
+                       length2 = right_set.Methods.Length;
+                       
+                       ArrayList common = new ArrayList ();
+
+                       foreach (MethodBase r in right_set.Methods){
+                               if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
+                                       common.Add (r);
+                       }
+
+                       miset = new MemberInfo [length1 + length2 - common.Count];
+                       left_set.Methods.CopyTo (miset, 0);
+                       
+                       int k = length1;
+
+                       foreach (MethodBase r in right_set.Methods) {
+                               if (!common.Contains (r))
+                                       miset [k++] = r;
+                       }
+
+                       union = new MethodGroupExpr (miset, loc);
+                       
+                       return union;
+               }
+
+               public static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
+                                                            ArrayList arguments, int arg_count,
+                                                            ref MethodBase candidate)
+               {
+                       return IsParamsMethodApplicable (
+                               ec, me, arguments, arg_count, false, ref candidate) ||
+                               IsParamsMethodApplicable (
+                                       ec, me, arguments, arg_count, true, ref candidate);
+
+
+               }
+
+               static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
+                                                     ArrayList arguments, int arg_count,
+                                                     bool do_varargs, ref MethodBase candidate)
+               {
+#if GMCS_SOURCE
+                       if (!me.HasTypeArguments &&
+                           !TypeManager.InferParamsTypeArguments (ec, arguments, ref candidate))
+                               return false;
+
+                       if (TypeManager.IsGenericMethodDefinition (candidate))
+                               throw new InternalErrorException ("a generic method definition took part in overload resolution");
+#endif
+
+                       return IsParamsMethodApplicable (
+                               ec, arguments, arg_count, candidate, do_varargs);
+               }
+
+               /// <summary>
+               ///   Determines if the candidate method, if a params method, is applicable
+               ///   in its expanded form to the given set of arguments
+               /// </summary>
+               static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
+                                                     int arg_count, MethodBase candidate,
+                                                     bool do_varargs)
+               {
+                       ParameterData pd = TypeManager.GetParameterData (candidate);
+
+                       int pd_count = pd.Count;
+                       if (pd_count == 0)
+                               return false;
+
+                       int count = pd_count - 1;
+                       if (do_varargs) {
+                               if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
+                                       return false;
+                               if (pd_count != arg_count)
+                                       return false;
+                       } else {
+                               if (!pd.HasParams)
+                                       return false;
+                       }
+                       
+                       if (count > arg_count)
+                               return false;
+                       
+                       if (pd_count == 1 && arg_count == 0)
+                               return true;
+
+                       //
+                       // If we have come this far, the case which
+                       // remains is when the number of parameters is
+                       // less than or equal to the argument count.
+                       //
+                       for (int i = 0; i < count; ++i) {
+
+                               Argument a = (Argument) arguments [i];
+
+                               Parameter.Modifier a_mod = a.Modifier & 
+                                       (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
+                               Parameter.Modifier p_mod = pd.ParameterModifier (i) &
+                                       (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
+
+                               if (a_mod == p_mod) {
+
+                                       if (a_mod == Parameter.Modifier.NONE)
+                                               if (!Convert.ImplicitConversionExists (ec,
+                                                                                       a.Expr,
+                                                                                       pd.ParameterType (i)))
+                               return false;
+
+                                       if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
+                                               Type pt = pd.ParameterType (i);
+
+                                               if (!pt.IsByRef)
+                                                       pt = TypeManager.GetReferenceType (pt);
+                                               
+                                               if (pt != a.Type)
+                                                       return false;
+                                       }
+                               } else
+                                       return false;
+                               
+                       }
+
+                       if (do_varargs) {
+                               Argument a = (Argument) arguments [count];
+                               if (!(a.Expr is Arglist))
+                                       return false;
+
+                               return true;
+                       }
+
+                       Type element_type = TypeManager.GetElementType (pd.ParameterType (pd_count - 1));
+
+                       for (int i = pd_count - 1; i < arg_count; i++) {
+                               Argument a = (Argument) arguments [i];
+
+                               if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
+                                       return false;
+                       }
+                       
+                       return true;
+               }
+
+               public static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
+                                                ArrayList arguments, int arg_count,
+                                                ref MethodBase candidate)
+               {
+#if GMCS_SOURCE
+                       if (!me.HasTypeArguments &&
+                           !TypeManager.InferTypeArguments (arguments, ref candidate))
+                               return false;
+
+                       if (TypeManager.IsGenericMethodDefinition (candidate))
+                               throw new InternalErrorException ("a generic method definition took part in overload resolution");
+#endif
+
+                       return IsApplicable (ec, arguments, arg_count, candidate);
+               }
+
+               /// <summary>
+               ///   Determines if the candidate method is applicable (section 14.4.2.1)
+               ///   to the given set of arguments
+               /// </summary>
+               public static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count,
+                       MethodBase candidate)
+               {
+                       ParameterData pd = TypeManager.GetParameterData (candidate);
+
+                       if (arg_count != pd.Count)
+                               return false;
+
+                       for (int i = arg_count; i > 0; ) {
+                               i--;
+
+                               Argument a = (Argument) arguments [i];
+
+                               Parameter.Modifier a_mod = a.Modifier &
+                                       ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
+
+                               Parameter.Modifier p_mod = pd.ParameterModifier (i) &
+                                       ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK | Parameter.Modifier.PARAMS);
+
+                               if (a_mod == p_mod) {
+                                       Type pt = pd.ParameterType (i);
+
+                                       if (a_mod == Parameter.Modifier.NONE) {
+                                                if (!TypeManager.IsEqual (a.Type, pt) &&
+                                                   !Convert.ImplicitConversionExists (ec, a.Expr, pt))
+                                                       return false;
+                                               continue;
+                                       }
+                                       
+                                       if (pt != a.Type)
+                                               return false;
+                               } else
+                                       return false;
+                       }
+
+                       return true;
+               }
+
+               static internal bool IsAncestralType (Type first_type, Type second_type)
+               {
+                       return first_type != second_type &&
+                               (TypeManager.IsSubclassOf (second_type, first_type) ||
+                                TypeManager.ImplementsInterface (second_type, first_type));
+               }
+               
+               /// <summary>
+               ///   Find the Applicable Function Members (7.4.2.1)
+               ///
+               ///   me: Method Group expression with the members to select.
+               ///       it might contain constructors or methods (or anything
+               ///       that maps to a method).
+               ///
+               ///   Arguments: ArrayList containing resolved Argument objects.
+               ///
+               ///   loc: The location if we want an error to be reported, or a Null
+               ///        location for "probing" purposes.
+               ///
+               ///   Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
+               ///            that is the best match of me on Arguments.
+               ///
+               /// </summary>
+               public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
+                                                         ArrayList Arguments, bool may_fail,
+                                                         Location loc)
+               {
+                       MethodBase method = null;
+                       bool method_params = false;
+                       Type applicable_type = null;
+                       int arg_count = 0;
+                       ArrayList candidates = new ArrayList (2);
+                       ArrayList candidate_overrides = null;
+
+                        //
+                        // Used to keep a map between the candidate
+                        // and whether it is being considered in its
+                        // normal or expanded form
+                        //
+                        // false is normal form, true is expanded form
+                        //
+                        Hashtable candidate_to_form = null;
+
+                       if (Arguments != null)
+                               arg_count = Arguments.Count;
+
+                       if ((me.Name == "Invoke") &&
+                               TypeManager.IsDelegateType (me.DeclaringType)) {
+                               Error_InvokeOnDelegate (loc);
+                               return null;
+                       }
+
+                       MethodBase[] methods = me.Methods;
+
+                       int nmethods = methods.Length;
+
+                       if (!me.IsBase) {
+                               //
+                               // Methods marked 'override' don't take part in 'applicable_type'
+                               // computation, nor in the actual overload resolution.
+                               // However, they still need to be emitted instead of a base virtual method.
+                               // So, we salt them away into the 'candidate_overrides' array.
+                               //
+                               // In case of reflected methods, we replace each overriding method with
+                               // its corresponding base virtual method.  This is to improve compatibility
+                               // with non-C# libraries which change the visibility of overrides (#75636)
+                               //
+                               int j = 0;
+                               for (int i = 0; i < methods.Length; ++i) {
+                                       MethodBase m = methods [i];
+#if GMCS_SOURCE
+                                       Type [] gen_args = null;
+                                       if (m.IsGenericMethod && !m.IsGenericMethodDefinition)
+                                               gen_args = m.GetGenericArguments ();
+#endif
+                                       if (TypeManager.IsOverride (m)) {
+                                               if (candidate_overrides == null)
+                                                       candidate_overrides = new ArrayList ();
+                                               candidate_overrides.Add (m);
+                                               m = TypeManager.TryGetBaseDefinition (m);
+#if GMCS_SOURCE
+                                               if (m != null && gen_args != null) {
+                                                       if (!m.IsGenericMethodDefinition)
+                                                               throw new InternalErrorException ("GetBaseDefinition didn't return a GenericMethodDefinition");
+                                                       m = ((MethodInfo) m).MakeGenericMethod (gen_args);
+                                               }
+#endif
+                                       }
+                                       if (m != null)
+                                               methods [j++] = m;
+                               }
+                               nmethods = j;
+                       }
+
+                       int applicable_errors = Report.Errors;
+                       
+                       //
+                       // First we construct the set of applicable methods
+                       //
+                       bool is_sorted = true;
+                       for (int i = 0; i < nmethods; i++){
+                               Type decl_type = methods [i].DeclaringType;
+
+                               //
+                               // If we have already found an applicable method
+                               // we eliminate all base types (Section 14.5.5.1)
+                               //
+                               if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
+                                       continue;
+
+                               //
+                               // Check if candidate is applicable (section 14.4.2.1)
+                               //   Is candidate applicable in normal form?
+                               //
+                               bool is_applicable = IsApplicable (ec, me, Arguments, arg_count, ref methods [i]);
+
+                               if (!is_applicable && IsParamsMethodApplicable (ec, me, Arguments, arg_count, ref methods [i])) {
+                                       MethodBase candidate = methods [i];
+                                       if (candidate_to_form == null)
+                                               candidate_to_form = new PtrHashtable ();
+                                       candidate_to_form [candidate] = candidate;
+                                       // Candidate is applicable in expanded form
+                                       is_applicable = true;
+                               }
+
+                               if (!is_applicable)
+                                       continue;
+
+                               candidates.Add (methods [i]);
+
+                               if (applicable_type == null)
+                                       applicable_type = decl_type;
+                               else if (applicable_type != decl_type) {
+                                       is_sorted = false;
+                                       if (IsAncestralType (applicable_type, decl_type))
+                                               applicable_type = decl_type;
+                               }
+                       }
+
+                       if (applicable_errors != Report.Errors)
+                               return null;
+                       
+                       int candidate_top = candidates.Count;
+
+                       if (applicable_type == null) {
+                               //
+                               // Okay so we have failed to find anything so we
+                               // return by providing info about the closest match
+                               //
+                               int errors = Report.Errors;
+                               for (int i = 0; i < nmethods; ++i) {
+                                       MethodBase c = (MethodBase) methods [i];
+                                       ParameterData pd = TypeManager.GetParameterData (c);
+
+                                       if (pd.Count != arg_count)
+                                               continue;
+
+#if GMCS_SOURCE
+                                       if (!TypeManager.InferTypeArguments (Arguments, ref c))
+                                               continue;
+                                       if (TypeManager.IsGenericMethodDefinition (c))
+                                               continue;
+#endif
+
+                                       VerifyArgumentsCompat (ec, Arguments, arg_count,
+                                               c, false, null, may_fail, loc);
+
+                                       if (!may_fail && errors == Report.Errors)
+                                               throw new InternalErrorException (
+                                                       "VerifyArgumentsCompat and IsApplicable do not agree; " +
+                                                       "likely reason: ImplicitConversion and ImplicitConversionExists have gone out of sync");
+
+                                       break;
+                               }
+
+                               if (!may_fail && errors == Report.Errors) {
+                                       string report_name = me.Name;
+                                       if (report_name == ".ctor")
+                                               report_name = TypeManager.CSharpName (me.DeclaringType);
+                                        
+#if GMCS_SOURCE
+                                       //
+                                       // Type inference
+                                       //
+                                       for (int i = 0; i < methods.Length; ++i) {
+                                               MethodBase c = methods [i];
+                                               ParameterData pd = TypeManager.GetParameterData (c);
+
+                                               if (pd.Count != arg_count)
+                                                       continue;
+
+                                               if (TypeManager.InferTypeArguments (Arguments, ref c))
+                                                       continue;
+
+                                               Report.Error (
+                                                       411, loc, "The type arguments for " +
+                                                       "method `{0}' cannot be infered from " +
+                                                       "the usage. Try specifying the type " +
+                                                       "arguments explicitly.", report_name);
+                                               return null;
+                                       }
+#endif
+
+                                       Error_WrongNumArguments (loc, report_name, arg_count);
+                               }
+                                
+                               return null;
+                       }
+
+                       if (!is_sorted) {
+                               //
+                               // At this point, applicable_type is _one_ of the most derived types
+                               // in the set of types containing the methods in this MethodGroup.
+                               // Filter the candidates so that they only contain methods from the
+                               // most derived types.
+                               //
+
+                               int finalized = 0; // Number of finalized candidates
+
+                               do {
+                                       // Invariant: applicable_type is a most derived type
+                                       
+                                       // We'll try to complete Section 14.5.5.1 for 'applicable_type' by 
+                                       // eliminating all it's base types.  At the same time, we'll also move
+                                       // every unrelated type to the end of the array, and pick the next
+                                       // 'applicable_type'.
+
+                                       Type next_applicable_type = null;
+                                       int j = finalized; // where to put the next finalized candidate
+                                       int k = finalized; // where to put the next undiscarded candidate
+                                       for (int i = finalized; i < candidate_top; ++i) {
+                                               MethodBase candidate = (MethodBase) candidates [i];
+                                               Type decl_type = candidate.DeclaringType;
+
+                                               if (decl_type == applicable_type) {
+                                                       candidates [k++] = candidates [j];
+                                                       candidates [j++] = candidates [i];
+                                                       continue;
+                                               }
+
+                                               if (IsAncestralType (decl_type, applicable_type))
+                                                       continue;
+
+                                               if (next_applicable_type != null &&
+                                                   IsAncestralType (decl_type, next_applicable_type))
+                                                       continue;
+
+                                               candidates [k++] = candidates [i];
+
+                                               if (next_applicable_type == null ||
+                                                   IsAncestralType (next_applicable_type, decl_type))
+                                                       next_applicable_type = decl_type;
+                                       }
+
+                                       applicable_type = next_applicable_type;
+                                       finalized = j;
+                                       candidate_top = k;
+                               } while (applicable_type != null);
+                       }
+
+                        //
+                        // Now we actually find the best method
+                        //
+
+                       method = (MethodBase) candidates [0];
+                       method_params = candidate_to_form != null && candidate_to_form.Contains (method);
+                       for (int ix = 1; ix < candidate_top; ix++){
+                               MethodBase candidate = (MethodBase) candidates [ix];
+
+                               if (candidate == method)
+                                       continue;
+
+                               bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
+
+                               if (BetterFunction (ec, Arguments, arg_count, 
+                                                   candidate, cand_params,
+                                                   method, method_params)) {
+                                       method = candidate;
+                                       method_params = cand_params;
+                               }
+                       }
+                       //
+                       // Now check that there are no ambiguities i.e the selected method
+                       // should be better than all the others
+                       //
+                       MethodBase ambiguous = null;
+                       for (int ix = 0; ix < candidate_top; ix++){
+                               MethodBase candidate = (MethodBase) candidates [ix];
+
+                                if (candidate == method)
+                                        continue;
+
+                                bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
+                               if (!BetterFunction (ec, Arguments, arg_count,
+                                                    method, method_params,
+                                                    candidate, cand_params)) {
+                                       Report.SymbolRelatedToPreviousError (candidate);
+                                       ambiguous = candidate;
+                               }
+                       }
+
+                       if (ambiguous != null) {
+                               Report.SymbolRelatedToPreviousError (method);
+                               Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
+                                       TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (method));
+                               return null;
+                       }
+
+                       //
+                       // If the method is a virtual function, pick an override closer to the LHS type.
+                       //
+                       if (!me.IsBase && method.IsVirtual) {
+                               if (TypeManager.IsOverride (method))
+                                       throw new InternalErrorException (
+                                               "Should not happen.  An 'override' method took part in overload resolution: " + method);
+
+                               if (candidate_overrides != null)
+                                       foreach (MethodBase candidate in candidate_overrides) {
+                                               if (IsOverride (candidate, method))
+                                                       method = candidate;
+                                       }
+                       }
+
+                       //
+                       // And now check if the arguments are all
+                       // compatible, perform conversions if
+                       // necessary etc. and return if everything is
+                       // all right
+                       //
+                        if (!VerifyArgumentsCompat (ec, Arguments, arg_count, method,
+                                                    method_params, null, may_fail, loc))
+                               return null;
+
+                       if (method == null)
+                               return null;
+
+                       MethodBase the_method = TypeManager.DropGenericMethodArguments (method);
+#if GMCS_SOURCE
+                       if (the_method.IsGenericMethodDefinition &&
+                           !ConstraintChecker.CheckConstraints (ec, the_method, method, loc))
+                               return null;
+#endif
+
+                       IMethodData data = TypeManager.GetMethod (the_method);
+                       if (data != null)
+                               data.SetMemberIsUsed ();
+
+                       return method;
+               }
+
+               public static void Error_WrongNumArguments (Location loc, String name, int arg_count)
+               {
+                       Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
+                               name, arg_count.ToString ());
+               }
+
+                static void Error_InvokeOnDelegate (Location loc)
+                {
+                        Report.Error (1533, loc,
+                                      "Invoke cannot be called directly on a delegate");
+                }
+                        
+               static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
+                                                    Type delegate_type, Argument a, ParameterData expected_par)
+               {
+                       if (delegate_type == null) 
+                               Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
+                                             TypeManager.CSharpSignature (method));
+                       else
+                               Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
+                                       TypeManager.CSharpName (delegate_type));
+
+                       Parameter.Modifier mod = expected_par.ParameterModifier (idx);
+
+                       string index = (idx + 1).ToString ();
+                       if (mod != Parameter.Modifier.ARGLIST && mod != a.Modifier) {
+                               if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
+                                       Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
+                                               index, Parameter.GetModifierSignature (a.Modifier));
+                               else
+                                       Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
+                                               index, Parameter.GetModifierSignature (mod));
+                       } else {
+                               Report.Error (1503, loc, "Argument {0}: Cannot convert from `{1}' to `{2}'",
+                                       index, Argument.FullDesc (a), expected_par.ParameterDesc (idx));
+                       }
+               }
+               
+               public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
+                                                         int arg_count, MethodBase method, 
+                                                         bool chose_params_expanded,
+                                                         Type delegate_type, bool may_fail,
+                                                         Location loc)
+               {
+                       ParameterData pd = TypeManager.GetParameterData (method);
+                       int j;
+                       for (j = 0; j < arg_count; j++) {
+                               Argument a = (Argument) Arguments [j];
+                               Expression a_expr = a.Expr;
+                               Type parameter_type = pd.ParameterType (j);
+                               Parameter.Modifier pm = pd.ParameterModifier (j);
+                               Parameter.Modifier am = a.Modifier;
+
+                               if (pm == Parameter.Modifier.ARGLIST) {
+                                       if (!(a.Expr is Arglist))
+                                               break;
+                                       continue;
+                               }
+
+                               if (pm == Parameter.Modifier.PARAMS) {
+                                       pm = Parameter.Modifier.NONE;
+                                       if (chose_params_expanded)
+                                               parameter_type = TypeManager.GetElementType (parameter_type);
+                               }
+
+                               if (pm != am)
+                                       break;
+
+                               if (!TypeManager.IsEqual (a.Type, parameter_type)) {
+                                       if (pm == Parameter.Modifier.OUT || pm == Parameter.Modifier.REF)
+                                               break;
+
+                                       Expression conv = Convert.ImplicitConversion (ec, a_expr, parameter_type, loc);
+                                       if (conv == null)
+                                               break;
+
+                                       // Update the argument with the implicit conversion
+                                       if (a_expr != conv)
+                                               a.Expr = conv;
+                               }
+
+                               if (parameter_type.IsPointer && !ec.InUnsafe) {
+                                       UnsafeError (loc);
+                                       return false;
+                               }
+                       }
+
+                       if (j == arg_count)
+                               return true;
+
+                       if (!may_fail)
+                               Error_InvalidArguments (loc, j, method, delegate_type, (Argument) Arguments [j], pd);
+                       return false;
+               }
+
+               private bool resolved = false;
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       if (resolved)
+                               return this.method == null ? null : this;
+
+                       resolved = true;
+                       //
+                       // First, resolve the expression that is used to
+                       // trigger the invocation
+                       //
+                       SimpleName sn = expr as SimpleName;
+                       if (sn != null)
+                               expr = sn.GetMethodGroup ();
+
+                       expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
+                       if (expr == null)
+                               return null;
+
+                       if (!(expr is MethodGroupExpr)) {
+                               Type expr_type = expr.Type;
+
+                               if (expr_type != null){
+                                       bool IsDelegate = TypeManager.IsDelegateType (expr_type);
+                                       if (IsDelegate)
+                                               return (new DelegateInvocation (
+                                                       this.expr, Arguments, loc)).Resolve (ec);
+                               }
+                       }
+
+                       if (!(expr is MethodGroupExpr)){
+                               expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
+                               return null;
+                       }
+
+                       //
+                       // Next, evaluate all the expressions in the argument list
+                       //
+                       if (Arguments != null){
+                               foreach (Argument a in Arguments){
+                                       if (!a.Resolve (ec, loc))
+                                               return null;
+                               }
+                       }
+
+                       MethodGroupExpr mg = (MethodGroupExpr) expr;
+                       MethodBase method = OverloadResolve (ec, mg, Arguments, false, loc);
+
+                       if (method == null)
+                               return null;
+
+                       MethodInfo mi = method as MethodInfo;
+                       if (mi != null) {
+                               type = TypeManager.TypeToCoreType (mi.ReturnType);
+                               Expression iexpr = mg.InstanceExpression;
+                               if (mi.IsStatic) {
+                                       if (iexpr == null || 
+                                           iexpr is This || iexpr is EmptyExpression ||
+                                           mg.IdenticalTypeName) {
+                                               mg.InstanceExpression = null;
+                                       } else {
+                                               MemberExpr.error176 (loc, TypeManager.CSharpSignature (mi));
+                                               return null;
+                                       }
+                               } else {
+                                       if (iexpr == null || iexpr is EmptyExpression) {
+                                               SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (mi));
+                                               return null;
+                                       }
+                               }
+                       }
+
+                       if (type.IsPointer){
+                               if (!ec.InUnsafe){
+                                       UnsafeError (loc);
+                                       return null;
+                               }
+                       }
+                       
+                       //
+                       // Only base will allow this invocation to happen.
+                       //
+                       if (mg.IsBase && method.IsAbstract){
+                               Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
+                               return null;
+                       }
+
+                       if (Arguments == null && method.Name == "Finalize") {
+                               if (mg.IsBase)
+                                       Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
+                               else
+                                       Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
+                               return null;
+                       }
+
+                       if ((method.Attributes & MethodAttributes.SpecialName) != 0 && IsSpecialMethodInvocation (method)) {
+                               return null;
+                       }
+                       
+                       if (mg.InstanceExpression != null)
+                               mg.InstanceExpression.CheckMarshalByRefAccess ();
+
+                       eclass = ExprClass.Value;
+                       this.method = method;
+                       return this;
+               }
+
+               bool IsSpecialMethodInvocation (MethodBase method)
+               {
+                       IMethodData md = TypeManager.GetMethod (method);
+                       if (md != null) {
+                               if (!(md is AbstractPropertyEventMethod) && !(md is Operator))
+                                       return false;
+                       } else {
+                               if (!TypeManager.IsSpecialMethod (method))
+                                       return false;
+
+                               int args = TypeManager.GetParameterData (method).Count;
+                               if (method.Name.StartsWith ("get_") && args > 0)
+                                       return false;
+                               else if (method.Name.StartsWith ("set_") && args > 2)
+                                       return false;
+
+                               // TODO: check operators and events as well ?
+                       }
+
+                       Report.SymbolRelatedToPreviousError (method);
+                       Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
+                               TypeManager.CSharpSignature (method, true));
+       
+                       return true;
+               }
+
+               // <summary>
+               //   Emits the list of arguments as an array
+               // </summary>
+               static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
+               {
+                       ILGenerator ig = ec.ig;
+                       int count = arguments.Count - idx;
+                       Argument a = (Argument) arguments [idx];
+                       Type t = a.Expr.Type;
+
+                       IntConstant.EmitInt (ig, count);
+                       ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
+
+                       int top = arguments.Count;
+                       for (int j = idx; j < top; j++){
+                               a = (Argument) arguments [j];
+                               
+                               ig.Emit (OpCodes.Dup);
+                               IntConstant.EmitInt (ig, j - idx);
+
+                               bool is_stobj, has_type_arg;
+                               OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
+                               if (is_stobj)
+                                       ig.Emit (OpCodes.Ldelema, t);
+
+                               a.Emit (ec);
+
+                               if (has_type_arg)
+                                       ig.Emit (op, t);
+                               else
+                                       ig.Emit (op);
+                       }
+               }
+               
+               /// <summary>
+               ///   Emits a list of resolved Arguments that are in the arguments
+               ///   ArrayList.
+               /// 
+               ///   The MethodBase argument might be null if the
+               ///   emission of the arguments is known not to contain
+               ///   a `params' field (for example in constructors or other routines
+               ///   that keep their arguments in this structure)
+               ///   
+               ///   if `dup_args' is true, a copy of the arguments will be left
+               ///   on the stack. If `dup_args' is true, you can specify `this_arg'
+               ///   which will be duplicated before any other args. Only EmitCall
+               ///   should be using this interface.
+               /// </summary>
+               public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
+               {
+                       ParameterData pd = mb == null ? null : TypeManager.GetParameterData (mb);
+                       int top = arguments == null ? 0 : arguments.Count;
+                       LocalTemporary [] temps = null;
+                       
+                       if (dup_args && top != 0)
+                               temps = new LocalTemporary [top];
+
+                       for (int i = 0; i < top; i++){
+                               Argument a = (Argument) arguments [i];
+
+                               if (pd != null){
+                                       if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
+                                               //
+                                               // Special case if we are passing the same data as the
+                                               // params argument, do not put it in an array.
+                                               //
+                                               if (pd.ParameterType (i) == a.Type)
+                                                       a.Emit (ec);
+                                               else
+                                                       EmitParams (ec, i, arguments);
+                                               return;
+                                       }
+                               }
+                                           
+                               a.Emit (ec);
+                               if (dup_args) {
+                                       ec.ig.Emit (OpCodes.Dup);
+                                       (temps [i] = new LocalTemporary (a.Type)).Store (ec);
+                               }
+                       }
+                       
+                       if (dup_args) {
+                               if (this_arg != null)
+                                       this_arg.Emit (ec);
+                               
+                               for (int i = 0; i < top; i ++) {
+                                       temps [i].Emit (ec);
+                                       temps [i].Release (ec);
+                               }
+                       }
+
+                       if (pd != null && pd.Count > top &&
+                           pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
+                               ILGenerator ig = ec.ig;
+
+                               IntConstant.EmitInt (ig, 0);
+                               ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (top)));
+                       }
+               }
+
+               static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
+               {
+                       ParameterData pd = TypeManager.GetParameterData (mb);
+
+                       if (arguments == null)
+                               return new Type [0];
+
+                       Argument a = (Argument) arguments [pd.Count - 1];
+                       Arglist list = (Arglist) a.Expr;
+
+                       return list.ArgumentTypes;
+               }
+
+               /// <summary>
+               /// This checks the ConditionalAttribute on the method 
+               /// </summary>
+               static bool IsMethodExcluded (MethodBase method)
+               {
+                       if (method.IsConstructor)
+                               return false;
+
+                       IMethodData md = TypeManager.GetMethod (method);
+                       if (md != null)
+                               return md.IsExcluded ();
+
+                       // For some methods (generated by delegate class) GetMethod returns null
+                       // because they are not included in builder_to_method table
+                       if (method.DeclaringType is TypeBuilder)
+                               return false;
+
+                       return AttributeTester.IsConditionalMethodExcluded (method);
+               }
+
+               /// <remarks>
+               ///   is_base tells whether we want to force the use of the `call'
+               ///   opcode instead of using callvirt.  Call is required to call
+               ///   a specific method, while callvirt will always use the most
+               ///   recent method in the vtable.
+               ///
+               ///   is_static tells whether this is an invocation on a static method
+               ///
+               ///   instance_expr is an expression that represents the instance
+               ///   it must be non-null if is_static is false.
+               ///
+               ///   method is the method to invoke.
+               ///
+               ///   Arguments is the list of arguments to pass to the method or constructor.
+               /// </remarks>
+               public static void EmitCall (EmitContext ec, bool is_base,
+                                            bool is_static, Expression instance_expr,
+                                            MethodBase method, ArrayList Arguments, Location loc)
+               {
+                       EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, loc, false, false);
+               }
+               
+               // `dup_args' leaves an extra copy of the arguments on the stack
+               // `omit_args' does not leave any arguments at all.
+               // So, basically, you could make one call with `dup_args' set to true,
+               // and then another with `omit_args' set to true, and the two calls
+               // would have the same set of arguments. However, each argument would
+               // only have been evaluated once.
+               public static void EmitCall (EmitContext ec, bool is_base,
+                                            bool is_static, Expression instance_expr,
+                                            MethodBase method, ArrayList Arguments, Location loc,
+                                            bool dup_args, bool omit_args)
+               {
+                       ILGenerator ig = ec.ig;
+                       bool struct_call = false;
+                       bool this_call = false;
+                       LocalTemporary this_arg = null;
+
+                       Type decl_type = method.DeclaringType;
+
+                       if (!RootContext.StdLib) {
+                               // Replace any calls to the system's System.Array type with calls to
+                               // the newly created one.
+                               if (method == TypeManager.system_int_array_get_length)
+                                       method = TypeManager.int_array_get_length;
+                               else if (method == TypeManager.system_int_array_get_rank)
+                                       method = TypeManager.int_array_get_rank;
+                               else if (method == TypeManager.system_object_array_clone)
+                                       method = TypeManager.object_array_clone;
+                               else if (method == TypeManager.system_int_array_get_length_int)
+                                       method = TypeManager.int_array_get_length_int;
+                               else if (method == TypeManager.system_int_array_get_lower_bound_int)
+                                       method = TypeManager.int_array_get_lower_bound_int;
+                               else if (method == TypeManager.system_int_array_get_upper_bound_int)
+                                       method = TypeManager.int_array_get_upper_bound_int;
+                               else if (method == TypeManager.system_void_array_copyto_array_int)
+                                       method = TypeManager.void_array_copyto_array_int;
+                       }
+
+                       if (!ec.IsInObsoleteScope) {
+                               //
+                               // This checks ObsoleteAttribute on the method and on the declaring type
+                               //
+                               ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
+                               if (oa != null)
+                                       AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
+
+                               oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
+                               if (oa != null) {
+                                       AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
+                               }
+                       }
+
+                       if (IsMethodExcluded (method))
+                               return;
+                       
+                       if (!is_static){
+                               if (instance_expr == EmptyExpression.Null) {
+                                       SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
+                                       return;
+                               }
+
+                               this_call = instance_expr is This;
+                               if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
+                                       struct_call = true;
+
+                               //
+                               // If this is ourselves, push "this"
+                               //
+                               if (!omit_args) {
+                                       Type t = null;
+                                       Type iexpr_type = instance_expr.Type;
+
+                                       //
+                                       // Push the instance expression
+                                       //
+                                       if (TypeManager.IsValueType (iexpr_type)) {
+                                               //
+                                               // Special case: calls to a function declared in a 
+                                               // reference-type with a value-type argument need
+                                               // to have their value boxed.
+                                               if (decl_type.IsValueType ||
+                                                   TypeManager.IsGenericParameter (iexpr_type)) {
+                                                       //
+                                                       // If the expression implements IMemoryLocation, then
+                                                       // we can optimize and use AddressOf on the
+                                                       // return.
+                                                       //
+                                                       // If not we have to use some temporary storage for
+                                                       // it.
+                                                       if (instance_expr is IMemoryLocation) {
+                                                               ((IMemoryLocation)instance_expr).
+                                                                       AddressOf (ec, AddressOp.LoadStore);
+                                                       } else {
+                                                               LocalTemporary temp = new LocalTemporary (iexpr_type);
+                                                               instance_expr.Emit (ec);
+                                                               temp.Store (ec);
+                                                               temp.AddressOf (ec, AddressOp.Load);
+                                                       }
+
+                                                       // avoid the overhead of doing this all the time.
+                                                       if (dup_args)
+                                                               t = TypeManager.GetReferenceType (iexpr_type);
+                                               } else {
+                                                       instance_expr.Emit (ec);
+                                                       ig.Emit (OpCodes.Box, instance_expr.Type);
+                                                       t = TypeManager.object_type;
+                                               }
+                                       } else {
+                                               instance_expr.Emit (ec);
+                                               t = instance_expr.Type;
+                                       }
+
+                                       if (dup_args) {
+                                               ig.Emit (OpCodes.Dup);
+                                               if (Arguments != null && Arguments.Count != 0) {
+                                                       this_arg = new LocalTemporary (t);
+                                                       this_arg.Store (ec);
+                                               }
+                                       }
+                               }
+                       }
+
+                       if (!omit_args)
+                               EmitArguments (ec, method, Arguments, dup_args, this_arg);
+
+#if GMCS_SOURCE
+                       if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
+                               ig.Emit (OpCodes.Constrained, instance_expr.Type);
+#endif
+
+                       OpCode call_op;
+                       if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
+                               call_op = OpCodes.Call;
+                       else
+                               call_op = OpCodes.Callvirt;
+
+                       if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
+                               Type[] varargs_types = GetVarargsTypes (method, Arguments);
+                               ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
+                               return;
+                       }
+
+                       //
+                       // If you have:
+                       // this.DoFoo ();
+                       // and DoFoo is not virtual, you can omit the callvirt,
+                       // because you don't need the null checking behavior.
+                       //
+                       if (method is MethodInfo)
+                               ig.Emit (call_op, (MethodInfo) method);
+                       else
+                               ig.Emit (call_op, (ConstructorInfo) method);
+               }
+               
+               public override void Emit (EmitContext ec)
+               {
+                       MethodGroupExpr mg = (MethodGroupExpr) this.expr;
+
+                       EmitCall (ec, mg.IsBase, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
+               }
+               
+               public override void EmitStatement (EmitContext ec)
+               {
+                       Emit (ec);
+
+                       // 
+                       // Pop the return value if there is one
+                       //
+                       if (method is MethodInfo){
+                               Type ret = ((MethodInfo)method).ReturnType;
+                               if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
+                                       ec.ig.Emit (OpCodes.Pop);
+                       }
+               }
+       }
+
+       public class InvocationOrCast : ExpressionStatement
+       {
+               Expression expr;
+               Expression argument;
+
+               public InvocationOrCast (Expression expr, Expression argument)
+               {
+                       this.expr = expr;
+                       this.argument = argument;
+                       this.loc = expr.Location;
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       //
+                       // First try to resolve it as a cast.
+                       //
+                       TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
+                       if ((te != null) && (te.eclass == ExprClass.Type)) {
+                               Cast cast = new Cast (te, argument, loc);
+                               return cast.Resolve (ec);
+                       }
+
+                       //
+                       // This can either be a type or a delegate invocation.
+                       // Let's just resolve it and see what we'll get.
+                       //
+                       expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
+                       if (expr == null)
+                               return null;
+
+                       //
+                       // Ok, so it's a Cast.
+                       //
+                       if (expr.eclass == ExprClass.Type) {
+                               Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
+                               return cast.Resolve (ec);
+                       }
+
+                       //
+                       // It's a delegate invocation.
+                       //
+                       if (!TypeManager.IsDelegateType (expr.Type)) {
+                               Error (149, "Method name expected");
+                               return null;
+                       }
+
+                       ArrayList args = new ArrayList ();
+                       args.Add (new Argument (argument, Argument.AType.Expression));
+                       DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
+                       return invocation.Resolve (ec);
+               }
+
+               void error201 ()
+               {
+                       Error (201, "Only assignment, call, increment, decrement and new object " +
+                              "expressions can be used as a statement");
+               }
+
+               public override ExpressionStatement ResolveStatement (EmitContext ec)
+               {
+                       //
+                       // First try to resolve it as a cast.
+                       //
+                       TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
+                       if ((te != null) && (te.eclass == ExprClass.Type)) {
+                               error201 ();
+                               return null;
+                       }
+
+                       //
+                       // This can either be a type or a delegate invocation.
+                       // Let's just resolve it and see what we'll get.
+                       //
+                       expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
+                       if ((expr == null) || (expr.eclass == ExprClass.Type)) {
+                               error201 ();
+                               return null;
+                       }
+
+                       //
+                       // It's a delegate invocation.
+                       //
+                       if (!TypeManager.IsDelegateType (expr.Type)) {
+                               Error (149, "Method name expected");
+                               return null;
+                       }
+
+                       ArrayList args = new ArrayList ();
+                       args.Add (new Argument (argument, Argument.AType.Expression));
+                       DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
+                       return invocation.ResolveStatement (ec);
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       throw new Exception ("Cannot happen");
+               }
+
+               public override void EmitStatement (EmitContext ec)
+               {
+                       throw new Exception ("Cannot happen");
+               }
+       }
+
+       //
+       // This class is used to "disable" the code generation for the
+       // temporary variable when initializing value types.
+       //
+       class EmptyAddressOf : EmptyExpression, IMemoryLocation {
+               public void AddressOf (EmitContext ec, AddressOp Mode)
+               {
+                       // nothing
+               }
+       }
+       
+       /// <summary>
+       ///    Implements the new expression 
+       /// </summary>
+       public class New : ExpressionStatement, IMemoryLocation {
+               public readonly ArrayList Arguments;
+
+               //
+               // During bootstrap, it contains the RequestedType,
+               // but if `type' is not null, it *might* contain a NewDelegate
+               // (because of field multi-initialization)
+               //
+               public Expression RequestedType;
+
+               MethodBase method = null;
+
+               //
+               // If set, the new expression is for a value_target, and
+               // we will not leave anything on the stack.
+               //
+               Expression value_target;
+               bool value_target_set = false;
+               bool is_type_parameter = false;
+               
+               public New (Expression requested_type, ArrayList arguments, Location l)
+               {
+                       RequestedType = requested_type;
+                       Arguments = arguments;
+                       loc = l;
+               }
+
+               public bool SetValueTypeVariable (Expression value)
+               {
+                       value_target = value;
+                       value_target_set = true;
+                       if (!(value_target is IMemoryLocation)){
+                               Error_UnexpectedKind (null, "variable", loc);
+                               return false;
+                       }
+                       return true;
+               }
+
+               //
+               // This function is used to disable the following code sequence for
+               // value type initialization:
+               //
+               // AddressOf (temporary)
+               // Construct/Init
+               // LoadTemporary
+               //
+               // Instead the provide will have provided us with the address on the
+               // stack to store the results.
+               //
+               static Expression MyEmptyExpression;
+               
+               public void DisableTemporaryValueType ()
+               {
+                       if (MyEmptyExpression == null)
+                               MyEmptyExpression = new EmptyAddressOf ();
+
+                       //
+                       // To enable this, look into:
+                       // test-34 and test-89 and self bootstrapping.
+                       //
+                       // For instance, we can avoid a copy by using `newobj'
+                       // instead of Call + Push-temp on value types.
+//                     value_target = MyEmptyExpression;
+               }
+
+
+               /// <summary>
+               /// Converts complex core type syntax like 'new int ()' to simple constant
+               /// </summary>
+               public static Constant Constantify (Type t)
+               {
+                       if (t == TypeManager.int32_type)
+                               return new IntConstant (0, Location.Null);
+                       if (t == TypeManager.uint32_type)
+                               return new UIntConstant (0, Location.Null);
+                       if (t == TypeManager.int64_type)
+                               return new LongConstant (0, Location.Null);
+                       if (t == TypeManager.uint64_type)
+                               return new ULongConstant (0, Location.Null);
+                       if (t == TypeManager.float_type)
+                               return new FloatConstant (0, Location.Null);
+                       if (t == TypeManager.double_type)
+                               return new DoubleConstant (0, Location.Null);
+                       if (t == TypeManager.short_type)
+                               return new ShortConstant (0, Location.Null);
+                       if (t == TypeManager.ushort_type)
+                               return new UShortConstant (0, Location.Null);
+                       if (t == TypeManager.sbyte_type)
+                               return new SByteConstant (0, Location.Null);
+                       if (t == TypeManager.byte_type)
+                               return new ByteConstant (0, Location.Null);
+                       if (t == TypeManager.char_type)
+                               return new CharConstant ('\0', Location.Null);
+                       if (t == TypeManager.bool_type)
+                               return new BoolConstant (false, Location.Null);
+                       if (t == TypeManager.decimal_type)
+                               return new DecimalConstant (0, Location.Null);
+                       if (TypeManager.IsEnumType (t))
+                               return new EnumConstant (Constantify (TypeManager.EnumToUnderlying (t)), t);
+
+                       return null;
+               }
+
+               //
+               // Checks whether the type is an interface that has the
+               // [ComImport, CoClass] attributes and must be treated
+               // specially
+               //
+               public Expression CheckComImport (EmitContext ec)
+               {
+                       if (!type.IsInterface)
+                               return null;
+
+                       //
+                       // Turn the call into:
+                       // (the-interface-stated) (new class-referenced-in-coclassattribute ())
+                       //
+                       Type real_class = AttributeTester.GetCoClassAttribute (type);
+                       if (real_class == null)
+                               return null;
+
+                       New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
+                       Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
+                       return cast.Resolve (ec);
+               }
+               
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       //
+                       // The New DoResolve might be called twice when initializing field
+                       // expressions (see EmitFieldInitializers, the call to
+                       // GetInitializerExpression will perform a resolve on the expression,
+                       // and later the assign will trigger another resolution
+                       //
+                       // This leads to bugs (#37014)
+                       //
+                       if (type != null){
+                               if (RequestedType is NewDelegate)
+                                       return RequestedType;
+                               return this;
+                       }
+
+                       TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
+                       if (texpr == null)
+                               return null;
+
+                       type = texpr.Type;
+
+                       if (type == TypeManager.void_type) {
+                               Error_VoidInvalidInTheContext (loc);
+                               return null;
+                       }
+
+                       if (Arguments == null) {
+                               Expression c = Constantify (type);
+                               if (c != null)
+                                       return c;
+                       }
+
+                       if (TypeManager.IsDelegateType (type)) {
+                               RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
+                               if (RequestedType != null)
+                                       if (!(RequestedType is DelegateCreation))
+                                               throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
+                               return RequestedType;
+                       }
+
+#if GMCS_SOURCE
+                       if (type.IsGenericParameter) {
+                               GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
+
+                               if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
+                                       Error (304, String.Format (
+                                                      "Cannot create an instance of the " +
+                                                      "variable type '{0}' because it " +
+                                                      "doesn't have the new() constraint",
+                                                      type));
+                                       return null;
+                               }
+
+                               if ((Arguments != null) && (Arguments.Count != 0)) {
+                                       Error (417, String.Format (
+                                                      "`{0}': cannot provide arguments " +
+                                                      "when creating an instance of a " +
+                                                      "variable type.", type));
+                                       return null;
+                               }
+
+                               is_type_parameter = true;
+                               eclass = ExprClass.Value;
+                               return this;
+                       }
+#endif
+
+                       if (type.IsAbstract && type.IsSealed) {
+                               Report.SymbolRelatedToPreviousError (type);
+                               Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
+                               return null;
+                       }
+
+                       if (type.IsInterface || type.IsAbstract){
+                               RequestedType = CheckComImport (ec);
+                               if (RequestedType != null)
+                                       return RequestedType;
+                               
+                               Report.SymbolRelatedToPreviousError (type);
+                               Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
+                               return null;
+                       }
+
+                       bool is_struct = type.IsValueType;
+                       eclass = ExprClass.Value;
+
+                       //
+                       // SRE returns a match for .ctor () on structs (the object constructor), 
+                       // so we have to manually ignore it.
+                       //
+                       if (is_struct && Arguments == null)
+                               return this;
+
+                       // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
+                       Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
+                               MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
+
+                       if (ml == null)
+                               return null;
+
+                       MethodGroupExpr mg = ml as MethodGroupExpr;
+
+                       if (mg == null) {
+                               ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
+                               return null;
+                       }
+
+                       if (Arguments != null){
+                               foreach (Argument a in Arguments){
+                                       if (!a.Resolve (ec, loc))
+                                               return null;
+                               }
+                       }
+
+                       method = Invocation.OverloadResolve (ec, mg, Arguments, false, loc);
+                       if (method == null) {
+                               if (almostMatchedMembers.Count != 0)
+                                       MemberLookupFailed (ec.ContainerType, type, type, ".ctor", null, true, loc);
+                               return null;
+                       }
+
+                       return this;
+               }
+
+               bool DoEmitTypeParameter (EmitContext ec)
+               {
+#if GMCS_SOURCE
+                       ILGenerator ig = ec.ig;
+
+                       ig.Emit (OpCodes.Ldtoken, type);
+                       ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
+                       ig.Emit (OpCodes.Call, TypeManager.activator_create_instance);
+                       ig.Emit (OpCodes.Unbox_Any, type);
+                       return true;
+#else
+                       throw new InternalErrorException ();
+#endif
+               }
+
+               //
+               // This DoEmit can be invoked in two contexts:
+               //    * As a mechanism that will leave a value on the stack (new object)
+               //    * As one that wont (init struct)
+               //
+               // You can control whether a value is required on the stack by passing
+               // need_value_on_stack.  The code *might* leave a value on the stack
+               // so it must be popped manually
+               //
+               // If we are dealing with a ValueType, we have a few
+               // situations to deal with:
+               //
+               //    * The target is a ValueType, and we have been provided
+               //      the instance (this is easy, we are being assigned).
+               //
+               //    * The target of New is being passed as an argument,
+               //      to a boxing operation or a function that takes a
+               //      ValueType.
+               //
+               //      In this case, we need to create a temporary variable
+               //      that is the argument of New.
+               //
+               // Returns whether a value is left on the stack
+               //
+               bool DoEmit (EmitContext ec, bool need_value_on_stack)
+               {
+                       bool is_value_type = TypeManager.IsValueType (type);
+                       ILGenerator ig = ec.ig;
+
+                       if (is_value_type){
+                               IMemoryLocation ml;
+
+                               // Allow DoEmit() to be called multiple times.
+                               // We need to create a new LocalTemporary each time since
+                               // you can't share LocalBuilders among ILGeneators.
+                               if (!value_target_set)
+                                       value_target = new LocalTemporary (type);
+
+                               ml = (IMemoryLocation) value_target;
+                               ml.AddressOf (ec, AddressOp.Store);
+                       }
+
+                       if (method != null)
+                               Invocation.EmitArguments (ec, method, Arguments, false, null);
+
+                       if (is_value_type){
+                               if (method == null)
+                                       ig.Emit (OpCodes.Initobj, type);
+                               else 
+                                       ig.Emit (OpCodes.Call, (ConstructorInfo) method);
+                                if (need_value_on_stack){
+                                        value_target.Emit (ec);
+                                        return true;
+                                }
+                                return false;
+                       } else {
+                               ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
+                               return true;
+                       }
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       if (is_type_parameter)
+                               DoEmitTypeParameter (ec);
+                       else
+                               DoEmit (ec, true);
+               }
+               
+               public override void EmitStatement (EmitContext ec)
+               {
+                       if (is_type_parameter)
+                               throw new InvalidOperationException ();
+
+                       if (DoEmit (ec, false))
+                               ec.ig.Emit (OpCodes.Pop);
+               }
+
+               public void AddressOf (EmitContext ec, AddressOp Mode)
+               {
+                       if (is_type_parameter)
+                               throw new InvalidOperationException ();
+
+                       if (!type.IsValueType){
+                               //
+                               // We throw an exception.  So far, I believe we only need to support
+                               // value types:
+                               // foreach (int j in new StructType ())
+                               // see bug 42390
+                               //
+                               throw new Exception ("AddressOf should not be used for classes");
+                       }
+
+                       if (!value_target_set)
+                               value_target = new LocalTemporary (type);
+                                       
+                       IMemoryLocation ml = (IMemoryLocation) value_target;
+                       ml.AddressOf (ec, AddressOp.Store);
+                       if (method != null)
+                               Invocation.EmitArguments (ec, method, Arguments, false, null);
+
+                       if (method == null)
+                               ec.ig.Emit (OpCodes.Initobj, type);
+                       else 
+                               ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
+                       
+                       ((IMemoryLocation) value_target).AddressOf (ec, Mode);
+               }
+       }
+
+       /// <summary>
+       ///   14.5.10.2: Represents an array creation expression.
+       /// </summary>
+       ///
+       /// <remarks>
+       ///   There are two possible scenarios here: one is an array creation
+       ///   expression that specifies the dimensions and optionally the
+       ///   initialization data and the other which does not need dimensions
+       ///   specified but where initialization data is mandatory.
+       /// </remarks>
+       public class ArrayCreation : Expression {
+               Expression requested_base_type;
+               ArrayList initializers;
+
+               //
+               // The list of Argument types.
+               // This is used to construct the `newarray' or constructor signature
+               //
+               ArrayList arguments;
+
+               //
+               // Method used to create the array object.
+               //
+               MethodBase new_method = null;
+               
+               Type array_element_type;
+               Type underlying_type;
+               bool is_one_dimensional = false;
+               bool is_builtin_type = false;
+               bool expect_initializers = false;
+               int num_arguments = 0;
+               int dimensions = 0;
+               string rank;
+
+               ArrayList array_data;
+
+               IDictionary bounds;
+
+               // The number of constants in array initializers
+               int const_initializers_count;
+               
+               public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
+               {
+                       this.requested_base_type = requested_base_type;
+                       this.initializers = initializers;
+                       this.rank = rank;
+                       loc = l;
+
+                       arguments = new ArrayList ();
+
+                       foreach (Expression e in exprs) {
+                               arguments.Add (new Argument (e, Argument.AType.Expression));
+                               num_arguments++;
+                       }
+               }
+
+               public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
+               {
+                       this.requested_base_type = requested_base_type;
+                       this.initializers = initializers;
+                       this.rank = rank;
+                       loc = l;
+
+                       //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
+                       //
+                       //string tmp = rank.Substring (rank.LastIndexOf ('['));
+                       //
+                       //dimensions = tmp.Length - 1;
+                       expect_initializers = true;
+               }
+
+               public Expression FormArrayType (Expression base_type, int idx_count, string rank)
+               {
+                       StringBuilder sb = new StringBuilder (rank);
+                       
+                       sb.Append ("[");
+                       for (int i = 1; i < idx_count; i++)
+                               sb.Append (",");
+                       
+                       sb.Append ("]");
+
+                       return new ComposedCast (base_type, sb.ToString (), loc);
+               }
+
+               void Error_IncorrectArrayInitializer ()
+               {
+                       Error (178, "Invalid rank specifier: expected `,' or `]'");
+               }
+               
+               bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
+               {
+                       if (specified_dims) { 
+                               Argument a = (Argument) arguments [idx];
+
+                               if (!a.Resolve (ec, loc))
+                                       return false;
+
+                               Constant c = a.Expr as Constant;
+                               if (c != null) {
+                                       c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
+                               }
+
+                               if (c == null) {
+                                       Report.Error (150, a.Expr.Location, "A constant value is expected");
+                                       return false;
+                               }
+
+                               int value = (int) c.GetValue ();
+                               
+                               if (value != probe.Count) {
+                                       Error_IncorrectArrayInitializer ();
+                                       return false;
+                               }
+                               
+                               bounds [idx] = value;
+                       }
+
+                       int child_bounds = -1;
+                       for (int i = 0; i < probe.Count; ++i) {
+                               object o = probe [i];
+                               if (o is ArrayList) {
+                                       ArrayList sub_probe = o as ArrayList;
+                                       int current_bounds = sub_probe.Count;
+                                       
+                                       if (child_bounds == -1) 
+                                               child_bounds = current_bounds;
+
+                                       else if (child_bounds != current_bounds){
+                                               Error_IncorrectArrayInitializer ();
+                                               return false;
+                                       }
+                                       if (idx + 1 >= dimensions){
+                                               Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
+                                               return false;
+                                       }
+                                       
+                                       bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
+                                       if (!ret)
+                                               return false;
+                               } else {
+                                       if (child_bounds != -1){
+                                               Error_IncorrectArrayInitializer ();
+                                               return false;
+                                       }
+                                       
+                                       Expression tmp = (Expression) o;
+                                       tmp = tmp.Resolve (ec);
+                                       if (tmp == null)
+                                               return false;
+
+                                       Expression conv = Convert.ImplicitConversionRequired (
+                                               ec, tmp, underlying_type, loc);
+                                       
+                                       if (conv == null) 
+                                               return false;
+
+                                       // Initializers with the default values can be ignored
+                                       Constant c = tmp as Constant;
+                                       if (c != null) {
+                                               if (c.IsDefaultInitializer (array_element_type)) {
+                                                       conv = null;
+                                               }
+                                               else {
+                                                       ++const_initializers_count;
+                                               }
+                                       } else {
+                                               // Used to invalidate static initializer
+                                               const_initializers_count = int.MinValue;
+                                       }
+                                       
+                                       array_data.Add (conv);
+                               }
+                       }
+
+                       return true;
+               }
+               
+               public void UpdateIndices ()
+               {
+                       int i = 0;
+                       for (ArrayList probe = initializers; probe != null;) {
+                               if (probe.Count > 0 && probe [0] is ArrayList) {
+                                       Expression e = new IntConstant (probe.Count, Location.Null);
+                                       arguments.Add (new Argument (e, Argument.AType.Expression));
+
+                                       bounds [i++] =  probe.Count;
+                                       
+                                       probe = (ArrayList) probe [0];
+                                       
+                               } else {
+                                       Expression e = new IntConstant (probe.Count, Location.Null);
+                                       arguments.Add (new Argument (e, Argument.AType.Expression));
+
+                                       bounds [i++] = probe.Count;
+                                       return;
+                               }
+                       }
+
+               }
+               
+               bool ResolveInitializers (EmitContext ec)
+               {
+                       if (initializers == null) {
+                               return !expect_initializers;
+                       }
+                       
+                       if (underlying_type == null)
+                               return false;
+                       
+                       //
+                       // We use this to store all the date values in the order in which we
+                       // will need to store them in the byte blob later
+                       //
+                       array_data = new ArrayList ();
+                       bounds = new System.Collections.Specialized.HybridDictionary ();
+                       
+                       if (arguments != null)
+                               return CheckIndices (ec, initializers, 0, true);
+
+                       arguments = new ArrayList ();
+
+                       if (!CheckIndices (ec, initializers, 0, false))
+                               return false;
+                               
+                       UpdateIndices ();
+                               
+                       if (arguments.Count != dimensions) {
+                               Error_IncorrectArrayInitializer ();
+                               return false;
+                       }
+
+                       return true;
+               }
+
+               //
+               // Creates the type of the array
+               //
+               bool LookupType (EmitContext ec)
+               {
+                       StringBuilder array_qualifier = new StringBuilder (rank);
+
+                       //
+                       // `In the first form allocates an array instace of the type that results
+                       // from deleting each of the individual expression from the expression list'
+                       //
+                       if (num_arguments > 0) {
+                               array_qualifier.Append ("[");
+                               for (int i = num_arguments-1; i > 0; i--)
+                                       array_qualifier.Append (",");
+                               array_qualifier.Append ("]");                           
+                       }
+
+                       //
+                       // Lookup the type
+                       //
+                       TypeExpr array_type_expr;
+                       array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
+                       array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
+                       if (array_type_expr == null)
+                               return false;
+
+                       type = array_type_expr.Type;
+                       underlying_type = TypeManager.GetElementType (type);
+                       dimensions = type.GetArrayRank ();
+
+                       return true;
+               }
+               
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       if (type != null)
+                               return this;
+
+                       if (!LookupType (ec))
+                               return null;
+                       
+                       array_element_type = TypeManager.GetElementType (type);
+                       if (array_element_type.IsAbstract && array_element_type.IsSealed) {
+                               Report.Error (719, loc, "`{0}': array elements cannot be of static type", TypeManager.CSharpName (array_element_type));
+                               return null;
+                       }
+
+                       //
+                       // First step is to validate the initializers and fill
+                       // in any missing bits
+                       //
+                       if (!ResolveInitializers (ec))
+                               return null;
+
+                       int arg_count;
+                       if (arguments == null)
+                               arg_count = 0;
+                       else {
+                               arg_count = arguments.Count;
+                               foreach (Argument a in arguments){
+                                       if (!a.Resolve (ec, loc))
+                                               return null;
+
+                                       Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
+                                       if (real_arg == null)
+                                               return null;
+
+                                       a.Expr = real_arg;
+                               }
+                       }
+                       
+                       if (arg_count == 1) {
+                               is_one_dimensional = true;
+                               eclass = ExprClass.Value;
+                               return this;
+                       }
+
+                       is_builtin_type = TypeManager.IsBuiltinType (type);
+
+                       if (is_builtin_type) {
+                               Expression ml;
+                               
+                               ml = MemberLookup (ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
+                                                  AllBindingFlags, loc);
+                               
+                               if (!(ml is MethodGroupExpr)) {
+                                       ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
+                                       return null;
+                               }
+                               
+                               if (ml == null) {
+                                       Error (-6, "New invocation: Can not find a constructor for " +
+                                                     "this argument list");
+                                       return null;
+                               }
+                               
+                               new_method = Invocation.OverloadResolve (
+                                       ec, (MethodGroupExpr) ml, arguments, false, loc);
+
+                               if (new_method == null) {
+                                       Error (-6, "New invocation: Can not find a constructor for " +
+                                                     "this argument list");
+                                       return null;
+                               }
+                               
+                               eclass = ExprClass.Value;
+                               return this;
+                       } else {
+                               ModuleBuilder mb = CodeGen.Module.Builder;
+                               ArrayList args = new ArrayList ();
+                               
+                               if (arguments != null) {
+                                       for (int i = 0; i < arg_count; i++)
+                                               args.Add (TypeManager.int32_type);
+                               }
+                               
+                               Type [] arg_types = null;
+
+                               if (args.Count > 0)
+                                       arg_types = new Type [args.Count];
+                               
+                               args.CopyTo (arg_types, 0);
+                               
+                               new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
+                                                           arg_types);
+
+                               if (new_method == null) {
+                                       Error (-6, "New invocation: Can not find a constructor for " +
+                                                     "this argument list");
+                                       return null;
+                               }
+                               
+                               eclass = ExprClass.Value;
+                               return this;
+                       }
+               }
+
+               byte [] MakeByteBlob ()
+               {
+                       int factor;
+                       byte [] data;
+                       byte [] element;
+                       int count = array_data.Count;
+
+                       if (underlying_type.IsEnum)
+                               underlying_type = TypeManager.EnumToUnderlying (underlying_type);
+                       
+                       factor = GetTypeSize (underlying_type);
+                       if (factor == 0)
+                               throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
+
+                       data = new byte [(count * factor + 4) & ~3];
+                       int idx = 0;
+
+                       for (int i = 0; i < count; ++i) {
+                               object v = array_data [i];
+
+                               if (v is EnumConstant)
+                                       v = ((EnumConstant) v).Child;
+                               
+                               if (v is Constant && !(v is StringConstant))
+                                       v = ((Constant) v).GetValue ();
+                               else {
+                                       idx += factor;
+                                       continue;
+                               }
+                               
+                               if (underlying_type == TypeManager.int64_type){
+                                       if (!(v is Expression)){
+                                               long val = (long) v;
+                                               
+                                               for (int j = 0; j < factor; ++j) {
+                                                       data [idx + j] = (byte) (val & 0xFF);
+                                                       val = (val >> 8);
+                                               }
+                                       }
+                               } else if (underlying_type == TypeManager.uint64_type){
+                                       if (!(v is Expression)){
+                                               ulong val = (ulong) v;
+
+                                               for (int j = 0; j < factor; ++j) {
+                                                       data [idx + j] = (byte) (val & 0xFF);
+                                                       val = (val >> 8);
+                                               }
+                                       }
+                               } else if (underlying_type == TypeManager.float_type) {
+                                       if (!(v is Expression)){
+                                               element = BitConverter.GetBytes ((float) v);
+                                                       
+                                               for (int j = 0; j < factor; ++j)
+                                                       data [idx + j] = element [j];
+                                       }
+                               } else if (underlying_type == TypeManager.double_type) {
+                                       if (!(v is Expression)){
+                                               element = BitConverter.GetBytes ((double) v);
+
+                                               for (int j = 0; j < factor; ++j)
+                                                       data [idx + j] = element [j];
+                                       }
+                               } else if (underlying_type == TypeManager.char_type){
+                                       if (!(v is Expression)){
+                                               int val = (int) ((char) v);
+                                               
+                                               data [idx] = (byte) (val & 0xff);
+                                               data [idx+1] = (byte) (val >> 8);
+                                       }
+                               } else if (underlying_type == TypeManager.short_type){
+                                       if (!(v is Expression)){
+                                               int val = (int) ((short) v);
+                                       
+                                               data [idx] = (byte) (val & 0xff);
+                                               data [idx+1] = (byte) (val >> 8);
+                                       }
+                               } else if (underlying_type == TypeManager.ushort_type){
+                                       if (!(v is Expression)){
+                                               int val = (int) ((ushort) v);
+                                       
+                                               data [idx] = (byte) (val & 0xff);
+                                               data [idx+1] = (byte) (val >> 8);
+                                       }
+                               } else if (underlying_type == TypeManager.int32_type) {
+                                       if (!(v is Expression)){
+                                               int val = (int) v;
+                                       
+                                               data [idx]   = (byte) (val & 0xff);
+                                               data [idx+1] = (byte) ((val >> 8) & 0xff);
+                                               data [idx+2] = (byte) ((val >> 16) & 0xff);
+                                               data [idx+3] = (byte) (val >> 24);
+                                       }
+                               } else if (underlying_type == TypeManager.uint32_type) {
+                                       if (!(v is Expression)){
+                                               uint val = (uint) v;
+                                       
+                                               data [idx]   = (byte) (val & 0xff);
+                                               data [idx+1] = (byte) ((val >> 8) & 0xff);
+                                               data [idx+2] = (byte) ((val >> 16) & 0xff);
+                                               data [idx+3] = (byte) (val >> 24);
+                                       }
+                               } else if (underlying_type == TypeManager.sbyte_type) {
+                                       if (!(v is Expression)){
+                                               sbyte val = (sbyte) v;
+                                               data [idx] = (byte) val;
+                                       }
+                               } else if (underlying_type == TypeManager.byte_type) {
+                                       if (!(v is Expression)){
+                                               byte val = (byte) v;
+                                               data [idx] = (byte) val;
+                                       }
+                               } else if (underlying_type == TypeManager.bool_type) {
+                                       if (!(v is Expression)){
+                                               bool val = (bool) v;
+                                               data [idx] = (byte) (val ? 1 : 0);
+                                       }
+                               } else if (underlying_type == TypeManager.decimal_type){
+                                       if (!(v is Expression)){
+                                               int [] bits = Decimal.GetBits ((decimal) v);
+                                               int p = idx;
+
+                                               // FIXME: For some reason, this doesn't work on the MS runtime.
+                                               int [] nbits = new int [4];
+                                               nbits [0] = bits [3];
+                                               nbits [1] = bits [2];
+                                               nbits [2] = bits [0];
+                                               nbits [3] = bits [1];
+                                               
+                                               for (int j = 0; j < 4; j++){
+                                                       data [p++] = (byte) (nbits [j] & 0xff);
+                                                       data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
+                                                       data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
+                                                       data [p++] = (byte) (nbits [j] >> 24);
+                                               }
+                                       }
+                               } else
+                                       throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
+
+                                idx += factor;
+                       }
+
+                       return data;
+               }
+
+               //
+               // Emits the initializers for the array
+               //
+               void EmitStaticInitializers (EmitContext ec)
+               {
+                       //
+                       // First, the static data
+                       //
+                       FieldBuilder fb;
+                       ILGenerator ig = ec.ig;
+                       
+                       byte [] data = MakeByteBlob ();
+
+                       fb = RootContext.MakeStaticData (data);
+
+                       ig.Emit (OpCodes.Dup);
+                       ig.Emit (OpCodes.Ldtoken, fb);
+                       ig.Emit (OpCodes.Call,
+                                TypeManager.void_initializearray_array_fieldhandle);
+               }
+
+               //
+               // Emits pieces of the array that can not be computed at compile
+               // time (variables and string locations).
+               //
+               // This always expect the top value on the stack to be the array
+               //
+               void EmitDynamicInitializers (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+                       int dims = bounds.Count;
+                       int [] current_pos = new int [dims];
+
+                       MethodInfo set = null;
+
+                       if (dims != 1){
+                               Type [] args = new Type [dims + 1];
+
+                               for (int j = 0; j < dims; j++)
+                                       args [j] = TypeManager.int32_type;
+                               args [dims] = array_element_type;
+                               
+                               set = CodeGen.Module.Builder.GetArrayMethod (
+                                       type, "Set",
+                                       CallingConventions.HasThis | CallingConventions.Standard,
+                                       TypeManager.void_type, args);
+                       }
+
+                       for (int i = 0; i < array_data.Count; i++){
+
+                               Expression e = (Expression)array_data [i];
+
+                               if (e != null) {
+                                       Type etype = e.Type;
+
+                                       ig.Emit (OpCodes.Dup);
+
+                                       for (int idx = 0; idx < dims; idx++) 
+                                               IntConstant.EmitInt (ig, current_pos [idx]);
+
+                                       //
+                                       // If we are dealing with a struct, get the
+                                       // address of it, so we can store it.
+                                       //
+                                       if ((dims == 1) && etype.IsValueType &&
+                                           (!TypeManager.IsBuiltinOrEnum (etype) ||
+                                            etype == TypeManager.decimal_type)) {
+                                               if (e is New){
+                                                       New n = (New) e;
+
+                                                       //
+                                                       // Let new know that we are providing
+                                                       // the address where to store the results
+                                                       //
+                                                       n.DisableTemporaryValueType ();
+                                               }
+
+                                               ig.Emit (OpCodes.Ldelema, etype);
+                                       }
+
+                                       e.Emit (ec);
+
+                                       if (dims == 1) {
+                                               bool is_stobj, has_type_arg;
+                                               OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
+                                               if (is_stobj)
+                                                       ig.Emit (OpCodes.Stobj, etype);
+                                               else if (has_type_arg)
+                                                       ig.Emit (op, etype);
+                                               else
+                                                       ig.Emit (op);
+                                       } else 
+                                               ig.Emit (OpCodes.Call, set);
+
+                               }
+                               
+                               //
+                               // Advance counter
+                               //
+                               for (int j = dims - 1; j >= 0; j--){
+                                       current_pos [j]++;
+                                       if (current_pos [j] < (int) bounds [j])
+                                               break;
+                                       current_pos [j] = 0;
+                               }
+                       }
+               }
+
+               void EmitArrayArguments (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+                       
+                       foreach (Argument a in arguments) {
+                               Type atype = a.Type;
+                               a.Emit (ec);
+
+                               if (atype == TypeManager.uint64_type)
+                                       ig.Emit (OpCodes.Conv_Ovf_U4);
+                               else if (atype == TypeManager.int64_type)
+                                       ig.Emit (OpCodes.Conv_Ovf_I4);
+                       }
+               }
+               
+               public override void Emit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+                       
+                       EmitArrayArguments (ec);
+                       if (is_one_dimensional)
+                               ig.Emit (OpCodes.Newarr, array_element_type);
+                       else {
+                               if (is_builtin_type) 
+                                       ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
+                               else 
+                                       ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
+                       }
+                       
+                       if (initializers == null)
+                               return;
+
+                       // This is a treshold for static initializers
+                       // I tried to make more accurate but it seems to me that Array.Initialize is
+                       // always slower (managed -> unmanaged switch?)
+                       const int max_automatic_initializers = 200;
+
+                       if (const_initializers_count > max_automatic_initializers && TypeManager.IsPrimitiveType (array_element_type)) {
+                               EmitStaticInitializers (ec);
+                               return;
+                       }
+                               
+                       EmitDynamicInitializers (ec);
+               }
+
+               public override bool GetAttributableValue (Type valueType, out object value)
+               {
+                       if (!is_one_dimensional){
+//                             Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
+                               return base.GetAttributableValue (null, out value);
+                       }
+
+                       if (array_data == null) {
+                               Constant c = (Constant)((Argument)arguments [0]).Expr;
+                               if (c.IsDefaultValue) {
+                                       value = Array.CreateInstance (array_element_type, 0);
+                                       return true;
+                               }
+//                             Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
+                               return base.GetAttributableValue (null, out value);
+                       }
+                       
+                       Array ret = Array.CreateInstance (array_element_type, array_data.Count);
+                       object element_value;
+                       for (int i = 0; i < ret.Length; ++i)
+                       {
+                               Expression e = (Expression)array_data [i];
+
+                               // Is null when an initializer is optimized (value == predefined value)
+                               if (e == null) 
+                                       continue;
+
+                               if (!e.GetAttributableValue (array_element_type, out element_value)) {
+                                       value = null;
+                                       return false;
+                               }
+                               ret.SetValue (element_value, i);
+                       }
+                       value = ret;
+                       return true;
+               }
+       }
+       
+       public sealed class CompilerGeneratedThis : This
+       {
+               public static This Instance = new CompilerGeneratedThis ();
+
+               private CompilerGeneratedThis ()
+                       : base (Location.Null)
+               {
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       eclass = ExprClass.Variable;
+                       type = ec.ContainerType;
+                       variable = new SimpleThis (type);
+                       return this;
+               }
+       }
+       
+       /// <summary>
+       ///   Represents the `this' construct
+       /// </summary>
+
+       public class This : VariableReference, IVariable
+       {
+               Block block;
+               VariableInfo variable_info;
+               protected Variable variable;
+               bool is_struct;
+
+               public This (Block block, Location loc)
+               {
+                       this.loc = loc;
+                       this.block = block;
+               }
+
+               public This (Location loc)
+               {
+                       this.loc = loc;
+               }
+
+               public VariableInfo VariableInfo {
+                       get { return variable_info; }
+               }
+
+               public bool VerifyFixed ()
+               {
+                       return !TypeManager.IsValueType (Type);
+               }
+
+               public override bool IsRef {
+                       get { return is_struct; }
+               }
+
+               public override Variable Variable {
+                       get { return variable; }
+               }
+
+               public bool ResolveBase (EmitContext ec)
+               {
+                       eclass = ExprClass.Variable;
+
+                       if (ec.TypeContainer.CurrentType != null)
+                               type = ec.TypeContainer.CurrentType;
+                       else
+                               type = ec.ContainerType;
+
+                       is_struct = ec.TypeContainer is Struct;
+
+                       if (ec.IsStatic) {
+                               Error (26, "Keyword `this' is not valid in a static property, " +
+                                      "static method, or static field initializer");
+                               return false;
+                       }
+
+                       if (block != null) {
+                               if (block.Toplevel.ThisVariable != null)
+                                       variable_info = block.Toplevel.ThisVariable.VariableInfo;
+
+                               AnonymousContainer am = ec.CurrentAnonymousMethod;
+                               if (is_struct && (am != null) && !am.IsIterator) {
+                                       Report.Error (1673, loc, "Anonymous methods inside structs " +
+                                                     "cannot access instance members of `this'. " +
+                                                     "Consider copying `this' to a local variable " +
+                                                     "outside the anonymous method and using the " +
+                                                     "local instead.");
+                                       return false;
+                               }
+
+                               IAnonymousMethodHost host = block.Toplevel.AnonymousMethodHost;
+                               if ((host != null) && (!is_struct || host.IsIterator)) {
+                                       variable = host.CaptureThis ();
+                                       type = variable.Type;
+                                       is_struct = false;
+                               }
+                       }
+
+                       if (variable == null)
+                               variable = new SimpleThis (type);
+                       
+                       return true;
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       if (!ResolveBase (ec))
+                               return null;
+
+                       if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
+                           !variable_info.IsAssigned (ec)) {
+                               Error (188, "The `this' object cannot be used before all of its " +
+                                      "fields are assigned to");
+                               variable_info.SetAssigned (ec);
+                               return this;
+                       }
+
+                       if (ec.IsFieldInitializer) {
+                               Error (27, "Keyword `this' is not available in the current context");
+                               return null;
+                       }
+
+                       return this;
+               }
+
+               override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
+               {
+                       if (!ResolveBase (ec))
+                               return null;
+
+                       if (variable_info != null)
+                               variable_info.SetAssigned (ec);
+                       
+                       if (ec.TypeContainer is Class){
+                               Error (1604, "Cannot assign to 'this' because it is read-only");
+                               return null;
+                       }
+
+                       return this;
+               }
+               public override int GetHashCode()
+               {
+                       return block.GetHashCode ();
+               }
+
+               public override bool Equals (object obj)
+               {
+                       This t = obj as This;
+                       if (t == null)
+                               return false;
+
+                       return block == t.block;
+               }
+
+               protected class SimpleThis : Variable
+               {
+                       Type type;
+
+                       public SimpleThis (Type type)
+                       {
+                               this.type = type;
+                       }
+
+                       public override Type Type {
+                               get { return type; }
+                       }
+
+                       public override bool HasInstance {
+                               get { return false; }
+                       }
+
+                       public override bool NeedsTemporary {
+                               get { return false; }
+                       }
+
+                       public override void EmitInstance (EmitContext ec)
+                       {
+                               // Do nothing.
+                       }
+
+                       public override void Emit (EmitContext ec)
+                       {
+                               ec.ig.Emit (OpCodes.Ldarg_0);
+                       }
+
+                       public override void EmitAssign (EmitContext ec)
+                       {
+                               throw new InvalidOperationException ();
+                       }
+
+                       public override void EmitAddressOf (EmitContext ec)
+                       {
+                               ec.ig.Emit (OpCodes.Ldarg_0);
+                       }
+               }
+       }
+
+       /// <summary>
+       ///   Represents the `__arglist' construct
+       /// </summary>
+       public class ArglistAccess : Expression
+       {
+               public ArglistAccess (Location loc)
+               {
+                       this.loc = loc;
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       eclass = ExprClass.Variable;
+                       type = TypeManager.runtime_argument_handle_type;
+
+                       if (ec.IsFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs) 
+                       {
+                               Error (190, "The __arglist construct is valid only within " +
+                                      "a variable argument method");
+                               return null;
+                       }
+
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       ec.ig.Emit (OpCodes.Arglist);
+               }
+       }
+
+       /// <summary>
+       ///   Represents the `__arglist (....)' construct
+       /// </summary>
+       public class Arglist : Expression
+       {
+               public readonly Argument[] Arguments;
+
+               public Arglist (Argument[] args, Location l)
+               {
+                       Arguments = args;
+                       loc = l;
+               }
+
+               public Type[] ArgumentTypes {
+                       get {
+                               Type[] retval = new Type [Arguments.Length];
+                               for (int i = 0; i < Arguments.Length; i++)
+                                       retval [i] = Arguments [i].Type;
+                               return retval;
+                       }
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       eclass = ExprClass.Variable;
+                       type = TypeManager.runtime_argument_handle_type;
+
+                       foreach (Argument arg in Arguments) {
+                               if (!arg.Resolve (ec, loc))
+                                       return null;
+                       }
+
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       foreach (Argument arg in Arguments)
+                               arg.Emit (ec);
+               }
+       }
+
+       //
+       // This produces the value that renders an instance, used by the iterators code
+       //
+       public class ProxyInstance : Expression, IMemoryLocation  {
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       eclass = ExprClass.Variable;
+                       type = ec.ContainerType;
+                       return this;
+               }
+               
+               public override void Emit (EmitContext ec)
+               {
+                       ec.ig.Emit (OpCodes.Ldarg_0);
+
+               }
+               
+               public void AddressOf (EmitContext ec, AddressOp mode)
+               {
+                       ec.ig.Emit (OpCodes.Ldarg_0);
+               }
+       }
+
+       /// <summary>
+       ///   Implements the typeof operator
+       /// </summary>
+       public class TypeOf : Expression {
+               readonly Expression QueriedType;
+               protected Type typearg;
+               
+               public TypeOf (Expression queried_type, Location l)
+               {
+                       QueriedType = queried_type;
+                       loc = l;
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
+                       if (texpr == null)
+                               return null;
+
+                       typearg = texpr.Type;
+
+                       if (typearg == TypeManager.void_type) {
+                               Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
+                               return null;
+                       }
+
+                       if (typearg.IsPointer && !ec.InUnsafe){
+                               UnsafeError (loc);
+                               return null;
+                       }
+
+                       type = TypeManager.type_type;
+                       // Even though what is returned is a type object, it's treated as a value by the compiler.
+                       // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
+                       eclass = ExprClass.Value;
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       ec.ig.Emit (OpCodes.Ldtoken, typearg);
+                       ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
+               }
+
+               public override bool GetAttributableValue (Type valueType, out object value)
+               {
+                       if (TypeManager.ContainsGenericParameters (typearg)) {
+                               Report.SymbolRelatedToPreviousError(typearg);
+                               Report.Error(416, loc, "`{0}': an attribute argument cannot use type parameters",
+                                            TypeManager.CSharpName(typearg));
+                               value = null;
+                               return false;
+                       }
+
+                       if (valueType == TypeManager.object_type) {
+                               value = (object)typearg;
+                               return true;
+                       }
+                       value = typearg;
+                       return true;
+               }
+
+               public Type TypeArgument
+               {
+                       get
+                       {
+                               return typearg;
+                       }
+               }
+       }
+
+       /// <summary>
+       ///   Implements the `typeof (void)' operator
+       /// </summary>
+       public class TypeOfVoid : TypeOf {
+               public TypeOfVoid (Location l) : base (null, l)
+               {
+                       loc = l;
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       type = TypeManager.type_type;
+                       typearg = TypeManager.void_type;
+                       // See description in TypeOf.
+                       eclass = ExprClass.Value;
+                       return this;
+               }
+       }
+
+       /// <summary>
+       ///   Implements the sizeof expression
+       /// </summary>
+       public class SizeOf : Expression {
+               public Expression QueriedType;
+               Type type_queried;
+               
+               public SizeOf (Expression queried_type, Location l)
+               {
+                       this.QueriedType = queried_type;
+                       loc = l;
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
+                       if (texpr == null)
+                               return null;
+
+#if GMCS_SOURCE
+                       if (texpr is TypeParameterExpr){
+                               ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
+                               return null;
+                       }
+#endif
+
+                       type_queried = texpr.Type;
+                       if (type_queried.IsEnum)
+                               type_queried = TypeManager.EnumToUnderlying (type_queried);
+
+                       if (type_queried == TypeManager.void_type) {
+                               Expression.Error_VoidInvalidInTheContext (loc);
+                               return null;
+                       }
+
+                       int size_of = GetTypeSize (type_queried);
+                       if (size_of > 0) {
+                               return new IntConstant (size_of, loc);
+                       }
+
+                       if (!ec.InUnsafe) {
+                               Report.Error (233, loc, "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
+                                        TypeManager.CSharpName (type_queried));
+                               return null;
+                       }
+
+                       if (!TypeManager.VerifyUnManaged (type_queried, loc)){
+                               return null;
+                       }
+                       
+                       type = TypeManager.int32_type;
+                       eclass = ExprClass.Value;
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       int size = GetTypeSize (type_queried);
+
+                       if (size == 0)
+                               ec.ig.Emit (OpCodes.Sizeof, type_queried);
+                       else
+                               IntConstant.EmitInt (ec.ig, size);
+               }
+       }
+
+       /// <summary>
+       ///   Implements the qualified-alias-member (::) expression.
+       /// </summary>
+       public class QualifiedAliasMember : Expression
+       {
+               string alias, identifier;
+
+               public QualifiedAliasMember (string alias, string identifier, Location l)
+               {
+                       this.alias = alias;
+                       this.identifier = identifier;
+                       loc = l;
+               }
+
+               public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
+               {
+                       if (alias == "global")
+                               return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
+
+                       int errors = Report.Errors;
+                       FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
+                       if (fne == null) {
+                               if (errors == Report.Errors)
+                                       Report.Error (432, loc, "Alias `{0}' not found", alias);
+                               return null;
+                       }
+                       if (fne.eclass != ExprClass.Namespace) {
+                               if (!silent)
+                                       Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
+                               return null;
+                       }
+                       return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       FullNamedExpression fne;
+                       if (alias == "global") {
+                               fne = RootNamespace.Global;
+                       } else {
+                               int errors = Report.Errors;
+                               fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
+                               if (fne == null) {
+                                       if (errors == Report.Errors)
+                                               Report.Error (432, loc, "Alias `{0}' not found", alias);
+                                       return null;
+                               }
+                       }
+
+                       Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
+                       if (retval == null)
+                               return null;
+
+                       if (!(retval is FullNamedExpression)) {
+                               Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
+                               return null;
+                       }
+
+                       // We defer this check till the end to match the behaviour of CSC
+                       if (fne.eclass != ExprClass.Namespace) {
+                               Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
+                               return null;
+                       }
+                       return retval;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
+               }
+
+
+               public override string ToString ()
+               {
+                       return alias + "::" + identifier;
+               }
+
+               public override string GetSignatureForError ()
+               {
+                       return ToString ();
+               }
+       }
+
+       /// <summary>
+       ///   Implements the member access expression
+       /// </summary>
+       public class MemberAccess : Expression {
+               public readonly string Identifier;
+               Expression expr;
+
+               public MemberAccess (Expression expr, string id)
+                       : this (expr, id, expr.Location)
+               {
+               }
+
+               public MemberAccess (Expression expr, string identifier, Location loc)
+               {
+                       this.expr = expr;
+                       Identifier = identifier;
+                       this.loc = loc;
+               }
+
+               public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
+                       : this (expr, identifier, loc)
+               {
+                       this.args = args;
+               }
+
+               TypeArguments args;
+
+               public Expression Expr {
+                       get { return expr; }
+               }
+
+               protected string LookupIdentifier {
+                       get { return MemberName.MakeName (Identifier, args); }
+               }
+
+               // TODO: this method has very poor performace for Enum fields and
+               // probably for other constants as well
+               Expression DoResolve (EmitContext ec, Expression right_side)
+               {
+                       if (type != null)
+                               throw new Exception ();
+
+                       //
+                       // Resolve the expression with flow analysis turned off, we'll do the definite
+                       // assignment checks later.  This is because we don't know yet what the expression
+                       // will resolve to - it may resolve to a FieldExpr and in this case we must do the
+                       // definite assignment check on the actual field and not on the whole struct.
+                       //
+
+                       SimpleName original = expr as SimpleName;
+                       Expression new_expr = expr.Resolve (ec,
+                               ResolveFlags.VariableOrValue | ResolveFlags.Type |
+                               ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
+
+                       if (new_expr == null)
+                               return null;
+
+                       if (new_expr is Namespace) {
+                               Namespace ns = (Namespace) new_expr;
+                               FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
+#if GMCS_SOURCE
+                               if ((retval != null) && (args != null))
+                                       retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
+#endif
+
+                               if (retval == null)
+                                       ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
+                               return retval;
+                       }
+
+                       Type expr_type = new_expr.Type;
+                       if (expr_type.IsPointer || expr_type == TypeManager.void_type || new_expr is NullLiteral){
+                               Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
+                               return null;
+                       }
+                       if (expr_type == TypeManager.anonymous_method_type){
+                               Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
+                               return null;
+                       }
+
+                       Constant c = new_expr as Constant;
+                       if (c != null && c.GetValue () == null) {
+                               Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
+                                       "System.NullReferenceException");
+                       }
+
+                       Expression member_lookup;
+                       member_lookup = MemberLookup (
+                               ec.ContainerType, expr_type, expr_type, Identifier, loc);
+#if GMCS_SOURCE
+                       if ((member_lookup == null) && (args != null)) {
+                               member_lookup = MemberLookup (
+                                       ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
+                       }
+#endif
+                       if (member_lookup == null) {
+                               MemberLookupFailed (
+                                       ec.ContainerType, expr_type, expr_type, Identifier, null, true, loc);
+                               return null;
+                       }
+
+                       TypeExpr texpr = member_lookup as TypeExpr;
+                       if (texpr != null) {
+                               if (!(new_expr is TypeExpr) && 
+                                   (original == null || !original.IdenticalNameAndTypeName (ec, new_expr, loc))) {
+                                       Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
+                                               Identifier, member_lookup.GetSignatureForError ());
+                                       return null;
+                               }
+
+                               if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
+                                       Report.SymbolRelatedToPreviousError (member_lookup.Type);
+                                       ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
+                                       return null;
+                               }
+
+#if GMCS_SOURCE
+                               ConstructedType ct = new_expr as ConstructedType;
+                               if (ct != null) {
+                                       //
+                                       // When looking up a nested type in a generic instance
+                                       // via reflection, we always get a generic type definition
+                                       // and not a generic instance - so we have to do this here.
+                                       //
+                                       // See gtest-172-lib.cs and gtest-172.cs for an example.
+                                       //
+                                       ct = new ConstructedType (
+                                               member_lookup.Type, ct.TypeArguments, loc);
+
+                                       return ct.ResolveAsTypeStep (ec, false);
+                               }
+#endif
+                               return member_lookup;
+                       }
+
+                       MemberExpr me = (MemberExpr) member_lookup;
+                       member_lookup = me.ResolveMemberAccess (ec, new_expr, loc, original);
+                       if (member_lookup == null)
+                               return null;
+
+                       if (args != null) {
+                               MethodGroupExpr mg = member_lookup as MethodGroupExpr;
+                               if (mg == null)
+                                       throw new InternalErrorException ();
+
+                               return mg.ResolveGeneric (ec, args);
+                       }
+
+                       if (original != null && !TypeManager.IsValueType (expr_type)) {
+                               me = member_lookup as MemberExpr;
+                               if (me != null && me.IsInstance) {
+                                       LocalVariableReference var = new_expr as LocalVariableReference;
+                                       if (var != null && !var.VerifyAssigned (ec))
+                                               return null;
+                               }
+                       }
+
+                       // The following DoResolve/DoResolveLValue will do the definite assignment
+                       // check.
+
+                       if (right_side != null)
+                               return member_lookup.DoResolveLValue (ec, right_side);
+                       else
+                               return member_lookup.DoResolve (ec);
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       return DoResolve (ec, null);
+               }
+
+               public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
+               {
+                       return DoResolve (ec, right_side);
+               }
+
+               public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
+               {
+                       return ResolveNamespaceOrType (ec, silent);
+               }
+
+               public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
+               {
+                       FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
+
+                       if (new_expr == null)
+                               return null;
+
+                       if (new_expr is Namespace) {
+                               Namespace ns = (Namespace) new_expr;
+                               FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
+#if GMCS_SOURCE
+                               if ((retval != null) && (args != null))
+                                       retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
+#endif
+                               if (!silent && retval == null)
+                                       ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
+                               return retval;
+                       }
+
+                       TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
+                       if (tnew_expr == null)
+                               return null;
+
+                       Type expr_type = tnew_expr.Type;
+
+                       if (expr_type.IsPointer){
+                               Error (23, "The `.' operator can not be applied to pointer operands (" +
+                                      TypeManager.CSharpName (expr_type) + ")");
+                               return null;
+                       }
+
+                       Expression member_lookup = MemberLookup (
+                               rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
+                               MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
+                       if (member_lookup == null) {
+                               if (silent)
+                                       return null;
+
+                               member_lookup = MemberLookup(
+                                   rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
+                                       MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
+
+                               if (member_lookup == null) {
+                                       Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
+                                                     Identifier, new_expr.GetSignatureForError ());
+                               } else {
+                               // TODO: Report.SymbolRelatedToPreviousError
+                                   member_lookup.Error_UnexpectedKind (null, "type", loc);
+                               }
+                               return null;
+                       }
+
+                       TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
+                       if (texpr == null)
+                               return null;
+
+#if GMCS_SOURCE
+                       TypeArguments the_args = args;
+                       if (TypeManager.HasGenericArguments (expr_type)) {
+                               Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
+
+                               TypeArguments new_args = new TypeArguments (loc);
+                               foreach (Type decl in decl_args)
+                                       new_args.Add (new TypeExpression (decl, loc));
+
+                               if (args != null)
+                                       new_args.Add (args);
+
+                               the_args = new_args;
+                       }
+
+                       if (the_args != null) {
+                               ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
+                               return ctype.ResolveAsTypeStep (rc, false);
+                       }
+#endif
+
+                       return texpr;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       throw new Exception ("Should not happen");
+               }
+
+               public override string ToString ()
+               {
+                       return expr + "." + MemberName.MakeName (Identifier, args);
+               }
+
+               public override string GetSignatureForError ()
+               {
+                       return expr.GetSignatureForError () + "." + Identifier;
+               }
+       }
+
+       /// <summary>
+       ///   Implements checked expressions
+       /// </summary>
+       public class CheckedExpr : Expression {
+
+               public Expression Expr;
+
+               public CheckedExpr (Expression e, Location l)
+               {
+                       Expr = e;
+                       loc = l;
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
+                               Expr = Expr.Resolve (ec);
+                       
+                       if (Expr == null)
+                               return null;
+
+                       if (Expr is Constant)
+                               return Expr;
+                       
+                       eclass = Expr.eclass;
+                       type = Expr.Type;
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
+                               Expr.Emit (ec);
+               }
+
+               public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
+               {
+                       using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
+                               Expr.EmitBranchable (ec, target, onTrue);
+               }
+       }
+
+       /// <summary>
+       ///   Implements the unchecked expression
+       /// </summary>
+       public class UnCheckedExpr : Expression {
+
+               public Expression Expr;
+
+               public UnCheckedExpr (Expression e, Location l)
+               {
+                       Expr = e;
+                       loc = l;
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
+                               Expr = Expr.Resolve (ec);
+
+                       if (Expr == null)
+                               return null;
+
+                       if (Expr is Constant)
+                               return Expr;
+                       
+                       eclass = Expr.eclass;
+                       type = Expr.Type;
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
+                               Expr.Emit (ec);
+               }
+               
+               public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
+               {
+                       using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
+                               Expr.EmitBranchable (ec, target, onTrue);
+               }
+       }
+
+       /// <summary>
+       ///   An Element Access expression.
+       ///
+       ///   During semantic analysis these are transformed into 
+       ///   IndexerAccess, ArrayAccess or a PointerArithmetic.
+       /// </summary>
+       public class ElementAccess : Expression {
+               public ArrayList  Arguments;
+               public Expression Expr;
+               
+               public ElementAccess (Expression e, ArrayList e_list)
+               {
+                       Expr = e;
+
+                       loc  = e.Location;
+                       
+                       if (e_list == null)
+                               return;
+                       
+                       Arguments = new ArrayList ();
+                       foreach (Expression tmp in e_list)
+                               Arguments.Add (new Argument (tmp, Argument.AType.Expression));
+                       
+               }
+
+               bool CommonResolve (EmitContext ec)
+               {
+                       Expr = Expr.Resolve (ec);
+
+                       if (Expr == null) 
+                               return false;
+
+                       if (Arguments == null)
+                               return false;
+
+                       foreach (Argument a in Arguments){
+                               if (!a.Resolve (ec, loc))
+                                       return false;
+                       }
+
+                       return true;
+               }
+
+               Expression MakePointerAccess (EmitContext ec, Type t)
+               {
+                       if (t == TypeManager.void_ptr_type){
+                               Error (242, "The array index operation is not valid on void pointers");
+                               return null;
+                       }
+                       if (Arguments.Count != 1){
+                               Error (196, "A pointer must be indexed by only one value");
+                               return null;
+                       }
+                       Expression p;
+
+                       p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
+                       if (p == null)
+                               return null;
+                       return new Indirection (p, loc).Resolve (ec);
+               }
+               
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       if (!CommonResolve (ec))
+                               return null;
+
+                       //
+                       // We perform some simple tests, and then to "split" the emit and store
+                       // code we create an instance of a different class, and return that.
+                       //
+                       // I am experimenting with this pattern.
+                       //
+                       Type t = Expr.Type;
+
+                       if (t == TypeManager.array_type){
+                               Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
+                               return null;
+                       }
+                       
+                       if (t.IsArray)
+                               return (new ArrayAccess (this, loc)).Resolve (ec);
+                       if (t.IsPointer)
+                               return MakePointerAccess (ec, Expr.Type);
+
+                       FieldExpr fe = Expr as FieldExpr;
+                       if (fe != null) {
+                               IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
+                               if (ff != null) {
+                                       return MakePointerAccess (ec, ff.ElementType);
+                               }
+                       }
+                       return (new IndexerAccess (this, loc)).Resolve (ec);
+               }
+
+               public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
+               {
+                       if (!CommonResolve (ec))
+                               return null;
+
+                       Type t = Expr.Type;
+                       if (t.IsArray)
+                               return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
+
+                       if (t.IsPointer)
+                               return MakePointerAccess (ec, Expr.Type);
+
+                       FieldExpr fe = Expr as FieldExpr;
+                       if (fe != null) {
+                               IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
+                               if (ff != null) {
+                                       if (!(fe.InstanceExpression is LocalVariableReference) && 
+                                               !(fe.InstanceExpression is This)) {
+                                               Report.Error (1708, loc, "Fixed size buffers can only be accessed through locals or fields");
+                                               return null;
+                                       }
+                                       if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
+                                               Error (1666, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
+                                               return null;
+                                       }
+                                       return MakePointerAccess (ec, ff.ElementType);
+                               }
+                       }
+                       return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
+               }
+               
+               public override void Emit (EmitContext ec)
+               {
+                       throw new Exception ("Should never be reached");
+               }
+       }
+
+       /// <summary>
+       ///   Implements array access 
+       /// </summary>
+       public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
+               //
+               // Points to our "data" repository
+               //
+               ElementAccess ea;
+
+               LocalTemporary temp;
+               bool prepared;
+               
+               public ArrayAccess (ElementAccess ea_data, Location l)
+               {
+                       ea = ea_data;
+                       eclass = ExprClass.Variable;
+                       loc = l;
+               }
+
+               public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
+               {
+                       return DoResolve (ec);
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+#if false
+                       ExprClass eclass = ea.Expr.eclass;
+
+                       // As long as the type is valid
+                       if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
+                             eclass == ExprClass.Value)) {
+                               ea.Expr.Error_UnexpectedKind ("variable or value");
+                               return null;
+                       }
+#endif
+
+                       Type t = ea.Expr.Type;
+                       if (t.GetArrayRank () != ea.Arguments.Count){
+                               Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
+                                         ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
+                               return null;
+                       }
+
+                        type = TypeManager.GetElementType (t);
+                        if (type.IsPointer && !ec.InUnsafe){
+                               UnsafeError (ea.Location);
+                               return null;
+                       }
+
+                       foreach (Argument a in ea.Arguments){
+                               Type argtype = a.Type;
+
+                               if (argtype == TypeManager.int32_type ||
+                                   argtype == TypeManager.uint32_type ||
+                                   argtype == TypeManager.int64_type ||
+                                   argtype == TypeManager.uint64_type) {
+                                       Constant c = a.Expr as Constant;
+                                       if (c != null && c.IsNegative) {
+                                               Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)");
+                                       }
+                                       continue;
+                               }
+
+                               //
+                               // Mhm.  This is strage, because the Argument.Type is not the same as
+                               // Argument.Expr.Type: the value changes depending on the ref/out setting.
+                               //
+                               // Wonder if I will run into trouble for this.
+                               //
+                               a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
+                               if (a.Expr == null)
+                                       return null;
+                       }
+                       
+                       eclass = ExprClass.Variable;
+
+                       return this;
+               }
+
+               /// <summary>
+               ///    Emits the right opcode to load an object of Type `t'
+               ///    from an array of T
+               /// </summary>
+               static public void EmitLoadOpcode (ILGenerator ig, Type type)
+               {
+                       if (type == TypeManager.byte_type || type == TypeManager.bool_type)
+                               ig.Emit (OpCodes.Ldelem_U1);
+                       else if (type == TypeManager.sbyte_type)
+                               ig.Emit (OpCodes.Ldelem_I1);
+                       else if (type == TypeManager.short_type)
+                               ig.Emit (OpCodes.Ldelem_I2);
+                       else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
+                               ig.Emit (OpCodes.Ldelem_U2);
+                       else if (type == TypeManager.int32_type)
+                               ig.Emit (OpCodes.Ldelem_I4);
+                       else if (type == TypeManager.uint32_type)
+                               ig.Emit (OpCodes.Ldelem_U4);
+                       else if (type == TypeManager.uint64_type)
+                               ig.Emit (OpCodes.Ldelem_I8);
+                       else if (type == TypeManager.int64_type)
+                               ig.Emit (OpCodes.Ldelem_I8);
+                       else if (type == TypeManager.float_type)
+                               ig.Emit (OpCodes.Ldelem_R4);
+                       else if (type == TypeManager.double_type)
+                               ig.Emit (OpCodes.Ldelem_R8);
+                       else if (type == TypeManager.intptr_type)
+                               ig.Emit (OpCodes.Ldelem_I);
+                       else if (TypeManager.IsEnumType (type)){
+                               EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
+                       } else if (type.IsValueType){
+                               ig.Emit (OpCodes.Ldelema, type);
+                               ig.Emit (OpCodes.Ldobj, type);
+#if GMCS_SOURCE
+                       } else if (type.IsGenericParameter) {
+#if MS_COMPATIBLE
+                               ig.Emit (OpCodes.Ldelem, type);
+#else
+                               ig.Emit (OpCodes.Ldelem_Any, type);
+#endif
+#endif
+                       } else if (type.IsPointer)
+                               ig.Emit (OpCodes.Ldelem_I);
+                       else
+                               ig.Emit (OpCodes.Ldelem_Ref);
+               }
+
+               /// <summary>
+               ///    Returns the right opcode to store an object of Type `t'
+               ///    from an array of T.  
+               /// </summary>
+               static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
+               {
+                       //Console.WriteLine (new System.Diagnostics.StackTrace ());
+                       has_type_arg = false; is_stobj = false;
+                       t = TypeManager.TypeToCoreType (t);
+                       if (TypeManager.IsEnumType (t))
+                               t = TypeManager.EnumToUnderlying (t);
+                       if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
+                           t == TypeManager.bool_type)
+                               return OpCodes.Stelem_I1;
+                       else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
+                                t == TypeManager.char_type)
+                               return OpCodes.Stelem_I2;
+                       else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
+                               return OpCodes.Stelem_I4;
+                       else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
+                               return OpCodes.Stelem_I8;
+                       else if (t == TypeManager.float_type)
+                               return OpCodes.Stelem_R4;
+                       else if (t == TypeManager.double_type)
+                               return OpCodes.Stelem_R8;
+                       else if (t == TypeManager.intptr_type) {
+                                has_type_arg = true;
+                               is_stobj = true;
+                                return OpCodes.Stobj;
+                       } else if (t.IsValueType) {
+                               has_type_arg = true;
+                               is_stobj = true;
+                               return OpCodes.Stobj;
+#if GMCS_SOURCE
+                       } else if (t.IsGenericParameter) {
+                               has_type_arg = true;
+#if MS_COMPATIBLE
+                               return OpCodes.Stelem;
+#else
+                               return OpCodes.Stelem_Any;
+#endif
+#endif
+
+                       } else if (t.IsPointer)
+                               return OpCodes.Stelem_I;
+                       else
+                               return OpCodes.Stelem_Ref;
+               }
+
+               MethodInfo FetchGetMethod ()
+               {
+                       ModuleBuilder mb = CodeGen.Module.Builder;
+                       int arg_count = ea.Arguments.Count;
+                       Type [] args = new Type [arg_count];
+                       MethodInfo get;
+                       
+                       for (int i = 0; i < arg_count; i++){
+                               //args [i++] = a.Type;
+                               args [i] = TypeManager.int32_type;
+                       }
+                       
+                       get = mb.GetArrayMethod (
+                               ea.Expr.Type, "Get",
+                               CallingConventions.HasThis |
+                               CallingConventions.Standard,
+                               type, args);
+                       return get;
+               }
+                               
+
+               MethodInfo FetchAddressMethod ()
+               {
+                       ModuleBuilder mb = CodeGen.Module.Builder;
+                       int arg_count = ea.Arguments.Count;
+                       Type [] args = new Type [arg_count];
+                       MethodInfo address;
+                       Type ret_type;
+                       
+                       ret_type = TypeManager.GetReferenceType (type);
+                       
+                       for (int i = 0; i < arg_count; i++){
+                               //args [i++] = a.Type;
+                               args [i] = TypeManager.int32_type;
+                       }
+                       
+                       address = mb.GetArrayMethod (
+                               ea.Expr.Type, "Address",
+                               CallingConventions.HasThis |
+                               CallingConventions.Standard,
+                               ret_type, args);
+
+                       return address;
+               }
+
+               //
+               // Load the array arguments into the stack.
+               //
+               // If we have been requested to cache the values (cached_locations array
+               // initialized), then load the arguments the first time and store them
+               // in locals.  otherwise load from local variables.
+               //
+               void LoadArrayAndArguments (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+                       
+                       ea.Expr.Emit (ec);
+                       foreach (Argument a in ea.Arguments){
+                               Type argtype = a.Expr.Type;
+                               
+                               a.Expr.Emit (ec);
+                               
+                               if (argtype == TypeManager.int64_type)
+                                       ig.Emit (OpCodes.Conv_Ovf_I);
+                               else if (argtype == TypeManager.uint64_type)
+                                       ig.Emit (OpCodes.Conv_Ovf_I_Un);
+                       }
+               }
+
+               public void Emit (EmitContext ec, bool leave_copy)
+               {
+                       int rank = ea.Expr.Type.GetArrayRank ();
+                       ILGenerator ig = ec.ig;
+
+                       if (!prepared) {
+                               LoadArrayAndArguments (ec);
+                               
+                               if (rank == 1)
+                                       EmitLoadOpcode (ig, type);
+                               else {
+                                       MethodInfo method;
+                                       
+                                       method = FetchGetMethod ();
+                                       ig.Emit (OpCodes.Call, method);
+                               }
+                       } else
+                               LoadFromPtr (ec.ig, this.type);
+                       
+                       if (leave_copy) {
+                               ec.ig.Emit (OpCodes.Dup);
+                               temp = new LocalTemporary (this.type);
+                               temp.Store (ec);
+                       }
+               }
+               
+               public override void Emit (EmitContext ec)
+               {
+                       Emit (ec, false);
+               }
+
+               public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
+               {
+                       int rank = ea.Expr.Type.GetArrayRank ();
+                       ILGenerator ig = ec.ig;
+                       Type t = source.Type;
+                       prepared = prepare_for_load;
+
+                       if (prepare_for_load) {
+                               AddressOf (ec, AddressOp.LoadStore);
+                               ec.ig.Emit (OpCodes.Dup);
+                               source.Emit (ec);
+                               if (leave_copy) {
+                                       ec.ig.Emit (OpCodes.Dup);
+                                       temp = new LocalTemporary (this.type);
+                                       temp.Store (ec);
+                               }
+                               StoreFromPtr (ec.ig, t);
+                               
+                               if (temp != null) {
+                                       temp.Emit (ec);
+                                       temp.Release (ec);
+                               }
+                               
+                               return;
+                       }
+                       
+                       LoadArrayAndArguments (ec);
+
+                       if (rank == 1) {
+                               bool is_stobj, has_type_arg;
+                               OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
+                               //
+                               // The stobj opcode used by value types will need
+                               // an address on the stack, not really an array/array
+                               // pair
+                               //
+                               if (is_stobj)
+                                       ig.Emit (OpCodes.Ldelema, t);
+                               
+                               source.Emit (ec);
+                               if (leave_copy) {
+                                       ec.ig.Emit (OpCodes.Dup);
+                                       temp = new LocalTemporary (this.type);
+                                       temp.Store (ec);
+                               }
+                               
+                               if (is_stobj)
+                                       ig.Emit (OpCodes.Stobj, t);
+                               else if (has_type_arg)
+                                       ig.Emit (op, t);
+                               else
+                                       ig.Emit (op);
+                       } else {
+                               ModuleBuilder mb = CodeGen.Module.Builder;
+                               int arg_count = ea.Arguments.Count;
+                               Type [] args = new Type [arg_count + 1];
+                               MethodInfo set;
+                               
+                               source.Emit (ec);
+                               if (leave_copy) {
+                                       ec.ig.Emit (OpCodes.Dup);
+                                       temp = new LocalTemporary (this.type);
+                                       temp.Store (ec);
+                               }
+                               
+                               for (int i = 0; i < arg_count; i++){
+                                       //args [i++] = a.Type;
+                                       args [i] = TypeManager.int32_type;
+                               }
+
+                               args [arg_count] = type;
+                               
+                               set = mb.GetArrayMethod (
+                                       ea.Expr.Type, "Set",
+                                       CallingConventions.HasThis |
+                                       CallingConventions.Standard,
+                                       TypeManager.void_type, args);
+                               
+                               ig.Emit (OpCodes.Call, set);
+                       }
+                       
+                       if (temp != null) {
+                               temp.Emit (ec);
+                               temp.Release (ec);
+                       }
+               }
+
+               public void AddressOf (EmitContext ec, AddressOp mode)
+               {
+                       int rank = ea.Expr.Type.GetArrayRank ();
+                       ILGenerator ig = ec.ig;
+
+                       LoadArrayAndArguments (ec);
+
+                       if (rank == 1){
+                               ig.Emit (OpCodes.Ldelema, type);
+                       } else {
+                               MethodInfo address = FetchAddressMethod ();
+                               ig.Emit (OpCodes.Call, address);
+                       }
+               }
+
+               public void EmitGetLength (EmitContext ec, int dim)
+               {
+                       int rank = ea.Expr.Type.GetArrayRank ();
+                       ILGenerator ig = ec.ig;
+
+                       ea.Expr.Emit (ec);
+                       if (rank == 1) {
+                               ig.Emit (OpCodes.Ldlen);
+                               ig.Emit (OpCodes.Conv_I4);
+                       } else {
+                               IntLiteral.EmitInt (ig, dim);
+                               ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
+                       }
+               }
+       }
+       
+       class Indexers {
+               // note that the ArrayList itself in mutable.  We just can't assign to 'Properties' again.
+               public readonly ArrayList Properties;
+               static Indexers empty;
+
+               public struct Indexer {
+                       public readonly PropertyInfo PropertyInfo;
+                       public readonly MethodInfo Getter, Setter;
+
+                       public Indexer (PropertyInfo property_info, MethodInfo get, MethodInfo set)
+                       {
+                               this.PropertyInfo = property_info;
+                               this.Getter = get;
+                               this.Setter = set;
+                       }
+               }
+
+               static Indexers ()
+               {
+                       empty = new Indexers (null);
+               }
+
+               Indexers (ArrayList array)
+               {
+                       Properties = array;
+               }
+
+               static void Append (ref Indexers ix, Type caller_type, MemberInfo [] mi)
+               {
+                       bool dummy;
+                       if (mi == null)
+                               return;
+                       foreach (PropertyInfo property in mi){
+                               MethodInfo get, set;
+                               
+                               get = property.GetGetMethod (true);
+                               set = property.GetSetMethod (true);
+                               if (get != null && !Expression.IsAccessorAccessible (caller_type, get, out dummy))
+                                       get = null;
+                               if (set != null && !Expression.IsAccessorAccessible (caller_type, set, out dummy))
+                                       set = null;
+                               if (get != null || set != null) {
+                                       if (ix == empty)
+                                               ix = new Indexers (new ArrayList ());
+                                       ix.Properties.Add (new Indexer (property, get, set));
+                               }
+                       }
+               }
+
+               static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
+               {
+                       string p_name = TypeManager.IndexerPropertyName (lookup_type);
+
+                       return TypeManager.MemberLookup (
+                               caller_type, caller_type, lookup_type, MemberTypes.Property,
+                               BindingFlags.Public | BindingFlags.Instance |
+                               BindingFlags.DeclaredOnly, p_name, null);
+               }
+               
+               static public Indexers GetIndexersForType (Type caller_type, Type lookup_type) 
+               {
+                       Indexers ix = empty;
+
+#if GMCS_SOURCE
+                       if (lookup_type.IsGenericParameter) {
+                               GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
+                               if (gc == null)
+                                       return empty;
+
+                               if (gc.HasClassConstraint)
+                                       Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
+
+                               Type[] ifaces = gc.InterfaceConstraints;
+                               foreach (Type itype in ifaces)
+                                       Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
+
+                               return ix;
+                       }
+#endif
+
+                       Type copy = lookup_type;
+                       while (copy != TypeManager.object_type && copy != null){
+                               Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
+                               copy = copy.BaseType;
+                       }
+
+                       if (lookup_type.IsInterface) {
+                               Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
+                               if (ifaces != null) {
+                                       foreach (Type itype in ifaces)
+                                               Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
+                               }
+                       }
+
+                       return ix;
+               }
+       }
+
+       /// <summary>
+       ///   Expressions that represent an indexer call.
+       /// </summary>
+       public class IndexerAccess : Expression, IAssignMethod {
+               //
+               // Points to our "data" repository
+               //
+               MethodInfo get, set;
+               ArrayList set_arguments;
+               bool is_base_indexer;
+
+               protected Type indexer_type;
+               protected Type current_type;
+               protected Expression instance_expr;
+               protected ArrayList arguments;
+               
+               public IndexerAccess (ElementAccess ea, Location loc)
+                       : this (ea.Expr, false, loc)
+               {
+                       this.arguments = ea.Arguments;
+               }
+
+               protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
+                                        Location loc)
+               {
+                       this.instance_expr = instance_expr;
+                       this.is_base_indexer = is_base_indexer;
+                       this.eclass = ExprClass.Value;
+                       this.loc = loc;
+               }
+
+               protected virtual bool CommonResolve (EmitContext ec)
+               {
+                       indexer_type = instance_expr.Type;
+                       current_type = ec.ContainerType;
+
+                       return true;
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       if (!CommonResolve (ec))
+                               return null;
+
+                       //
+                       // Step 1: Query for all `Item' *properties*.  Notice
+                       // that the actual methods are pointed from here.
+                       //
+                       // This is a group of properties, piles of them.  
+
+                       ArrayList AllGetters = null;
+
+                       Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
+                       if (ilist.Properties != null) {
+                               AllGetters = new ArrayList(ilist.Properties.Count);
+                               foreach (Indexers.Indexer ix in ilist.Properties) {
+                                       if (ix.Getter != null)
+                                               AllGetters.Add (ix.Getter);
+                               }
+                       }
+
+                       if (AllGetters == null) {
+                               Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
+                                       TypeManager.CSharpName (indexer_type));
+                               return null;
+                       }
+
+                       if (AllGetters.Count == 0) {
+                               // FIXME: we cannot simply select first one as the error message is missleading when
+                               // multiple indexers exist
+                               Indexers.Indexer first_indexer = (Indexers.Indexer)ilist.Properties[ilist.Properties.Count - 1];
+                               Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
+                                       TypeManager.GetFullNameSignature (first_indexer.PropertyInfo));
+                               return null;
+                       }
+
+                       get = (MethodInfo)Invocation.OverloadResolve (ec, new MethodGroupExpr (AllGetters, loc),
+                                       arguments, false, loc);
+
+                       if (get == null) {
+                               Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
+                               return null;
+                       }
+
+                       //
+                       // Only base will allow this invocation to happen.
+                       //
+                       if (get.IsAbstract && this is BaseIndexerAccess){
+                               Error_CannotCallAbstractBase (TypeManager.CSharpSignature (get));
+                               return null;
+                       }
+
+                       type = get.ReturnType;
+                       if (type.IsPointer && !ec.InUnsafe){
+                               UnsafeError (loc);
+                               return null;
+                       }
+
+                       instance_expr.CheckMarshalByRefAccess ();
+                       
+                       eclass = ExprClass.IndexerAccess;
+                       return this;
+               }
+
+               public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
+               {
+                       if (right_side == EmptyExpression.OutAccess) {
+                               Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
+                                             GetSignatureForError ());
+                               return null;
+                       }
+
+                       // if the indexer returns a value type, and we try to set a field in it
+                       if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
+                               Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
+                                             GetSignatureForError ());
+                               return null;
+                       }
+
+                       ArrayList AllSetters = new ArrayList();
+                       if (!CommonResolve (ec))
+                               return null;
+
+                       bool found_any = false, found_any_setters = false;
+
+                       Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
+                       if (ilist.Properties != null) {
+                               found_any = true;
+                               foreach (Indexers.Indexer ix in ilist.Properties) {
+                                       if (ix.Setter != null)
+                                               AllSetters.Add (ix.Setter);
+                               }
+                       }
+                       if (AllSetters.Count > 0) {
+                               found_any_setters = true;
+                               set_arguments = (ArrayList) arguments.Clone ();
+                               set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
+                               set = (MethodInfo) Invocation.OverloadResolve (
+                                       ec, new MethodGroupExpr (AllSetters, loc),
+                                       set_arguments, false, loc);
+                       }
+
+                       if (!found_any) {
+                               Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
+                                             TypeManager.CSharpName (indexer_type));
+                               return null;
+                       }
+
+                       if (!found_any_setters) {
+                               Error (154, "indexer can not be used in this context, because " +
+                                      "it lacks a `set' accessor");
+                               return null;
+                       }
+
+                       if (set == null) {
+                               Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
+                               return null;
+                       }
+
+                       //
+                       // Only base will allow this invocation to happen.
+                       //
+                       if (set.IsAbstract && this is BaseIndexerAccess){
+                               Error_CannotCallAbstractBase (TypeManager.CSharpSignature (set));
+                               return null;
+                       }
+
+                       //
+                       // Now look for the actual match in the list of indexers to set our "return" type
+                       //
+                       type = TypeManager.void_type;   // default value
+                       foreach (Indexers.Indexer ix in ilist.Properties){
+                               if (ix.Setter == set){
+                                       type = ix.PropertyInfo.PropertyType;
+                                       break;
+                               }
+                       }
+
+                       instance_expr.CheckMarshalByRefAccess ();
+
+                       eclass = ExprClass.IndexerAccess;
+                       return this;
+               }
+               
+               bool prepared = false;
+               LocalTemporary temp;
+               
+               public void Emit (EmitContext ec, bool leave_copy)
+               {
+                       Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc, prepared, false);
+                       if (leave_copy) {
+                               ec.ig.Emit (OpCodes.Dup);
+                               temp = new LocalTemporary (Type);
+                               temp.Store (ec);
+                       }
+               }
+               
+               //
+               // source is ignored, because we already have a copy of it from the
+               // LValue resolution and we have already constructed a pre-cached
+               // version of the arguments (ea.set_arguments);
+               //
+               public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
+               {
+                       prepared = prepare_for_load;
+                       Argument a = (Argument) set_arguments [set_arguments.Count - 1];
+                       
+                       if (prepared) {
+                               source.Emit (ec);
+                               if (leave_copy) {
+                                       ec.ig.Emit (OpCodes.Dup);
+                                       temp = new LocalTemporary (Type);
+                                       temp.Store (ec);
+                               }
+                       } else if (leave_copy) {
+                               temp = new LocalTemporary (Type);
+                               source.Emit (ec);
+                               temp.Store (ec);
+                               a.Expr = temp;
+                       }
+                       
+                       Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc, false, prepared);
+                       
+                       if (temp != null) {
+                               temp.Emit (ec);
+                               temp.Release (ec);
+                       }
+               }
+               
+               
+               public override void Emit (EmitContext ec)
+               {
+                       Emit (ec, false);
+               }
+
+               public override string GetSignatureForError ()
+               {
+                       // FIXME: print the argument list of the indexer
+                       return instance_expr.GetSignatureForError () + ".this[...]";
+               }
+       }
+
+       /// <summary>
+       ///   The base operator for method names
+       /// </summary>
+       public class BaseAccess : Expression {
+               public readonly string Identifier;
+
+               public BaseAccess (string member, Location l)
+               {
+                       this.Identifier = member;
+                       loc = l;
+               }
+
+               public BaseAccess (string member, TypeArguments args, Location l)
+                       : this (member, l)
+               {
+                       this.args = args;
+               }
+
+               TypeArguments args;
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       Expression c = CommonResolve (ec);
+
+                       if (c == null)
+                               return null;
+
+                       //
+                       // MethodGroups use this opportunity to flag an error on lacking ()
+                       //
+                       if (!(c is MethodGroupExpr))
+                               return c.Resolve (ec);
+                       return c;
+               }
+
+               public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
+               {
+                       Expression c = CommonResolve (ec);
+
+                       if (c == null)
+                               return null;
+
+                       //
+                       // MethodGroups use this opportunity to flag an error on lacking ()
+                       //
+                       if (! (c is MethodGroupExpr))
+                               return c.DoResolveLValue (ec, right_side);
+
+                       return c;
+               }
+
+               Expression CommonResolve (EmitContext ec)
+               {
+                       Expression member_lookup;
+                       Type current_type = ec.ContainerType;
+                       Type base_type = current_type.BaseType;
+
+                       if (ec.IsStatic){
+                               Error (1511, "Keyword `base' is not available in a static method");
+                               return null;
+                       }
+
+                       if (ec.IsFieldInitializer){
+                               Error (1512, "Keyword `base' is not available in the current context");
+                               return null;
+                       }
+                       
+                       member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
+                                                     AllMemberTypes, AllBindingFlags, loc);
+                       if (member_lookup == null) {
+                               MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier, null, true, loc);
+                               return null;
+                       }
+
+                       Expression left;
+                       
+                       if (ec.IsStatic)
+                               left = new TypeExpression (base_type, loc);
+                       else
+                               left = ec.GetThis (loc);
+
+                       MemberExpr me = (MemberExpr) member_lookup;
+                       
+                       Expression e = me.ResolveMemberAccess (ec, left, loc, null);
+
+                       if (e is PropertyExpr) {
+                               PropertyExpr pe = (PropertyExpr) e;
+
+                               pe.IsBase = true;
+                       }
+
+                       MethodGroupExpr mg = e as MethodGroupExpr;
+                       if (mg != null)
+                               mg.IsBase = true;
+
+                       if (args != null) {
+                               if (mg != null)
+                                       return mg.ResolveGeneric (ec, args);
+
+                               Report.Error (307, loc, "`{0}' cannot be used with type arguments",
+                                             Identifier);
+                               return null;
+                       }
+
+                       return e;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       throw new Exception ("Should never be called"); 
+               }
+       }
+
+       /// <summary>
+       ///   The base indexer operator
+       /// </summary>
+       public class BaseIndexerAccess : IndexerAccess {
+               public BaseIndexerAccess (ArrayList args, Location loc)
+                       : base (null, true, loc)
+               {
+                       arguments = new ArrayList ();
+                       foreach (Expression tmp in args)
+                               arguments.Add (new Argument (tmp, Argument.AType.Expression));
+               }
+
+               protected override bool CommonResolve (EmitContext ec)
+               {
+                       instance_expr = ec.GetThis (loc);
+
+                       current_type = ec.ContainerType.BaseType;
+                       indexer_type = current_type;
+
+                       foreach (Argument a in arguments){
+                               if (!a.Resolve (ec, loc))
+                                       return false;
+                       }
+
+                       return true;
+               }
+       }
+       
+       /// <summary>
+       ///   This class exists solely to pass the Type around and to be a dummy
+       ///   that can be passed to the conversion functions (this is used by
+       ///   foreach implementation to typecast the object return value from
+       ///   get_Current into the proper type.  All code has been generated and
+       ///   we only care about the side effect conversions to be performed
+       ///
+       ///   This is also now used as a placeholder where a no-action expression
+       ///   is needed (the `New' class).
+       /// </summary>
+       public class EmptyExpression : Expression {
+               public static readonly EmptyExpression Null = new EmptyExpression ();
+
+               public static readonly EmptyExpression OutAccess = new EmptyExpression ();
+               public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
+               public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
+
+               static EmptyExpression temp = new EmptyExpression ();
+               public static EmptyExpression Grab ()
+               {
+                       EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
+                       temp = null;
+                       return retval;
+               }
+
+               public static void Release (EmptyExpression e)
+               {
+                       temp = e;
+               }
+
+               // TODO: should be protected
+               public EmptyExpression ()
+               {
+                       type = TypeManager.object_type;
+                       eclass = ExprClass.Value;
+                       loc = Location.Null;
+               }
+
+               public EmptyExpression (Type t)
+               {
+                       type = t;
+                       eclass = ExprClass.Value;
+                       loc = Location.Null;
+               }
+               
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       // nothing, as we only exist to not do anything.
+               }
+
+               //
+               // This is just because we might want to reuse this bad boy
+               // instead of creating gazillions of EmptyExpressions.
+               // (CanImplicitConversion uses it)
+               //
+               public void SetType (Type t)
+               {
+                       type = t;
+               }
+       }
+
+       public class UserCast : Expression {
+               MethodBase method;
+               Expression source;
+               
+               public UserCast (MethodInfo method, Expression source, Location l)
+               {
+                       this.method = method;
+                       this.source = source;
+                       type = method.ReturnType;
+                       eclass = ExprClass.Value;
+                       loc = l;
+               }
+
+               public Expression Source {
+                       get {
+                               return source;
+                       }
+               }
+                       
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       //
+                       // We are born fully resolved
+                       //
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+
+                       source.Emit (ec);
+                       
+                       if (method is MethodInfo)
+                               ig.Emit (OpCodes.Call, (MethodInfo) method);
+                       else
+                               ig.Emit (OpCodes.Call, (ConstructorInfo) method);
+
+               }
+       }
+
+       // <summary>
+       //   This class is used to "construct" the type during a typecast
+       //   operation.  Since the Type.GetType class in .NET can parse
+       //   the type specification, we just use this to construct the type
+       //   one bit at a time.
+       // </summary>
+       public class ComposedCast : TypeExpr {
+               Expression left;
+               string dim;
+               
+               public ComposedCast (Expression left, string dim)
+                       : this (left, dim, left.Location)
+               {
+               }
+
+               public ComposedCast (Expression left, string dim, Location l)
+               {
+                       this.left = left;
+                       this.dim = dim;
+                       loc = l;
+               }
+
+#if GMCS_SOURCE
+               public Expression RemoveNullable ()
+               {
+                       if (dim.EndsWith ("?")) {
+                               dim = dim.Substring (0, dim.Length - 1);
+                               if (dim == "")
+                                       return left;
+                       }
+
+                       return this;
+               }
+#endif
+
+               protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
+               {
+                       TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
+                       if (lexpr == null)
+                               return null;
+
+                       Type ltype = lexpr.Type;
+                       if ((ltype == TypeManager.void_type) && (dim != "*")) {
+                               Error_VoidInvalidInTheContext (loc);
+                               return null;
+                       }
+
+#if GMCS_SOURCE
+                       if ((dim.Length > 0) && (dim [0] == '?')) {
+                               TypeExpr nullable = new NullableType (left, loc);
+                               if (dim.Length > 1)
+                                       nullable = new ComposedCast (nullable, dim.Substring (1), loc);
+                               return nullable.ResolveAsTypeTerminal (ec, false);
+                       }
+#endif
+
+                       if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
+                               return null;
+
+                       if (dim != "" && dim [0] == '[' &&
+                           (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
+                               Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
+                               return null;
+                       }
+
+                       if (dim != "")
+                               type = TypeManager.GetConstructedType (ltype, dim);
+                       else
+                               type = ltype;
+
+                       if (type == null)
+                               throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
+
+                       if (type.IsPointer && !ec.IsInUnsafeScope){
+                               UnsafeError (loc);
+                               return null;
+                       }
+
+                       eclass = ExprClass.Type;
+                       return this;
+               }
+
+               public override string Name {
+                       get { return left + dim; }
+               }
+
+               public override string FullName {
+                       get { return type.FullName; }
+               }
+
+               public override string GetSignatureForError ()
+               {
+                       return left.GetSignatureForError () + dim;
+               }
+       }
+
+       public class FixedBufferPtr : Expression {
+               Expression array;
+
+               public FixedBufferPtr (Expression array, Type array_type, Location l)
+               {
+                       this.array = array;
+                       this.loc = l;
+
+                       type = TypeManager.GetPointerType (array_type);
+                       eclass = ExprClass.Value;
+               }
+
+               public override void Emit(EmitContext ec)
+               {
+                       array.Emit (ec);
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       //
+                       // We are born fully resolved
+                       //
+                       return this;
+               }
+       }
+
+
+       //
+       // This class is used to represent the address of an array, used
+       // only by the Fixed statement, this generates "&a [0]" construct
+       // for fixed (char *pa = a)
+       //
+       public class ArrayPtr : FixedBufferPtr {
+               Type array_type;
+               
+               public ArrayPtr (Expression array, Type array_type, Location l):
+                       base (array, array_type, l)
+               {
+                       this.array_type = array_type;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       base.Emit (ec);
+                       
+                       ILGenerator ig = ec.ig;
+                       IntLiteral.EmitInt (ig, 0);
+                       ig.Emit (OpCodes.Ldelema, array_type);
+               }
+       }
+
+       //
+       // Used by the fixed statement
+       //
+       public class StringPtr : Expression {
+               LocalBuilder b;
+               
+               public StringPtr (LocalBuilder b, Location l)
+               {
+                       this.b = b;
+                       eclass = ExprClass.Value;
+                       type = TypeManager.char_ptr_type;
+                       loc = l;
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       // This should never be invoked, we are born in fully
+                       // initialized state.
+
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+
+                       ig.Emit (OpCodes.Ldloc, b);
+                       ig.Emit (OpCodes.Conv_I);
+                       ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
+                       ig.Emit (OpCodes.Add);
+               }
+       }
+       
+       //
+       // Implements the `stackalloc' keyword
+       //
+       public class StackAlloc : Expression {
+               Type otype;
+               Expression t;
+               Expression count;
+               
+               public StackAlloc (Expression type, Expression count, Location l)
+               {
+                       t = type;
+                       this.count = count;
+                       loc = l;
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       count = count.Resolve (ec);
+                       if (count == null)
+                               return null;
+                       
+                       if (count.Type != TypeManager.int32_type){
+                               count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
+                               if (count == null)
+                                       return null;
+                       }
+
+                       Constant c = count as Constant;
+                       if (c != null && c.IsNegative) {
+                               Report.Error (247, loc, "Cannot use a negative size with stackalloc");
+                               return null;
+                       }
+
+                       if (ec.InCatch || ec.InFinally) {
+                               Error (255, "Cannot use stackalloc in finally or catch");
+                               return null;
+                       }
+
+                       TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
+                       if (texpr == null)
+                               return null;
+
+                       otype = texpr.Type;
+
+                       if (!TypeManager.VerifyUnManaged (otype, loc))
+                               return null;
+
+                       type = TypeManager.GetPointerType (otype);
+                       eclass = ExprClass.Value;
+
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       int size = GetTypeSize (otype);
+                       ILGenerator ig = ec.ig;
+                               
+                       if (size == 0)
+                               ig.Emit (OpCodes.Sizeof, otype);
+                       else
+                               IntConstant.EmitInt (ig, size);
+                       count.Emit (ec);
+                       ig.Emit (OpCodes.Mul);
+                       ig.Emit (OpCodes.Localloc);
+               }
+       }
+}
diff --git a/mcs/mcs/statement.cs b/mcs/mcs/statement.cs
new file mode 100644 (file)
index 0000000..74f2194
--- /dev/null
@@ -0,0 +1,5133 @@
+//
+// statement.cs: Statement representation for the IL tree.
+//
+// Author:
+//   Miguel de Icaza (miguel@ximian.com)
+//   Martin Baulig (martin@ximian.com)
+//   Marek Safar (marek.safar@seznam.cz)
+//
+// (C) 2001, 2002, 2003 Ximian, Inc.
+// (C) 2003, 2004 Novell, Inc.
+//
+
+using System;
+using System.Text;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Diagnostics;
+using System.Collections;
+using System.Collections.Specialized;
+
+namespace Mono.CSharp {
+       
+       public abstract class Statement {
+               public Location loc;
+               
+               /// <summary>
+               ///   Resolves the statement, true means that all sub-statements
+               ///   did resolve ok.
+               //  </summary>
+               public virtual bool Resolve (EmitContext ec)
+               {
+                       return true;
+               }
+
+               /// <summary>
+               ///   We already know that the statement is unreachable, but we still
+               ///   need to resolve it to catch errors.
+               /// </summary>
+               public virtual bool ResolveUnreachable (EmitContext ec, bool warn)
+               {
+                       //
+                       // This conflicts with csc's way of doing this, but IMHO it's
+                       // the right thing to do.
+                       //
+                       // If something is unreachable, we still check whether it's
+                       // correct.  This means that you cannot use unassigned variables
+                       // in unreachable code, for instance.
+                       //
+
+                       if (warn)
+                               Report.Warning (162, 2, loc, "Unreachable code detected");
+
+                       ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
+                       bool ok = Resolve (ec);
+                       ec.KillFlowBranching ();
+
+                       return ok;
+               }
+                               
+               /// <summary>
+               ///   Return value indicates whether all code paths emitted return.
+               /// </summary>
+               protected abstract void DoEmit (EmitContext ec);
+
+               /// <summary>
+               ///   Utility wrapper routine for Error, just to beautify the code
+               /// </summary>
+               public void Error (int error, string format, params object[] args)
+               {
+                       Error (error, String.Format (format, args));
+               }
+
+               public void Error (int error, string s)
+               {
+                       if (!loc.IsNull)
+                               Report.Error (error, loc, s);
+                       else
+                               Report.Error (error, s);
+               }
+
+               /// <summary>
+               ///   Return value indicates whether all code paths emitted return.
+               /// </summary>
+               public virtual void Emit (EmitContext ec)
+               {
+                       ec.Mark (loc, true);
+                       DoEmit (ec);
+               }               
+       }
+
+       public sealed class EmptyStatement : Statement {
+               
+               private EmptyStatement () {}
+               
+               public static readonly EmptyStatement Value = new EmptyStatement ();
+               
+               public override bool Resolve (EmitContext ec)
+               {
+                       return true;
+               }
+
+               public override bool ResolveUnreachable (EmitContext ec, bool warn)
+               {
+                       return true;
+               }
+
+               protected override void DoEmit (EmitContext ec)
+               {
+               }
+       }
+       
+       public class If : Statement {
+               Expression expr;
+               public Statement TrueStatement;
+               public Statement FalseStatement;
+
+               bool is_true_ret;
+               
+               public If (Expression expr, Statement trueStatement, Location l)
+               {
+                       this.expr = expr;
+                       TrueStatement = trueStatement;
+                       loc = l;
+               }
+
+               public If (Expression expr,
+                          Statement trueStatement,
+                          Statement falseStatement,
+                          Location l)
+               {
+                       this.expr = expr;
+                       TrueStatement = trueStatement;
+                       FalseStatement = falseStatement;
+                       loc = l;
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       bool ok = true;
+
+                       Report.Debug (1, "START IF BLOCK", loc);
+
+                       expr = Expression.ResolveBoolean (ec, expr, loc);
+                       if (expr == null){
+                               ok = false;
+                               goto skip;
+                       }
+
+                       Assign ass = expr as Assign;
+                       if (ass != null && ass.Source is Constant) {
+                               Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
+                       }
+
+                       //
+                       // Dead code elimination
+                       //
+                       if (expr is BoolConstant){
+                               bool take = ((BoolConstant) expr).Value;
+
+                               if (take){
+                                       if (!TrueStatement.Resolve (ec))
+                                               return false;
+
+                                       if ((FalseStatement != null) &&
+                                           !FalseStatement.ResolveUnreachable (ec, true))
+                                               return false;
+                                       FalseStatement = null;
+                               } else {
+                                       if (!TrueStatement.ResolveUnreachable (ec, true))
+                                               return false;
+                                       TrueStatement = null;
+
+                                       if ((FalseStatement != null) &&
+                                           !FalseStatement.Resolve (ec))
+                                               return false;
+                               }
+
+                               return true;
+                       }
+               skip:
+                       ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
+                       
+                       ok &= TrueStatement.Resolve (ec);
+
+                       is_true_ret = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable;
+
+                       ec.CurrentBranching.CreateSibling ();
+
+                       if (FalseStatement != null)
+                               ok &= FalseStatement.Resolve (ec);
+                                       
+                       ec.EndFlowBranching ();
+
+                       Report.Debug (1, "END IF BLOCK", loc);
+
+                       return ok;
+               }
+               
+               protected override void DoEmit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+                       Label false_target = ig.DefineLabel ();
+                       Label end;
+
+                       //
+                       // If we're a boolean expression, Resolve() already
+                       // eliminated dead code for us.
+                       //
+                       if (expr is BoolConstant){
+                               bool take = ((BoolConstant) expr).Value;
+
+                               if (take)
+                                       TrueStatement.Emit (ec);
+                               else if (FalseStatement != null)
+                                       FalseStatement.Emit (ec);
+
+                               return;
+                       }
+                       
+                       expr.EmitBranchable (ec, false_target, false);
+                       
+                       TrueStatement.Emit (ec);
+
+                       if (FalseStatement != null){
+                               bool branch_emitted = false;
+                               
+                               end = ig.DefineLabel ();
+                               if (!is_true_ret){
+                                       ig.Emit (OpCodes.Br, end);
+                                       branch_emitted = true;
+                               }
+
+                               ig.MarkLabel (false_target);
+                               FalseStatement.Emit (ec);
+
+                               if (branch_emitted)
+                                       ig.MarkLabel (end);
+                       } else {
+                               ig.MarkLabel (false_target);
+                       }
+               }
+       }
+
+       public class Do : Statement {
+               public Expression expr;
+               public readonly Statement  EmbeddedStatement;
+               bool infinite;
+               
+               public Do (Statement statement, Expression boolExpr, Location l)
+               {
+                       expr = boolExpr;
+                       EmbeddedStatement = statement;
+                       loc = l;
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       bool ok = true;
+
+                       ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
+
+                       bool was_unreachable = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable;
+
+                       ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
+                       if (!EmbeddedStatement.Resolve (ec))
+                               ok = false;
+                       ec.EndFlowBranching ();
+
+                       if (ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable && !was_unreachable)
+                               Report.Warning (162, 2, expr.Location, "Unreachable code detected");
+
+                       expr = Expression.ResolveBoolean (ec, expr, loc);
+                       if (expr == null)
+                               ok = false;
+                       else if (expr is BoolConstant){
+                               bool res = ((BoolConstant) expr).Value;
+
+                               if (res)
+                                       infinite = true;
+                       }
+                       if (infinite)
+                               ec.CurrentBranching.CurrentUsageVector.Goto ();
+
+                       ec.EndFlowBranching ();
+
+                       return ok;
+               }
+               
+               protected override void DoEmit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+                       Label loop = ig.DefineLabel ();
+                       Label old_begin = ec.LoopBegin;
+                       Label old_end = ec.LoopEnd;
+                       
+                       ec.LoopBegin = ig.DefineLabel ();
+                       ec.LoopEnd = ig.DefineLabel ();
+                               
+                       ig.MarkLabel (loop);
+                       EmbeddedStatement.Emit (ec);
+                       ig.MarkLabel (ec.LoopBegin);
+
+                       //
+                       // Dead code elimination
+                       //
+                       if (expr is BoolConstant){
+                               bool res = ((BoolConstant) expr).Value;
+
+                               if (res)
+                                       ec.ig.Emit (OpCodes.Br, loop); 
+                       } else
+                               expr.EmitBranchable (ec, loop, true);
+                       
+                       ig.MarkLabel (ec.LoopEnd);
+
+                       ec.LoopBegin = old_begin;
+                       ec.LoopEnd = old_end;
+               }
+       }
+
+       public class While : Statement {
+               public Expression expr;
+               public readonly Statement Statement;
+               bool infinite, empty;
+               
+               public While (Expression boolExpr, Statement statement, Location l)
+               {
+                       this.expr = boolExpr;
+                       Statement = statement;
+                       loc = l;
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       bool ok = true;
+
+                       expr = Expression.ResolveBoolean (ec, expr, loc);
+                       if (expr == null)
+                               return false;
+
+                       //
+                       // Inform whether we are infinite or not
+                       //
+                       if (expr is BoolConstant){
+                               BoolConstant bc = (BoolConstant) expr;
+
+                               if (bc.Value == false){
+                                       if (!Statement.ResolveUnreachable (ec, true))
+                                               return false;
+                                       empty = true;
+                                       return true;
+                               } else
+                                       infinite = true;
+                       }
+
+                       ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
+                       if (!infinite)
+                               ec.CurrentBranching.CreateSibling ();
+
+                       ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
+                       if (!Statement.Resolve (ec))
+                               ok = false;
+                       ec.EndFlowBranching ();
+
+                       // There's no direct control flow from the end of the embedded statement to the end of the loop
+                       ec.CurrentBranching.CurrentUsageVector.Goto ();
+
+                       ec.EndFlowBranching ();
+
+                       return ok;
+               }
+               
+               protected override void DoEmit (EmitContext ec)
+               {
+                       if (empty)
+                               return;
+
+                       ILGenerator ig = ec.ig;
+                       Label old_begin = ec.LoopBegin;
+                       Label old_end = ec.LoopEnd;
+                       
+                       ec.LoopBegin = ig.DefineLabel ();
+                       ec.LoopEnd = ig.DefineLabel ();
+
+                       //
+                       // Inform whether we are infinite or not
+                       //
+                       if (expr is BoolConstant){
+                               ig.MarkLabel (ec.LoopBegin);
+                               Statement.Emit (ec);
+                               ig.Emit (OpCodes.Br, ec.LoopBegin);
+                                       
+                               //
+                               // Inform that we are infinite (ie, `we return'), only
+                               // if we do not `break' inside the code.
+                               //
+                               ig.MarkLabel (ec.LoopEnd);
+                       } else {
+                               Label while_loop = ig.DefineLabel ();
+
+                               ig.Emit (OpCodes.Br, ec.LoopBegin);
+                               ig.MarkLabel (while_loop);
+
+                               Statement.Emit (ec);
+                       
+                               ig.MarkLabel (ec.LoopBegin);
+
+                               expr.EmitBranchable (ec, while_loop, true);
+                               
+                               ig.MarkLabel (ec.LoopEnd);
+                       }       
+
+                       ec.LoopBegin = old_begin;
+                       ec.LoopEnd = old_end;
+               }
+       }
+
+       public class For : Statement {
+               Expression Test;
+               readonly Statement InitStatement;
+               readonly Statement Increment;
+               public readonly Statement Statement;
+               bool infinite, empty;
+               
+               public For (Statement initStatement,
+                           Expression test,
+                           Statement increment,
+                           Statement statement,
+                           Location l)
+               {
+                       InitStatement = initStatement;
+                       Test = test;
+                       Increment = increment;
+                       Statement = statement;
+                       loc = l;
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       bool ok = true;
+
+                       if (InitStatement != null){
+                               if (!InitStatement.Resolve (ec))
+                                       ok = false;
+                       }
+
+                       if (Test != null){
+                               Test = Expression.ResolveBoolean (ec, Test, loc);
+                               if (Test == null)
+                                       ok = false;
+                               else if (Test is BoolConstant){
+                                       BoolConstant bc = (BoolConstant) Test;
+
+                                       if (bc.Value == false){
+                                               if (!Statement.ResolveUnreachable (ec, true))
+                                                       return false;
+                                               if ((Increment != null) &&
+                                                   !Increment.ResolveUnreachable (ec, false))
+                                                       return false;
+                                               empty = true;
+                                               return true;
+                                       } else
+                                               infinite = true;
+                               }
+                       } else
+                               infinite = true;
+
+                       ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
+                       if (!infinite)
+                               ec.CurrentBranching.CreateSibling ();
+
+                       bool was_unreachable = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable;
+
+                       ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
+                       if (!Statement.Resolve (ec))
+                               ok = false;
+                       ec.EndFlowBranching ();
+
+                       if (Increment != null){
+                               if (ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable) {
+                                       if (!Increment.ResolveUnreachable (ec, !was_unreachable))
+                                               ok = false;
+                               } else {
+                                       if (!Increment.Resolve (ec))
+                                               ok = false;
+                               }
+                       }
+
+                       // There's no direct control flow from the end of the embedded statement to the end of the loop
+                       ec.CurrentBranching.CurrentUsageVector.Goto ();
+
+                       ec.EndFlowBranching ();
+
+                       return ok;
+               }
+               
+               protected override void DoEmit (EmitContext ec)
+               {
+                       if (empty)
+                               return;
+
+                       ILGenerator ig = ec.ig;
+                       Label old_begin = ec.LoopBegin;
+                       Label old_end = ec.LoopEnd;
+                       Label loop = ig.DefineLabel ();
+                       Label test = ig.DefineLabel ();
+                       
+                       if (InitStatement != null && InitStatement != EmptyStatement.Value)
+                               InitStatement.Emit (ec);
+
+                       ec.LoopBegin = ig.DefineLabel ();
+                       ec.LoopEnd = ig.DefineLabel ();
+
+                       ig.Emit (OpCodes.Br, test);
+                       ig.MarkLabel (loop);
+                       Statement.Emit (ec);
+
+                       ig.MarkLabel (ec.LoopBegin);
+                       if (Increment != EmptyStatement.Value)
+                               Increment.Emit (ec);
+
+                       ig.MarkLabel (test);
+                       //
+                       // If test is null, there is no test, and we are just
+                       // an infinite loop
+                       //
+                       if (Test != null){
+                               //
+                               // The Resolve code already catches the case for
+                               // Test == BoolConstant (false) so we know that
+                               // this is true
+                               //
+                               if (Test is BoolConstant)
+                                       ig.Emit (OpCodes.Br, loop);
+                               else
+                                       Test.EmitBranchable (ec, loop, true);
+                               
+                       } else
+                               ig.Emit (OpCodes.Br, loop);
+                       ig.MarkLabel (ec.LoopEnd);
+
+                       ec.LoopBegin = old_begin;
+                       ec.LoopEnd = old_end;
+               }
+       }
+       
+       public class StatementExpression : Statement {
+               ExpressionStatement expr;
+               
+               public StatementExpression (ExpressionStatement expr)
+               {
+                       this.expr = expr;
+                       loc = expr.Location;
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       if (expr != null)
+                               expr = expr.ResolveStatement (ec);
+                       return expr != null;
+               }
+               
+               protected override void DoEmit (EmitContext ec)
+               {
+                       expr.EmitStatement (ec);
+               }
+
+               public override string ToString ()
+               {
+                       return "StatementExpression (" + expr + ")";
+               }
+       }
+
+       /// <summary>
+       ///   Implements the return statement
+       /// </summary>
+       public class Return : Statement {
+               public Expression Expr;
+               
+               public Return (Expression expr, Location l)
+               {
+                       Expr = expr;
+                       loc = l;
+               }
+
+               bool unwind_protect;
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       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;
+                       }
+
+                       if (ec.ReturnType == null){
+                               if (Expr != null){
+                                       if (ec.CurrentAnonymousMethod != 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",
+                                                       ec.CurrentAnonymousMethod.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;
+                               }
+
+                               Expr = Expr.Resolve (ec);
+                               if (Expr == null)
+                                       return false;
+
+                               if (Expr.Type != ec.ReturnType) {
+                                       Expr = Convert.ImplicitConversionRequired (
+                                               ec, Expr, ec.ReturnType, loc);
+                                       if (Expr == null)
+                                               return false;
+                               }
+                       }
+
+                       int errors = Report.Errors;
+                       unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
+                       if (unwind_protect)
+                               ec.NeedReturnLabel ();
+                       ec.CurrentBranching.CurrentUsageVector.Return ();
+                       return errors == Report.Errors;
+               }
+               
+               protected override void DoEmit (EmitContext ec)
+               {
+                       if (Expr != null) {
+                               Expr.Emit (ec);
+
+                               if (unwind_protect)
+                                       ec.ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
+                       }
+
+                       if (unwind_protect)
+                               ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel);
+                       else
+                               ec.ig.Emit (OpCodes.Ret);
+               }
+       }
+
+       public class Goto : Statement {
+               string target;
+               LabeledStatement label;
+               bool unwind_protect;
+               
+               public override bool Resolve (EmitContext ec)
+               {
+                       int errors = Report.Errors;
+                       unwind_protect = ec.CurrentBranching.AddGotoOrigin (ec.CurrentBranching.CurrentUsageVector, this);
+                       ec.CurrentBranching.CurrentUsageVector.Goto ();
+                       return errors == Report.Errors;
+               }
+               
+               public Goto (string label, Location l)
+               {
+                       loc = l;
+                       target = label;
+               }
+
+               public string Target {
+                       get { return target; }
+               }
+
+               public void SetResolvedTarget (LabeledStatement label)
+               {
+                       this.label = label;
+                       label.AddReference ();
+               }
+
+               protected override void DoEmit (EmitContext ec)
+               {
+                       if (label == null)
+                               throw new InternalErrorException ("goto emitted before target resolved");
+                       Label l = label.LabelTarget (ec);
+                       ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
+               }
+       }
+
+       public class LabeledStatement : Statement {
+               string name;
+               bool defined;
+               bool referenced;
+               Label label;
+               ILGenerator ig;
+
+               FlowBranching.UsageVector vectors;
+               
+               public LabeledStatement (string name, Location l)
+               {
+                       this.name = name;
+                       this.loc = l;
+               }
+
+               public Label LabelTarget (EmitContext ec)
+               {
+                       if (defined)
+                               return label;
+                       ig = ec.ig;
+                       label = ec.ig.DefineLabel ();
+                       defined = true;
+
+                       return label;
+               }
+
+               public string Name {
+                       get { return name; }
+               }
+
+               public bool IsDefined {
+                       get { return defined; }
+               }
+
+               public bool HasBeenReferenced {
+                       get { return referenced; }
+               }
+
+               public FlowBranching.UsageVector JumpOrigins {
+                       get { return vectors; }
+               }
+
+               public void AddUsageVector (FlowBranching.UsageVector vector)
+               {
+                       vector = vector.Clone ();
+                       vector.Next = vectors;
+                       vectors = vector;
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       // this flow-branching will be terminated when the surrounding block ends
+                       ec.StartFlowBranching (this);
+                       return true;
+               }
+
+               protected override void DoEmit (EmitContext ec)
+               {
+                       if (ig != null && ig != ec.ig)
+                               throw new InternalErrorException ("cannot happen");
+                       LabelTarget (ec);
+                       ec.ig.MarkLabel (label);
+               }
+
+               public void AddReference ()
+               {
+                       referenced = true;
+               }
+       }
+       
+
+       /// <summary>
+       ///   `goto default' statement
+       /// </summary>
+       public class GotoDefault : Statement {
+               
+               public GotoDefault (Location l)
+               {
+                       loc = l;
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       ec.CurrentBranching.CurrentUsageVector.Goto ();
+                       return true;
+               }
+
+               protected override void DoEmit (EmitContext ec)
+               {
+                       if (ec.Switch == null){
+                               Report.Error (153, loc, "A goto case is only valid inside a switch statement");
+                               return;
+                       }
+
+                       if (!ec.Switch.GotDefault){
+                               Report.Error (159, loc, "No such label `default:' within the scope of the goto statement");
+                               return;
+                       }
+                       ec.ig.Emit (OpCodes.Br, ec.Switch.DefaultTarget);
+               }
+       }
+
+       /// <summary>
+       ///   `goto case' statement
+       /// </summary>
+       public class GotoCase : Statement {
+               Expression expr;
+               SwitchLabel sl;
+               
+               public GotoCase (Expression e, Location l)
+               {
+                       expr = e;
+                       loc = l;
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       if (ec.Switch == null){
+                               Report.Error (153, loc, "A goto case is only valid inside a switch statement");
+                               return false;
+                       }
+
+                       expr = expr.Resolve (ec);
+                       if (expr == null)
+                               return false;
+
+                       Constant c = expr as Constant;
+                       if (c == null) {
+                               Error (150, "A constant value is expected");
+                               return false;
+                       }
+
+                       Type type = ec.Switch.SwitchType;
+                       if (!Convert.ImplicitStandardConversionExists (c, type))
+                               Report.Warning (469, 2, loc, "The `goto case' value is not implicitly " +
+                                               "convertible to type `{0}'", TypeManager.CSharpName (type));
+
+                       bool fail = false;
+                       object val = c.GetValue ();
+                       if ((val != null) && (c.Type != type) && (c.Type != TypeManager.object_type))
+                               val = TypeManager.ChangeType (val, type, out fail);
+
+                       if (fail) {
+                               Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
+                                             c.GetSignatureForError (), TypeManager.CSharpName (type));
+                               return false;
+                       }
+
+                       if (val == null)
+                               val = SwitchLabel.NullStringCase;
+                                       
+                       sl = (SwitchLabel) ec.Switch.Elements [val];
+
+                       if (sl == null){
+                               Report.Error (159, loc, "No such label `case {0}:' within the scope of the goto statement", c.GetValue () == null ? "null" : val.ToString ());
+                               return false;
+                       }
+
+                       ec.CurrentBranching.CurrentUsageVector.Goto ();
+                       return true;
+               }
+
+               protected override void DoEmit (EmitContext ec)
+               {
+                       ec.ig.Emit (OpCodes.Br, sl.GetILLabelCode (ec));
+               }
+       }
+       
+       public class Throw : Statement {
+               Expression expr;
+               
+               public Throw (Expression expr, Location l)
+               {
+                       this.expr = expr;
+                       loc = l;
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       ec.CurrentBranching.CurrentUsageVector.Throw ();
+
+                       if (expr != null){
+                               expr = expr.Resolve (ec);
+                               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) &&
+                                   !TypeManager.IsSubclassOf (t, TypeManager.exception_type) &&
+                                   !(expr is NullLiteral)) {
+                                       Error (155,
+                                               "The type caught or thrown must be derived " +
+                                               "from System.Exception");
+                                       return false;
+                               }
+                               return true;
+                       }
+
+                       if (!ec.InCatch) {
+                               Error (156, "A throw statement with no arguments is not allowed outside of a catch clause");
+                               return false;
+                       }
+
+                       if (ec.InFinally) {
+                               Error (724, "A throw statement with no arguments is not allowed inside of a finally clause nested inside of the innermost catch clause");
+                               return false;
+                       }
+                       return true;
+               }
+                       
+               protected override void DoEmit (EmitContext ec)
+               {
+                       if (expr == null)
+                               ec.ig.Emit (OpCodes.Rethrow);
+                       else {
+                               expr.Emit (ec);
+
+                               ec.ig.Emit (OpCodes.Throw);
+                       }
+               }
+       }
+
+       public class Break : Statement {
+               
+               public Break (Location l)
+               {
+                       loc = l;
+               }
+
+               bool unwind_protect;
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       int errors = Report.Errors;
+                       unwind_protect = ec.CurrentBranching.AddBreakOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
+                       ec.CurrentBranching.CurrentUsageVector.Goto ();
+                       return errors == Report.Errors;
+               }
+
+               protected override void DoEmit (EmitContext ec)
+               {
+                       ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopEnd);
+               }
+       }
+
+       public class Continue : Statement {
+               
+               public Continue (Location l)
+               {
+                       loc = l;
+               }
+
+               bool unwind_protect;
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       int errors = Report.Errors;
+                       unwind_protect = ec.CurrentBranching.AddContinueOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
+                       ec.CurrentBranching.CurrentUsageVector.Goto ();
+                       return errors == Report.Errors;
+               }
+
+               protected override void DoEmit (EmitContext ec)
+               {
+                       ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin);
+               }
+       }
+
+       public abstract class Variable
+       {
+               public abstract Type Type {
+                       get;
+               }
+
+               public abstract bool HasInstance {
+                       get;
+               }
+
+               public abstract bool NeedsTemporary {
+                       get;
+               }
+
+               public abstract void EmitInstance (EmitContext ec);
+
+               public abstract void Emit (EmitContext ec);
+
+               public abstract void EmitAssign (EmitContext ec);
+
+               public abstract void EmitAddressOf (EmitContext ec);
+       }
+
+       //
+       // The information about a user-perceived local variable
+       //
+       public class LocalInfo {
+               public Expression Type;
+
+               public Type VariableType;
+               public readonly string Name;
+               public readonly Location Location;
+               public readonly Block Block;
+
+               public VariableInfo VariableInfo;
+
+               Variable var;
+               public Variable Variable {
+                       get { return var; }
+               }
+
+               [Flags]
+               enum Flags : byte {
+                       Used = 1,
+                       ReadOnly = 2,
+                       Pinned = 4,
+                       IsThis = 8,
+                       Captured = 16,
+                       AddressTaken = 32,
+                       CompilerGenerated = 64,
+                       IsConstant = 128
+               }
+
+               public enum ReadOnlyContext: byte {
+                       Using,
+                       Foreach,
+                       Fixed
+               }
+
+               Flags flags;
+               ReadOnlyContext ro_context;
+               
+               public LocalInfo (Expression type, string name, Block block, Location l)
+               {
+                       Type = type;
+                       Name = name;
+                       Block = block;
+                       Location = l;
+               }
+
+               public LocalInfo (DeclSpace ds, Block block, Location l)
+               {
+                       VariableType = ds.TypeBuilder;
+                       Block = block;
+                       Location = l;
+               }
+
+               public void ResolveVariable (EmitContext ec)
+               {
+                       Block theblock = Block;
+                       while (theblock.Implicit)
+                               theblock = theblock.Parent;
+                       if (theblock.ScopeInfo != null)
+                               var = theblock.ScopeInfo.GetCapturedVariable (this);
+
+                       if (var == null) {
+                               LocalBuilder builder;
+                               if (Pinned)
+                                       //
+                                       // This is needed to compile on both .NET 1.x and .NET 2.x
+                                       // the later introduced `DeclareLocal (Type t, bool pinned)'
+                                       //
+                                       builder = TypeManager.DeclareLocalPinned (ec.ig, VariableType);
+                               else
+                                       builder = ec.ig.DeclareLocal (VariableType);
+
+                               var = new LocalVariable (this, builder);
+                       }
+               }
+
+               public bool IsThisAssigned (EmitContext ec, Location loc)
+               {
+                       if (VariableInfo == null)
+                               throw new Exception ();
+
+                       if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo))
+                               return true;
+
+                       return VariableInfo.TypeInfo.IsFullyInitialized (ec.CurrentBranching, VariableInfo, loc);
+               }
+
+               public bool IsAssigned (EmitContext ec)
+               {
+                       if (VariableInfo == null)
+                               throw new Exception ();
+
+                       return !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo);
+               }
+
+               public bool Resolve (EmitContext ec)
+               {
+                       if (VariableType == null) {
+                               TypeExpr texpr = Type.ResolveAsTypeTerminal (ec, false);
+                               if (texpr == null)
+                                       return false;
+                               
+                               VariableType = texpr.Type;
+                       }
+
+                       if (VariableType == TypeManager.void_type) {
+                               Expression.Error_VoidInvalidInTheContext (Location);
+                               return false;
+                       }
+
+                       if (VariableType.IsAbstract && VariableType.IsSealed) {
+                               FieldMember.Error_VariableOfStaticClass (Location, Name, VariableType);
+                               return false;
+                       }
+
+                       if (VariableType.IsPointer && !ec.InUnsafe)
+                               Expression.UnsafeError (Location);
+
+                       return true;
+               }
+
+               public bool IsCaptured {
+                       get {
+                               return (flags & Flags.Captured) != 0;
+                       }
+
+                       set {
+                               flags |= Flags.Captured;
+                       }
+               }
+
+               public bool IsConstant {
+                       get {
+                               return (flags & Flags.IsConstant) != 0;
+                       }
+                       set {
+                               flags |= Flags.IsConstant;
+                       }
+               }
+
+               public bool AddressTaken {
+                       get {
+                               return (flags & Flags.AddressTaken) != 0;
+                       }
+
+                       set {
+                               flags |= Flags.AddressTaken;
+                       }
+               }
+
+               public bool CompilerGenerated {
+                       get {
+                               return (flags & Flags.CompilerGenerated) != 0;
+                       }
+
+                       set {
+                               flags |= Flags.CompilerGenerated;
+                       }
+               }
+
+               public override string ToString ()
+               {
+                       return String.Format ("LocalInfo ({0},{1},{2},{3})",
+                                             Name, Type, VariableInfo, Location);
+               }
+
+               public bool Used {
+                       get {
+                               return (flags & Flags.Used) != 0;
+                       }
+                       set {
+                               flags = value ? (flags | Flags.Used) : (unchecked (flags & ~Flags.Used));
+                       }
+               }
+
+               public bool ReadOnly {
+                       get {
+                               return (flags & Flags.ReadOnly) != 0;
+                       }
+               }
+
+               public void SetReadOnlyContext (ReadOnlyContext context)
+               {
+                       flags |= Flags.ReadOnly;
+                       ro_context = context;
+               }
+
+               public string GetReadOnlyContext ()
+               {
+                       if (!ReadOnly)
+                               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";
+                       }
+                       throw new NotImplementedException ();
+               }
+
+               //
+               // Whether the variable is pinned, if Pinned the variable has been 
+               // allocated in a pinned slot with DeclareLocal.
+               //
+               public bool Pinned {
+                       get {
+                               return (flags & Flags.Pinned) != 0;
+                       }
+                       set {
+                               flags = value ? (flags | Flags.Pinned) : (flags & ~Flags.Pinned);
+                       }
+               }
+
+               public bool IsThis {
+                       get {
+                               return (flags & Flags.IsThis) != 0;
+                       }
+                       set {
+                               flags = value ? (flags | Flags.IsThis) : (flags & ~Flags.IsThis);
+                       }
+               }
+
+               protected class LocalVariable : Variable
+               {
+                       public readonly LocalInfo LocalInfo;
+                       LocalBuilder builder;
+
+                       public LocalVariable (LocalInfo local, LocalBuilder builder)
+                       {
+                               this.LocalInfo = local;
+                               this.builder = builder;
+                       }
+
+                       public override Type Type {
+                               get { return LocalInfo.VariableType; }
+                       }
+
+                       public override bool HasInstance {
+                               get { return false; }
+                       }
+
+                       public override bool NeedsTemporary {
+                               get { return false; }
+                       }
+
+                       public override void EmitInstance (EmitContext ec)
+                       {
+                               // Do nothing.
+                       }
+
+                       public override void Emit (EmitContext ec)
+                       {
+                               ec.ig.Emit (OpCodes.Ldloc, builder);
+                       }
+
+                       public override void EmitAssign (EmitContext ec)
+                       {
+                               ec.ig.Emit (OpCodes.Stloc, builder);
+                       }
+
+                       public override void EmitAddressOf (EmitContext ec)
+                       {
+                               ec.ig.Emit (OpCodes.Ldloca, builder);
+                       }
+               }
+       }
+               
+       /// <summary>
+       ///   Block represents a C# block.
+       /// </summary>
+       ///
+       /// <remarks>
+       ///   This class is used in a number of places: either to represent
+       ///   explicit blocks that the programmer places or implicit blocks.
+       ///
+       ///   Implicit blocks are used as labels or to introduce variable
+       ///   declarations.
+       ///
+       ///   Top-level blocks derive from Block, and they are called ToplevelBlock
+       ///   they contain extra information that is not necessary on normal blocks.
+       /// </remarks>
+       public class Block : Statement {
+               public Block    Parent;
+               public readonly Location  StartLocation;
+               public Location EndLocation = Location.Null;
+
+               public readonly ToplevelBlock Toplevel;
+
+               [Flags]
+               public enum Flags : ushort {
+                       Implicit  = 1,
+                       Unchecked = 2,
+                       BlockUsed = 4,
+                       VariablesInitialized = 8,
+                       HasRet = 16,
+                       IsDestructor = 32,
+                       IsToplevel = 64,
+                       Unsafe = 128,
+                       HasVarargs = 256, // Used in ToplevelBlock
+                       IsIterator = 512
+
+               }
+               protected Flags flags;
+
+               public bool Implicit {
+                       get { return (flags & Flags.Implicit) != 0; }
+               }
+
+               public bool Unchecked {
+                       get { return (flags & Flags.Unchecked) != 0; }
+                       set { flags |= Flags.Unchecked; }
+               }
+
+               public bool Unsafe {
+                       get { return (flags & Flags.Unsafe) != 0; }
+                       set { flags |= Flags.Unsafe; }
+               }
+
+               //
+               // The statements in this block
+               //
+               protected ArrayList statements;
+               int num_statements;
+
+               //
+               // An array of Blocks.  We keep track of children just
+               // to generate the local variable declarations.
+               //
+               // Statements and child statements are handled through the
+               // statements.
+               //
+               ArrayList children;
+
+               //
+               // Labels.  (label, block) pairs.
+               //
+               Hashtable labels;
+
+               //
+               // Keeps track of (name, type) pairs
+               //
+               IDictionary variables;
+
+               //
+               // Keeps track of constants
+               Hashtable constants;
+
+               //
+               // Temporary variables.
+               //
+               ArrayList temporary_variables;
+               
+               //
+               // If this is a switch section, the enclosing switch block.
+               //
+               Block switch_block;
+
+               ExpressionStatement scope_init;
+
+               ArrayList anonymous_children;
+
+               protected static int id;
+
+               int this_id;
+               
+               public Block (Block parent)
+                       : this (parent, (Flags) 0, Location.Null, Location.Null)
+               { }
+
+               public Block (Block parent, Flags flags)
+                       : this (parent, flags, Location.Null, Location.Null)
+               { }
+
+               public Block (Block parent, Location start, Location end)
+                       : this (parent, (Flags) 0, start, end)
+               { }
+
+               public Block (Block parent, Flags flags, Location start, Location end)
+               {
+                       if (parent != null)
+                               parent.AddChild (this);
+                       
+                       this.Parent = parent;
+                       this.flags = flags;
+                       this.StartLocation = start;
+                       this.EndLocation = end;
+                       this.loc = start;
+                       this_id = id++;
+                       statements = new ArrayList ();
+
+                       if ((flags & Flags.IsToplevel) != 0)
+                               Toplevel = (ToplevelBlock) this;
+                       else
+                               Toplevel = parent.Toplevel;
+
+                       if (parent != null && Implicit) {
+                               if (parent.known_variables == null)
+                                       parent.known_variables = new Hashtable ();
+                               // share with parent
+                               known_variables = parent.known_variables;
+                       }
+               }
+
+               public Block CreateSwitchBlock (Location start)
+               {
+                       Block new_block = new Block (this, start, start);
+                       new_block.switch_block = this;
+                       return new_block;
+               }
+
+               public int ID {
+                       get { return this_id; }
+               }
+
+               public IDictionary Variables {
+                       get {
+                               if (variables == null)
+                                       variables = new ListDictionary ();
+                               return variables;
+                       }
+               }
+
+               void AddChild (Block b)
+               {
+                       if (children == null)
+                               children = new ArrayList ();
+                       
+                       children.Add (b);
+               }
+
+               public void SetEndLocation (Location loc)
+               {
+                       EndLocation = loc;
+               }
+
+               protected static void Error_158 (string name, Location loc)
+               {
+                       Report.Error (158, loc, "The label `{0}' shadows another label " +
+                                     "by the same name in a contained scope.", name);
+               }
+
+               /// <summary>
+               ///   Adds a label to the current block. 
+               /// </summary>
+               ///
+               /// <returns>
+               ///   false if the name already exists in this block. true
+               ///   otherwise.
+               /// </returns>
+               ///
+               public bool AddLabel (LabeledStatement target)
+               {
+                       if (switch_block != null)
+                               return switch_block.AddLabel (target);
+
+                       string name = target.Name;
+
+                       Block cur = this;
+                       while (cur != null) {
+                               if (cur.DoLookupLabel (name) != null) {
+                                       Report.Error (140, target.loc,
+                                                     "The label `{0}' is a duplicate", name);
+                                       return false;
+                               }
+
+                               if (!Implicit)
+                                       break;
+
+                               cur = cur.Parent;
+                       }
+
+                       while (cur != null) {
+                               if (cur.DoLookupLabel (name) != null) {
+                                       Error_158 (name, target.loc);
+                                       return false;
+                               }
+
+                               if (children != null) {
+                                       foreach (Block b in children) {
+                                               LabeledStatement s = b.DoLookupLabel (name);
+                                               if (s == null)
+                                                       continue;
+
+                                               Error_158 (name, target.loc);
+                                               return false;
+                                       }
+                               }
+
+                               cur = cur.Parent;
+                       }
+
+                       Toplevel.CheckError158 (name, target.loc);
+
+                       if (labels == null)
+                               labels = new Hashtable ();
+
+                       labels.Add (name, target);
+                       return true;
+               }
+
+               public LabeledStatement LookupLabel (string name)
+               {
+                       LabeledStatement s = DoLookupLabel (name);
+                       if (s != null)
+                               return s;
+
+                       if (children == null)
+                               return null;
+
+                       foreach (Block child in children) {
+                               if (!child.Implicit)
+                                       continue;
+
+                               s = child.LookupLabel (name);
+                               if (s != null)
+                                       return s;
+                       }
+
+                       return null;
+               }
+
+               LabeledStatement DoLookupLabel (string name)
+               {
+                       if (switch_block != null)
+                               return switch_block.LookupLabel (name);
+
+                       if (labels != null)
+                               if (labels.Contains (name))
+                                       return ((LabeledStatement) labels [name]);
+
+                       return null;
+               }
+
+               Hashtable known_variables;
+
+               // <summary>
+               //   Marks a variable with name @name as being used in this or a child block.
+               //   If a variable name has been used in a child block, it's illegal to
+               //   declare a variable with the same name in the current block.
+               // </summary>
+               void AddKnownVariable (string name, LocalInfo info)
+               {
+                       if (known_variables == null)
+                               known_variables = new Hashtable ();
+
+                       known_variables [name] = info;
+               }
+
+               LocalInfo GetKnownVariableInfo (string name, bool recurse)
+               {
+                       if (known_variables != null) {
+                               LocalInfo vi = (LocalInfo) known_variables [name];
+                               if (vi != null)
+                                       return vi;
+                       }
+
+                       if (!recurse || (children == null))
+                               return null;
+
+                       foreach (Block block in children) {
+                               LocalInfo vi = block.GetKnownVariableInfo (name, true);
+                               if (vi != null)
+                                       return vi;
+                       }
+
+                       return null;
+               }
+
+               public bool CheckInvariantMeaningInBlock (string name, Expression e, Location loc)
+               {
+                       Block b = this;
+                       LocalInfo kvi = b.GetKnownVariableInfo (name, true);
+                       while (kvi == null) {
+                               while (b.Implicit)
+                                       b = b.Parent;
+                               b = b.Parent;
+                               if (b == null)
+                                       return true;
+                               kvi = b.GetKnownVariableInfo (name, false);
+                       }
+
+                       if (kvi.Block == b)
+                               return true;
+
+                       // Is kvi.Block nested inside 'b'
+                       if (b.known_variables != kvi.Block.known_variables) {
+                               //
+                               // If a variable by the same name it defined in a nested block of this
+                               // block, we violate the invariant meaning in a block.
+                               //
+                               if (b == this) {
+                                       Report.SymbolRelatedToPreviousError (kvi.Location, name);
+                                       Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", name);
+                                       return false;
+                               }
+
+                               //
+                               // It's ok if the definition is in a nested subblock of b, but not
+                               // nested inside this block -- a definition in a sibling block
+                               // should not affect us.
+                               //
+                               return true;
+                       }
+
+                       //
+                       // Block 'b' and kvi.Block are the same textual block.
+                       // However, different variables are extant.
+                       //
+                       // Check if the variable is in scope in both blocks.  We use
+                       // an indirect check that depends on AddVariable doing its
+                       // part in maintaining the invariant-meaning-in-block property.
+                       //
+                       if (e is LocalVariableReference || (e is Constant && b.GetLocalInfo (name) != null))
+                               return true;
+
+                       //
+                       // Even though we detected the error when the name is used, we
+                       // treat it as if the variable declaration was in error.
+                       //
+                       Report.SymbolRelatedToPreviousError (loc, name);
+                       Error_AlreadyDeclared (kvi.Location, name, "parent or current");
+                       return false;
+               }
+
+               public bool CheckError136_InParents (string name, Location loc)
+               {
+                       for (Block b = Parent; b != null; b = b.Parent) {
+                               if (!b.DoCheckError136 (name, "parent or current", loc))
+                                       return false;
+                       }
+
+                       for (Block b = Toplevel.ContainerBlock; b != null; b = b.Toplevel.ContainerBlock) {
+                               if (!b.CheckError136_InParents (name, loc))
+                                       return false;
+                       }
+
+                       return true;
+               }
+
+               public bool CheckError136_InChildren (string name, Location loc)
+               {
+                       if (!DoCheckError136_InChildren (name, loc))
+                               return false;
+
+                       Block b = this;
+                       while (b.Implicit) {
+                               if (!b.Parent.DoCheckError136_InChildren (name, loc))
+                                       return false;
+                               b = b.Parent;
+                       }
+
+                       return true;
+               }
+
+               protected bool DoCheckError136_InChildren (string name, Location loc)
+               {
+                       if (!DoCheckError136 (name, "child", loc))
+                               return false;
+
+                       if (AnonymousChildren != null) {
+                               foreach (ToplevelBlock child in AnonymousChildren) {
+                                       if (!child.DoCheckError136_InChildren (name, loc))
+                                               return false;
+                               }
+                       }
+
+                       if (children != null) {
+                               foreach (Block child in children) {
+                                       if (!child.DoCheckError136_InChildren (name, loc))
+                                               return false;
+                               }
+                       }
+
+                       return true;
+               }
+
+               public bool CheckError136 (string name, string scope, bool check_parents,
+                                          bool check_children, Location loc)
+               {
+                       if (!DoCheckError136 (name, scope, loc))
+                               return false;
+
+                       if (check_parents) {
+                               if (!CheckError136_InParents (name, loc))
+                                       return false;
+                       }
+
+                       if (check_children) {
+                               if (!CheckError136_InChildren (name, loc))
+                                       return false;
+                       }
+
+                       for (Block c = Toplevel.ContainerBlock; c != null; c = c.Toplevel.ContainerBlock) {
+                               if (!c.DoCheckError136 (name, "parent or current", loc))
+                                       return false;
+                       }
+
+                       return true;
+               }
+
+               protected bool DoCheckError136 (string name, string scope, Location loc)
+               {
+                       LocalInfo vi = GetKnownVariableInfo (name, false);
+                       if (vi != null) {
+                               Report.SymbolRelatedToPreviousError (vi.Location, name);
+                               Error_AlreadyDeclared (loc, name, scope != null ? scope : "child");
+                               return false;
+                       }
+
+                       int idx;
+                       Parameter p = Toplevel.Parameters.GetParameterByName (name, out idx);
+                       if (p != null) {
+                               Report.SymbolRelatedToPreviousError (p.Location, name);
+                               Error_AlreadyDeclared (
+                                       loc, name, scope != null ? scope : "method argument");
+                               return false;
+                       }
+
+                       return true;
+               }
+
+               public LocalInfo AddVariable (Expression type, string name, Location l)
+               {
+                       LocalInfo vi = GetLocalInfo (name);
+                       if (vi != null) {
+                               Report.SymbolRelatedToPreviousError (vi.Location, name);
+                               if (known_variables == vi.Block.known_variables)
+                                       Report.Error (128, l,
+                                               "A local variable named `{0}' is already defined in this scope", name);
+                               else
+                                       Error_AlreadyDeclared (l, name, "parent");
+                               return null;
+                       }
+
+                       if (!CheckError136 (name, null, true, true, l))
+                               return null;
+
+                       vi = new LocalInfo (type, name, this, l);
+                       Variables.Add (name, vi);
+                       AddKnownVariable (name, vi);
+
+                       if ((flags & Flags.VariablesInitialized) != 0)
+                               throw new Exception ();
+
+                       return vi;
+               }
+
+               void Error_AlreadyDeclared (Location loc, string var, string reason)
+               {
+                       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);
+               }
+
+               public bool AddConstant (Expression type, string name, Expression value, Location l)
+               {
+                       if (AddVariable (type, name, l) == null)
+                               return false;
+                       
+                       if (constants == null)
+                               constants = new Hashtable ();
+
+                       constants.Add (name, value);
+
+                       // A block is considered used if we perform an initialization in a local declaration, even if it is constant.
+                       Use ();
+                       return true;
+               }
+
+               static int next_temp_id = 0;
+
+               public LocalInfo AddTemporaryVariable (TypeExpr te, Location loc)
+               {
+                       Report.Debug (64, "ADD TEMPORARY", this, Toplevel, loc);
+
+                       if (temporary_variables == null)
+                               temporary_variables = new ArrayList ();
+
+                       int id = ++next_temp_id;
+                       string name = "$s_" + id.ToString ();
+
+                       LocalInfo li = new LocalInfo (te, name, this, loc);
+                       li.CompilerGenerated = true;
+                       temporary_variables.Add (li);
+                       return li;
+               }
+
+               public LocalInfo GetLocalInfo (string name)
+               {
+                       for (Block b = this; b != null; b = b.Parent) {
+                               if (b.variables != null) {
+                                       LocalInfo ret = b.variables [name] as LocalInfo;
+                                       if (ret != null)
+                                               return ret;
+                               }
+                       }
+                       return null;
+               }
+
+               public Expression GetVariableType (string name)
+               {
+                       LocalInfo vi = GetLocalInfo (name);
+                       return vi == null ? null : vi.Type;
+               }
+
+               public Expression GetConstantExpression (string name)
+               {
+                       for (Block b = this; b != null; b = b.Parent) {
+                               if (b.constants != null) {
+                                       Expression ret = b.constants [name] as Expression;
+                                       if (ret != null)
+                                               return ret;
+                               }
+                       }
+                       return null;
+               }
+               
+               public void AddStatement (Statement s)
+               {
+                       statements.Add (s);
+                       flags |= Flags.BlockUsed;
+               }
+
+               public bool Used {
+                       get { return (flags & Flags.BlockUsed) != 0; }
+               }
+
+               public void Use ()
+               {
+                       flags |= Flags.BlockUsed;
+               }
+
+               public bool HasRet {
+                       get { return (flags & Flags.HasRet) != 0; }
+               }
+
+               public bool IsDestructor {
+                       get { return (flags & Flags.IsDestructor) != 0; }
+               }
+
+               public void SetDestructor ()
+               {
+                       flags |= Flags.IsDestructor;
+               }
+
+               VariableMap param_map, local_map;
+
+               public VariableMap ParameterMap {
+                       get {
+                               if ((flags & Flags.VariablesInitialized) == 0)
+                                       throw new Exception ("Variables have not been initialized yet");
+
+                               return param_map;
+                       }
+               }
+
+               public VariableMap LocalMap {
+                       get {
+                               if ((flags & Flags.VariablesInitialized) == 0)
+                                       throw new Exception ("Variables have not been initialized yet");
+
+                               return local_map;
+                       }
+               }
+
+               public ScopeInfo ScopeInfo;
+
+               public ScopeInfo CreateScopeInfo ()
+               {
+                       if (Implicit)
+                               return Parent.CreateScopeInfo ();
+
+                       if (ScopeInfo == null)
+                               ScopeInfo = new ScopeInfo (Toplevel.AnonymousMethodHost, this);
+
+                       return ScopeInfo;
+               }
+
+               public ArrayList AnonymousChildren {
+                       get { return anonymous_children; }
+               }
+
+               public void AddAnonymousChild (ToplevelBlock b)
+               {
+                       if (anonymous_children == null)
+                               anonymous_children = new ArrayList ();
+
+                       anonymous_children.Add (b);
+               }
+
+               /// <summary>
+               ///   Emits the variable declarations and labels.
+               /// </summary>
+               /// <remarks>
+               ///   tc: is our typecontainer (to resolve type references)
+               ///   ig: is the code generator:
+               /// </remarks>
+               public void ResolveMeta (ToplevelBlock toplevel, EmitContext ec, Parameters ip)
+               {
+                       Report.Debug (64, "BLOCK RESOLVE META", this, Parent, toplevel);
+
+                       // If some parent block was unsafe, we remain unsafe even if this block
+                       // isn't explicitly marked as such.
+                       using (ec.With (EmitContext.Flags.InUnsafe, ec.InUnsafe | Unsafe)) {
+                               //
+                               // Compute the VariableMap's.
+                               //
+                               // Unfortunately, we don't know the type when adding variables with
+                               // AddVariable(), so we need to compute this info here.
+                               //
+
+                               LocalInfo[] locals;
+                               if (variables != null) {
+                                       foreach (LocalInfo li in variables.Values)
+                                               li.Resolve (ec);
+
+                                       locals = new LocalInfo [variables.Count];
+                                       variables.Values.CopyTo (locals, 0);
+                               } else
+                                       locals = new LocalInfo [0];
+
+                               if (Parent != null)
+                                       local_map = new VariableMap (Parent.LocalMap, locals);
+                               else
+                                       local_map = new VariableMap (locals);
+
+                               param_map = new VariableMap (ip);
+                               flags |= Flags.VariablesInitialized;
+
+                               //
+                               // Process this block variables
+                               //
+                               if (variables != null) {
+                                       foreach (DictionaryEntry de in variables) {
+                                               string name = (string) de.Key;
+                                               LocalInfo vi = (LocalInfo) de.Value;
+                                               Type variable_type = vi.VariableType;
+
+                                               if (variable_type == null)
+                                                       continue;
+
+                                               if (variable_type.IsPointer) {
+                                                       //
+                                                       // Am not really convinced that this test is required (Microsoft does it)
+                                                       // but the fact is that you would not be able to use the pointer variable
+                                                       // *anyways*
+                                                       //
+                                                       if (!TypeManager.VerifyUnManaged (TypeManager.GetElementType (variable_type),
+                                                                                         vi.Location))
+                                                               continue;
+                                               }
+
+                                               if (constants == null)
+                                                       continue;
+
+                                               Expression cv = (Expression) constants [name];
+                                               if (cv == null)
+                                                       continue;
+
+                                               // Don't let 'const int Foo = Foo;' succeed.
+                                               // Removing the name from 'constants' ensures that we get a LocalVariableReference below,
+                                               // which in turn causes the 'must be constant' error to be triggered.
+                                               constants.Remove (name);
+
+                                               if (!Const.IsConstantTypeValid (variable_type)) {
+                                                       Const.Error_InvalidConstantType (variable_type, loc);
+                                                       continue;
+                                               }
+
+                                               using (ec.With (EmitContext.Flags.ConstantCheckState, (flags & Flags.Unchecked) == 0)) {
+                                                       ec.CurrentBlock = this;
+                                                       Expression e = cv.Resolve (ec);
+                                                       if (e == null)
+                                                               continue;
+
+                                                       Constant ce = e as Constant;
+                                                       if (ce == null) {
+                                                               Const.Error_ExpressionMustBeConstant (vi.Location, name);
+                                                               continue;
+                                                       }
+
+                                                       e = ce.ImplicitConversionRequired (variable_type, vi.Location);
+                                                       if (e == null)
+                                                               continue;
+
+                                                       if (!variable_type.IsValueType && variable_type != TypeManager.string_type && !ce.IsDefaultValue) {
+                                                               Const.Error_ConstantCanBeInitializedWithNullOnly (vi.Location, vi.Name);
+                                                               continue;
+                                                       }
+
+                                                       constants.Add (name, e);
+                                                       vi.IsConstant = true;
+                                               }
+                                       }
+                               }
+
+                               //
+                               // Now, handle the children
+                               //
+                               if (children != null) {
+                                       foreach (Block b in children)
+                                               b.ResolveMeta (toplevel, ec, ip);
+                               }
+                       }
+               }
+
+               //
+               // Emits the local variable declarations for a block
+               //
+               public virtual void EmitMeta (EmitContext ec)
+               {
+                       Report.Debug (64, "BLOCK EMIT META", this, Toplevel, ScopeInfo, ec);
+                       if (ScopeInfo != null) {
+                               scope_init = ScopeInfo.GetScopeInitializer (ec);
+                               Report.Debug (64, "BLOCK EMIT META #1", this, Toplevel, ScopeInfo,
+                                             ec, scope_init);
+                       }
+
+                       if (variables != null){
+                               foreach (LocalInfo vi in variables.Values)
+                                       vi.ResolveVariable (ec);
+                       }
+
+                       if (temporary_variables != null) {
+                               foreach (LocalInfo vi in temporary_variables)
+                                       vi.ResolveVariable (ec);
+                       }
+
+                       if (children != null){
+                               foreach (Block b in children)
+                                       b.EmitMeta (ec);
+                       }
+               }
+
+               void UsageWarning (FlowBranching.UsageVector vector)
+               {
+                       string name;
+
+                       if ((variables != null) && (RootContext.WarningLevel >= 3)) {
+                               foreach (DictionaryEntry de in variables){
+                                       LocalInfo vi = (LocalInfo) de.Value;
+
+                                       if (vi.Used)
+                                               continue;
+
+                                       name = (string) de.Key;
+
+                                       // vi.VariableInfo can be null for 'catch' variables
+                                       if (vi.VariableInfo != null && vector.IsAssigned (vi.VariableInfo, true)){
+                                               Report.Warning (219, 3, vi.Location, "The variable `{0}' is assigned but its value is never used", name);
+                                       } else {
+                                               Report.Warning (168, 3, vi.Location, "The variable `{0}' is declared but never used", name);
+                                       }
+                               }
+                       }
+               }
+
+               bool unreachable_shown;
+               bool unreachable;
+
+               private void CheckPossibleMistakenEmptyStatement (Statement s)
+               {
+                       Statement body;
+
+                       // Some statements are wrapped by a Block. Since
+                       // others' internal could be changed, here I treat
+                       // them as possibly wrapped by Block equally.
+                       Block b = s as Block;
+                       if (b != null && b.statements.Count == 1)
+                               s = (Statement) b.statements [0];
+
+                       if (s is Lock)
+                               body = ((Lock) s).Statement;
+                       else if (s is For)
+                               body = ((For) s).Statement;
+                       else if (s is Foreach)
+                               body = ((Foreach) s).Statement;
+                       else if (s is While)
+                               body = ((While) s).Statement;
+                       else if (s is Using)
+                               body = ((Using) s).Statement;
+                       else if (s is Fixed)
+                               body = ((Fixed) s).Statement;
+                       else
+                               return;
+
+                       if (body == null || body is EmptyStatement)
+                               Report.Warning (642, 3, s.loc, "Possible mistaken empty statement");
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       Block prev_block = ec.CurrentBlock;
+                       bool ok = true;
+
+                       int errors = Report.Errors;
+
+                       ec.CurrentBlock = this;
+                       ec.StartFlowBranching (this);
+
+                       Report.Debug (4, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching);
+
+                       //
+                       // This flag is used to notate nested statements as unreachable from the beginning of this block.
+                       // For the purposes of this resolution, it doesn't matter that the whole block is unreachable 
+                       // from the beginning of the function.  The outer Resolve() that detected the unreachability is
+                       // responsible for handling the situation.
+                       //
+                       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 &&
+                                       ix + 1 < statement_count &&
+                                               statements [ix + 1] is Block)
+                                       CheckPossibleMistakenEmptyStatement (s);
+
+                               //
+                               // Warn if we detect unreachable code.
+                               //
+                               if (unreachable) {
+                                       if (s is EmptyStatement)
+                                               continue;
+
+                                       if (s is Block)
+                                               ((Block) s).unreachable = true;
+
+                                       if (!unreachable_shown && !(s is LabeledStatement)) {
+                                               Report.Warning (162, 2, s.loc, "Unreachable code detected");
+                                               unreachable_shown = true;
+                                       }
+                               }
+
+                               //
+                               // Note that we're not using ResolveUnreachable() for unreachable
+                               // statements here.  ResolveUnreachable() creates a temporary
+                               // flow branching and kills it afterwards.  This leads to problems
+                               // if you have two unreachable statements where the first one
+                               // assigns a variable and the second one tries to access it.
+                               //
+
+                               if (!s.Resolve (ec)) {
+                                       ok = false;
+                                       statements [ix] = EmptyStatement.Value;
+                                       continue;
+                               }
+
+                               if (unreachable && !(s is LabeledStatement) && !(s is Block))
+                                       statements [ix] = EmptyStatement.Value;
+
+                               num_statements = ix + 1;
+
+                               unreachable = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable;
+                               if (unreachable && s is LabeledStatement)
+                                       throw new InternalErrorException ("should not happen");
+                       }
+
+                       Report.Debug (4, "RESOLVE BLOCK DONE", StartLocation,
+                                     ec.CurrentBranching, statement_count, num_statements);
+
+                       while (ec.CurrentBranching is FlowBranchingLabeled)
+                               ec.EndFlowBranching ();
+
+                       FlowBranching.UsageVector vector = ec.DoEndFlowBranching ();
+
+                       ec.CurrentBlock = prev_block;
+
+                       // If we're a non-static `struct' constructor which doesn't have an
+                       // initializer, then we must initialize all of the struct's fields.
+                       if ((flags & Flags.IsToplevel) != 0 && 
+                           !Toplevel.IsThisAssigned (ec) &&
+                           !vector.Reachability.AlwaysThrows)
+                               ok = false;
+
+                       if ((labels != null) && (RootContext.WarningLevel >= 2)) {
+                               foreach (LabeledStatement label in labels.Values)
+                                       if (!label.HasBeenReferenced)
+                                               Report.Warning (164, 2, label.loc,
+                                                               "This label has not been referenced");
+                       }
+
+                       Report.Debug (4, "RESOLVE BLOCK DONE #2", StartLocation, vector);
+
+                       if (vector.Reachability.IsUnreachable)
+                               flags |= Flags.HasRet;
+
+                       if (ok && (errors == Report.Errors)) {
+                               if (RootContext.WarningLevel >= 3)
+                                       UsageWarning (vector);
+                       }
+
+                       return ok;
+               }
+
+               public override bool ResolveUnreachable (EmitContext ec, bool warn)
+               {
+                       unreachable_shown = true;
+                       unreachable = true;
+
+                       if (warn)
+                               Report.Warning (162, 2, loc, "Unreachable code detected");
+
+                       ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
+                       bool ok = Resolve (ec);
+                       ec.KillFlowBranching ();
+
+                       return ok;
+               }
+               
+               protected override void DoEmit (EmitContext ec)
+               {
+                       for (int ix = 0; ix < num_statements; ix++){
+                               Statement s = (Statement) statements [ix];
+
+                               // Check whether we are the last statement in a
+                               // top-level block.
+
+                               if (((Parent == null) || Implicit) && (ix+1 == num_statements) && !(s is Block))
+                                       ec.IsLastStatement = true;
+                               else
+                                       ec.IsLastStatement = false;
+
+                               s.Emit (ec);
+                       }
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       Block prev_block = ec.CurrentBlock;
+
+                       ec.CurrentBlock = this;
+
+                       bool emit_debug_info = (CodeGen.SymbolWriter != null);
+                       bool is_lexical_block = !Implicit && (Parent != null);
+
+                       if (emit_debug_info) {
+                               if (is_lexical_block)
+                                       ec.BeginScope ();
+                       }
+                       ec.Mark (StartLocation, true);
+                       if (scope_init != null)
+                               scope_init.EmitStatement (ec);
+                       DoEmit (ec);
+                       ec.Mark (EndLocation, true); 
+
+                       if (emit_debug_info && is_lexical_block)
+                               ec.EndScope ();
+
+                       ec.CurrentBlock = prev_block;
+               }
+
+               //
+               // Returns true if we ar ea child of `b'.
+               //
+               public bool IsChildOf (Block b)
+               {
+                       Block current = this;
+                       
+                       do {
+                               if (current.Parent == b)
+                                       return true;
+                               current = current.Parent;
+                       } while (current != null);
+                       return false;
+               }
+
+               public override string ToString ()
+               {
+                       return String.Format ("{0} ({1}:{2})", GetType (),ID, StartLocation);
+               }
+       }
+
+       //
+       // A toplevel block contains extra information, the split is done
+       // only to separate information that would otherwise bloat the more
+       // lightweight Block.
+       //
+       // In particular, this was introduced when the support for Anonymous
+       // Methods was implemented. 
+       // 
+       public class ToplevelBlock : Block {
+               //
+               // Pointer to the host of this anonymous method, or null
+               // if we are the topmost block
+               //
+               Block container;
+               ToplevelBlock child;    
+               GenericMethod generic;
+               FlowBranchingToplevel top_level_branching;
+               AnonymousMethodHost anonymous_method_host;
+
+               public bool HasVarargs {
+                       get { return (flags & Flags.HasVarargs) != 0; }
+                       set { flags |= Flags.HasVarargs; }
+               }
+
+               public bool IsIterator {
+                       get { return (flags & Flags.IsIterator) != 0; }
+               }
+
+               //
+               // The parameters for the block.
+               //
+               Parameters parameters;
+               public Parameters Parameters {
+                       get { return parameters; }
+               }
+
+               public bool CompleteContexts (EmitContext ec)
+               {
+                       Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS", this,
+                                     container, anonymous_method_host);
+
+                       return ScopeInfo.CompleteContexts (anonymous_method_host, container);
+               }
+
+               public GenericMethod GenericMethod {
+                       get { return generic; }
+               }
+
+               public ToplevelBlock Container {
+                       get { return container != null ? container.Toplevel : null; }
+               }
+
+               public Block ContainerBlock {
+                       get { return container; }
+               }
+
+               //
+               // Parent is only used by anonymous blocks to link back to their
+               // parents
+               //
+               public ToplevelBlock (Block container, Parameters parameters, Location start) :
+                       this (container, (Flags) 0, parameters, start)
+               {
+               }
+
+               public ToplevelBlock (Block container, Parameters parameters, GenericMethod generic,
+                                     Location start) :
+                       this (container, parameters, start)
+               {
+                       this.generic = generic;
+               }
+               
+               public ToplevelBlock (Parameters parameters, Location start) :
+                       this (null, (Flags) 0, parameters, start)
+               {
+               }
+
+               public ToplevelBlock (Flags flags, Parameters parameters, Location start) :
+                       this (null, flags, parameters, start)
+               {
+               }
+
+               public ToplevelBlock (Block container, Flags flags, Parameters parameters, Location start) :
+                       base (null, flags | Flags.IsToplevel, start, Location.Null)
+               {
+                       this.parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters;
+                       this.container = container;
+               }
+
+               public ToplevelBlock (Location loc) : this (null, (Flags) 0, null, loc)
+               {
+               }
+
+               public bool CheckError158 (string name, Location loc)
+               {
+                       if (AnonymousChildren != null) {
+                               foreach (ToplevelBlock child in AnonymousChildren) {
+                                       if (!child.CheckError158 (name, loc))
+                                               return false;
+                               }
+                       }
+
+                       for (ToplevelBlock c = Container; c != null; c = c.Container) {
+                               if (!c.DoCheckError158 (name, loc))
+                                       return false;
+                       }
+
+                       return true;
+               }
+
+               bool DoCheckError158 (string name, Location loc)
+               {
+                       LabeledStatement s = LookupLabel (name);
+                       if (s != null) {
+                               Error_158 (name, loc);
+                               return false;
+                       }
+
+                       return true;
+               }
+
+               public AnonymousMethodHost CreateAnonymousMethodHost (TypeContainer host)
+               {
+                       if (anonymous_method_host != null)
+                               return anonymous_method_host;
+
+                       if (Container != null)
+                               anonymous_method_host = new AnonymousMethodHost (
+                                       this, Container.anonymous_method_host, null, StartLocation);
+                       else
+                               anonymous_method_host = new AnonymousMethodHost (
+                                       this, host, generic, StartLocation);
+
+                       ScopeInfo = anonymous_method_host;
+                       return anonymous_method_host;
+               }
+
+               public void CreateIteratorHost (AnonymousMethodHost root_scope)
+               {
+                       Report.Debug (64, "CREATE ITERATOR HOST", this, root_scope,
+                                     container, anonymous_method_host);
+
+                       if ((container != null) || (anonymous_method_host != null))
+                               throw new InternalErrorException ();
+
+                       ScopeInfo = anonymous_method_host = root_scope;
+               }
+
+               public IAnonymousMethodHost AnonymousMethodHost {
+                       get {
+                               if (anonymous_method_host != null)
+                                       return anonymous_method_host;
+                               else if (Container != null)
+                                       return Container.AnonymousMethodHost;
+                               else
+                                       return null;
+                       }
+               }
+
+               public void EmitScopeInstance (EmitContext ec, ScopeInfo scope)
+               {
+                       ScopeInfo.EmitScopeInstance (ec, scope, this);
+               }
+
+               public FlowBranchingToplevel TopLevelBranching {
+                       get { return top_level_branching; }
+               }
+
+               //
+               // This is used if anonymous methods are used inside an iterator
+               // (see 2test-22.cs for an example).
+               //
+               // The AnonymousMethod is created while parsing - at a time when we don't
+               // know yet that we're inside an iterator, so it's `Container' is initially
+               // null.  Later on, when resolving the iterator, we need to move the
+               // anonymous method into that iterator.
+               //
+               public void ReParent (ToplevelBlock new_parent)
+               {
+                       container = new_parent;
+                       Parent = new_parent;
+                       new_parent.child = this;
+
+#if FIXME
+                       if (container != null)
+                               container.AddAnonymousChild (this);
+#endif
+               }
+
+               //
+               // Returns a `ParameterReference' for the given name, or null if there
+               // is no such parameter
+               //
+               public ParameterReference GetParameterReference (string name, Location loc)
+               {
+                       Parameter par;
+                       int idx;
+
+                       for (ToplevelBlock t = this; t != null; t = t.Container) {
+                               Parameters pars = t.Parameters;
+                               par = pars.GetParameterByName (name, out idx);
+                               if (par != null)
+                                       return new ParameterReference (par, this, idx, loc);
+                       }
+                       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>
+               //   Returns the "this" instance variable of this block.
+               //   See AddThisVariable() for more information.
+               // </summary>
+               public LocalInfo ThisVariable {
+                       get { return this_variable; }
+               }
+
+
+               // <summary>
+               //   This is used by non-static `struct' constructors which do not have an
+               //   initializer - in this case, the constructor must initialize all of the
+               //   struct's fields.  To do this, we add a "this" variable and use the flow
+               //   analysis code to ensure that it's been fully initialized before control
+               //   leaves the constructor.
+               // </summary>
+               public LocalInfo AddThisVariable (DeclSpace ds, Location l)
+               {
+                       if (this_variable == null) {
+                               this_variable = new LocalInfo (ds, this, l);
+                               this_variable.Used = true;
+                               this_variable.IsThis = true;
+
+                               Variables.Add ("this", this_variable);
+                       }
+
+                       return this_variable;
+               }
+
+               public bool IsThisAssigned (EmitContext ec)
+               {
+                       return this_variable == null || this_variable.IsThisAssigned (ec, loc);
+               }
+
+               public bool ResolveMeta (EmitContext ec, Parameters ip)
+               {
+                       int errors = Report.Errors;
+
+                       if (top_level_branching != null)
+                               return true;
+
+                       if (ip != null)
+                               parameters = ip;
+
+                       if (!IsIterator && (container != null) && (parameters != null)) {
+                               foreach (Parameter p in parameters.FixedParameters) {
+                                       if (!CheckError136_InParents (p.Name, loc))
+                                               return false;
+                               }
+                       }
+
+                       ResolveMeta (this, ec, ip);
+
+                       if (child != null)
+                               child.ResolveMeta (this, ec, ip);
+
+                       top_level_branching = ec.StartFlowBranching (this);
+
+                       return Report.Errors == errors;
+               }
+
+               public override void EmitMeta (EmitContext ec)
+               {
+                       base.EmitMeta (ec);
+                       parameters.ResolveVariable (this);
+               }
+
+               public void MakeIterator (Iterator iterator)
+               {
+                       flags |= Flags.IsIterator;
+
+                       Block block = new Block (this);
+                       foreach (Statement stmt in statements)
+                               block.AddStatement (stmt);
+                       statements = new ArrayList ();
+                       statements.Add (new MoveNextStatement (iterator, block));
+               }
+
+               protected class MoveNextStatement : Statement {
+                       Iterator iterator;
+                       Block block;
+
+                       public MoveNextStatement (Iterator iterator, Block block)
+                       {
+                               this.iterator = iterator;
+                               this.block = block;
+                               this.loc = iterator.Location;
+                       }
+
+                       public override bool Resolve (EmitContext ec)
+                       {
+                               return block.Resolve (ec);
+                       }
+
+                       protected override void DoEmit (EmitContext ec)
+                       {
+                               iterator.EmitMoveNext (ec, block);
+                       }
+               }
+
+               public override string ToString ()
+               {
+                       return String.Format ("{0} ({1}:{2}{3})", GetType (), ID, StartLocation,
+                                             anonymous_method_host);
+               }
+       }
+       
+       public class SwitchLabel {
+               Expression label;
+               object converted;
+               Location loc;
+
+               Label il_label;
+               bool  il_label_set;
+               Label il_label_code;
+               bool  il_label_code_set;
+
+               public static readonly object NullStringCase = new object ();
+
+               //
+               // if expr == null, then it is the default case.
+               //
+               public SwitchLabel (Expression expr, Location l)
+               {
+                       label = expr;
+                       loc = l;
+               }
+
+               public Expression Label {
+                       get {
+                               return label;
+                       }
+               }
+
+               public object Converted {
+                       get {
+                               return converted;
+                       }
+               }
+
+               public Label GetILLabel (EmitContext ec)
+               {
+                       if (!il_label_set){
+                               il_label = ec.ig.DefineLabel ();
+                               il_label_set = true;
+                       }
+                       return il_label;
+               }
+
+               public Label GetILLabelCode (EmitContext ec)
+               {
+                       if (!il_label_code_set){
+                               il_label_code = ec.ig.DefineLabel ();
+                               il_label_code_set = true;
+                       }
+                       return il_label_code;
+               }                               
+               
+               //
+               // Resolves the expression, reduces it to a literal if possible
+               // and then converts it to the requested type.
+               //
+               public bool ResolveAndReduce (EmitContext ec, Type required_type, bool allow_nullable)
+               {       
+                       Expression e = label.Resolve (ec);
+
+                       if (e == null)
+                               return false;
+
+                       Constant c = e as Constant;
+                       if (c == null){
+                               Report.Error (150, loc, "A constant value is expected");
+                               return false;
+                       }
+
+                       if (required_type == TypeManager.string_type && c.GetValue () == null) {
+                               converted = NullStringCase;
+                               return true;
+                       }
+
+                       if (allow_nullable && c.GetValue () == null) {
+                               converted = NullStringCase;
+                               return true;
+                       }
+
+                       c = c.ImplicitConversionRequired (required_type, loc);
+                       if (c == null)
+                               return false;
+
+                       converted = c.GetValue ();
+                       return true;
+               }
+
+               public void Erorr_AlreadyOccurs ()
+               {
+                       string label;
+                       if (converted == null)
+                               label = "default";
+                       else if (converted == NullStringCase)
+                               label = "null";
+                       else
+                               label = converted.ToString ();
+
+                       Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label);
+               }
+       }
+
+       public class SwitchSection {
+               // An array of SwitchLabels.
+               public readonly ArrayList Labels;
+               public readonly Block Block;
+               
+               public SwitchSection (ArrayList labels, Block block)
+               {
+                       Labels = labels;
+                       Block = block;
+               }
+       }
+       
+       public class Switch : Statement {
+               public readonly ArrayList Sections;
+               public Expression Expr;
+
+               /// <summary>
+               ///   Maps constants whose type type SwitchType to their  SwitchLabels.
+               /// </summary>
+               public IDictionary Elements;
+
+               /// <summary>
+               ///   The governing switch type
+               /// </summary>
+               public Type SwitchType;
+
+               //
+               // Computed
+               //
+               Label default_target;
+               Label null_target;
+               Expression new_expr;
+               bool is_constant;
+               SwitchSection constant_section;
+               SwitchSection default_section;
+
+#if GMCS_SOURCE
+               //
+               // Nullable Types support for GMCS.
+               //
+               Nullable.Unwrap unwrap;
+
+               protected bool HaveUnwrap {
+                       get { return unwrap != null; }
+               }
+#else
+               protected bool HaveUnwrap {
+                       get { return false; }
+               }
+#endif
+
+               //
+               // The types allowed to be implicitly cast from
+               // on the governing type
+               //
+               static Type [] allowed_types;
+               
+               public Switch (Expression e, ArrayList sects, Location l)
+               {
+                       Expr = e;
+                       Sections = sects;
+                       loc = l;
+               }
+
+               public bool GotDefault {
+                       get {
+                               return default_section != null;
+                       }
+               }
+
+               public Label DefaultTarget {
+                       get {
+                               return default_target;
+                       }
+               }
+
+               //
+               // Determines the governing type for a switch.  The returned
+               // expression might be the expression from the switch, or an
+               // expression that includes any potential conversions to the
+               // integral types or to string.
+               //
+               Expression SwitchGoverningType (EmitContext ec, Expression expr)
+               {
+                       Type t = expr.Type;
+
+                       if (t == TypeManager.byte_type ||
+                           t == TypeManager.sbyte_type ||
+                           t == TypeManager.ushort_type ||
+                           t == TypeManager.short_type ||
+                           t == TypeManager.uint32_type ||
+                           t == TypeManager.int32_type ||
+                           t == TypeManager.uint64_type ||
+                           t == TypeManager.int64_type ||
+                           t == TypeManager.char_type ||
+                           t == TypeManager.string_type ||
+                           t == TypeManager.bool_type ||
+                           t.IsSubclassOf (TypeManager.enum_type))
+                               return expr;
+
+                       if (allowed_types == null){
+                               allowed_types = new Type [] {
+                                       TypeManager.sbyte_type,
+                                       TypeManager.byte_type,
+                                       TypeManager.short_type,
+                                       TypeManager.ushort_type,
+                                       TypeManager.int32_type,
+                                       TypeManager.uint32_type,
+                                       TypeManager.int64_type,
+                                       TypeManager.uint64_type,
+                                       TypeManager.char_type,
+                                       TypeManager.string_type,
+                                       TypeManager.bool_type
+                               };
+                       }
+
+                       //
+                       // Try to find a *user* defined implicit conversion.
+                       //
+                       // If there is no implicit conversion, or if there are multiple
+                       // conversions, we have to report an error
+                       //
+                       Expression converted = null;
+                       foreach (Type tt in allowed_types){
+                               Expression e;
+                               
+                               e = Convert.ImplicitUserConversion (ec, expr, tt, loc);
+                               if (e == null)
+                                       continue;
+
+                               //
+                               // Ignore over-worked ImplicitUserConversions that do
+                               // an implicit conversion in addition to the user conversion.
+                               // 
+                               if (!(e is UserCast))
+                                       continue;
+
+                               if (converted != null){
+                                       Report.ExtraInformation (
+                                               loc,
+                                               String.Format ("reason: more than one conversion to an integral type exist for type {0}",
+                                                              TypeManager.CSharpName (expr.Type)));
+                                       return null;
+                               }
+
+                               converted = e;
+                       }
+                       return converted;
+               }
+
+               //
+               // Performs the basic sanity checks on the switch statement
+               // (looks for duplicate keys and non-constant expressions).
+               //
+               // It also returns a hashtable with the keys that we will later
+               // use to compute the switch tables
+               //
+               bool CheckSwitch (EmitContext ec)
+               {
+                       bool error = false;
+                       Elements = Sections.Count > 10 ? 
+                               (IDictionary)new Hashtable () : 
+                               (IDictionary)new ListDictionary ();
+                               
+                       foreach (SwitchSection ss in Sections){
+                               foreach (SwitchLabel sl in ss.Labels){
+                                       if (sl.Label == null){
+                                               if (default_section != null){
+                                                       sl.Erorr_AlreadyOccurs ();
+                                                       error = true;
+                                               }
+                                               default_section = ss;
+                                               continue;
+                                       }
+
+                                       if (!sl.ResolveAndReduce (ec, SwitchType, HaveUnwrap)) {
+                                               error = true;
+                                               continue;
+                                       }
+                                       
+                                       object key = sl.Converted;
+                                       try {
+                                               Elements.Add (key, sl);
+                                       } catch (ArgumentException) {
+                                               sl.Erorr_AlreadyOccurs ();
+                                               error = true;
+                                       }
+                               }
+                       }
+                       return !error;
+               }
+
+               void EmitObjectInteger (ILGenerator ig, object k)
+               {
+                       if (k is int)
+                               IntConstant.EmitInt (ig, (int) k);
+                       else if (k is Constant) {
+                               EmitObjectInteger (ig, ((Constant) k).GetValue ());
+                       } 
+                       else if (k is uint)
+                               IntConstant.EmitInt (ig, unchecked ((int) (uint) k));
+                       else if (k is long)
+                       {
+                               if ((long) k >= int.MinValue && (long) k <= int.MaxValue)
+                               {
+                                       IntConstant.EmitInt (ig, (int) (long) k);
+                                       ig.Emit (OpCodes.Conv_I8);
+                               }
+                               else
+                                       LongConstant.EmitLong (ig, (long) k);
+                       }
+                       else if (k is ulong)
+                       {
+                               ulong ul = (ulong) k;
+                               if (ul < (1L<<32))
+                               {
+                                       IntConstant.EmitInt (ig, unchecked ((int) ul));
+                                       ig.Emit (OpCodes.Conv_U8);
+                               }
+                               else
+                               {
+                                       LongConstant.EmitLong (ig, unchecked ((long) ul));
+                               }
+                       }
+                       else if (k is char)
+                               IntConstant.EmitInt (ig, (int) ((char) k));
+                       else if (k is sbyte)
+                               IntConstant.EmitInt (ig, (int) ((sbyte) k));
+                       else if (k is byte)
+                               IntConstant.EmitInt (ig, (int) ((byte) k));
+                       else if (k is short)
+                               IntConstant.EmitInt (ig, (int) ((short) k));
+                       else if (k is ushort)
+                               IntConstant.EmitInt (ig, (int) ((ushort) k));
+                       else if (k is bool)
+                               IntConstant.EmitInt (ig, ((bool) k) ? 1 : 0);
+                       else
+                               throw new Exception ("Unhandled case");
+               }
+               
+               // structure used to hold blocks of keys while calculating table switch
+               class KeyBlock : IComparable
+               {
+                       public KeyBlock (long _nFirst)
+                       {
+                               nFirst = nLast = _nFirst;
+                       }
+                       public long nFirst;
+                       public long nLast;
+                       public ArrayList rgKeys = null;
+                       // how many items are in the bucket
+                       public int Size = 1;
+                       public int Length
+                       {
+                               get { return (int) (nLast - nFirst + 1); }
+                       }
+                       public static long TotalLength (KeyBlock kbFirst, KeyBlock kbLast)
+                       {
+                               return kbLast.nLast - kbFirst.nFirst + 1;
+                       }
+                       public int CompareTo (object obj)
+                       {
+                               KeyBlock kb = (KeyBlock) obj;
+                               int nLength = Length;
+                               int nLengthOther = kb.Length;
+                               if (nLengthOther == nLength)
+                                       return (int) (kb.nFirst - nFirst);
+                               return nLength - nLengthOther;
+                       }
+               }
+
+               /// <summary>
+               /// This method emits code for a lookup-based switch statement (non-string)
+               /// Basically it groups the cases into blocks that are at least half full,
+               /// and then spits out individual lookup opcodes for each block.
+               /// It emits the longest blocks first, and short blocks are just
+               /// handled with direct compares.
+               /// </summary>
+               /// <param name="ec"></param>
+               /// <param name="val"></param>
+               /// <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);
+
+                       // 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)));
+
+                       KeyBlock kbCurr;
+                       // 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)
+                       {
+                               ArrayList rgKeyBlocksNew = new ArrayList ();
+                               kbCurr = (KeyBlock) rgKeyBlocks [0];
+                               for (int ikb = 1; ikb < rgKeyBlocks.Count; ikb++)
+                               {
+                                       KeyBlock kb = (KeyBlock) rgKeyBlocks [ikb];
+                                       if ((kbCurr.Size + kb.Size) * 2 >=  KeyBlock.TotalLength (kbCurr, kb))
+                                       {
+                                               // merge blocks
+                                               kbCurr.nLast = kb.nLast;
+                                               kbCurr.Size += kb.Size;
+                                       }
+                                       else
+                                       {
+                                               // start a new block
+                                               rgKeyBlocksNew.Add (kbCurr);
+                                               kbCurr = kb;
+                                       }
+                               }
+                               rgKeyBlocksNew.Add (kbCurr);
+                               if (rgKeyBlocks.Count == rgKeyBlocksNew.Count)
+                                       break;
+                               rgKeyBlocks = rgKeyBlocksNew;
+                       }
+
+                       // initialize the key lists
+                       foreach (KeyBlock kb in rgKeyBlocks)
+                               kb.rgKeys = new ArrayList ();
+
+                       // fill the key lists
+                       int iBlockCurr = 0;
+                       if (rgKeyBlocks.Count > 0) {
+                               kbCurr = (KeyBlock) rgKeyBlocks [0];
+                               foreach (object key in rgKeys)
+                               {
+                                       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);
+                               }
+                       }
+
+                       // sort the blocks so we can tackle the largest ones first
+                       rgKeyBlocks.Sort ();
+
+                       // okay now we can start...
+                       ILGenerator ig = ec.ig;
+                       Label lblEnd = ig.DefineLabel ();       // at the end ;-)
+                       Label lblDefault = ig.DefineLabel ();
+
+                       Type typeKeys = null;
+                       if (rgKeys.Length > 0)
+                               typeKeys = rgKeys [0].GetType ();       // used for conversions
+
+                       Type compare_type;
+                       
+                       if (TypeManager.IsEnumType (SwitchType))
+                               compare_type = TypeManager.EnumToUnderlying (SwitchType);
+                       else
+                               compare_type = SwitchType;
+                       
+                       for (int iBlock = rgKeyBlocks.Count - 1; iBlock >= 0; --iBlock)
+                       {
+                               KeyBlock kb = ((KeyBlock) rgKeyBlocks [iBlock]);
+                               lblDefault = (iBlock == 0) ? DefaultTarget : ig.DefineLabel ();
+                               if (kb.Length <= 2)
+                               {
+                                       foreach (object key in kb.rgKeys)
+                                       {
+                                               ig.Emit (OpCodes.Ldloc, val);
+                                               EmitObjectInteger (ig, key);
+                                               SwitchLabel sl = (SwitchLabel) Elements [key];
+                                               ig.Emit (OpCodes.Beq, sl.GetILLabel (ec));
+                                       }
+                               }
+                               else
+                               {
+                                       // TODO: if all the keys in the block are the same and there are
+                                       //       no gaps/defaults then just use a range-check.
+                                       if (compare_type == TypeManager.int64_type ||
+                                               compare_type == TypeManager.uint64_type)
+                                       {
+                                               // TODO: optimize constant/I4 cases
+
+                                               // 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);
+                                               ig.Emit (OpCodes.Ldloc, val);
+                                               EmitObjectInteger (ig, System.Convert.ChangeType (kb.nLast, typeKeys));
+                                               ig.Emit (OpCodes.Bgt, lblDefault);
+
+                                               // normalize range
+                                               ig.Emit (OpCodes.Ldloc, val);
+                                               if (kb.nFirst != 0)
+                                               {
+                                                       EmitObjectInteger (ig, System.Convert.ChangeType (kb.nFirst, typeKeys));
+                                                       ig.Emit (OpCodes.Sub);
+                                               }
+                                               ig.Emit (OpCodes.Conv_I4);      // assumes < 2^31 labels!
+                                       }
+                                       else
+                                       {
+                                               // normalize range
+                                               ig.Emit (OpCodes.Ldloc, val);
+                                               int nFirst = (int) kb.nFirst;
+                                               if (nFirst > 0)
+                                               {
+                                                       IntConstant.EmitInt (ig, nFirst);
+                                                       ig.Emit (OpCodes.Sub);
+                                               }
+                                               else if (nFirst < 0)
+                                               {
+                                                       IntConstant.EmitInt (ig, -nFirst);
+                                                       ig.Emit (OpCodes.Add);
+                                               }
+                                       }
+
+                                       // first, build the list of labels for the switch
+                                       int iKey = 0;
+                                       int cJumps = kb.Length;
+                                       Label [] rgLabels = new Label [cJumps];
+                                       for (int iJump = 0; iJump < cJumps; iJump++)
+                                       {
+                                               object key = kb.rgKeys [iKey];
+                                               if (System.Convert.ToInt64 (key) == kb.nFirst + iJump)
+                                               {
+                                                       SwitchLabel sl = (SwitchLabel) Elements [key];
+                                                       rgLabels [iJump] = sl.GetILLabel (ec);
+                                                       iKey++;
+                                               }
+                                               else
+                                                       rgLabels [iJump] = lblDefault;
+                                       }
+                                       // emit the switch opcode
+                                       ig.Emit (OpCodes.Switch, rgLabels);
+                               }
+
+                               // mark the default for this block
+                               if (iBlock != 0)
+                                       ig.MarkLabel (lblDefault);
+                       }
+
+                       // TODO: find the default case and emit it here,
+                       //       to prevent having to do the following jump.
+                       //       make sure to mark other labels in the default section
+
+                       // the last default just goes to the end
+                       ig.Emit (OpCodes.Br, lblDefault);
+
+                       // now emit the code for the sections
+                       bool fFoundDefault = false;
+                       bool fFoundNull = false;
+                       foreach (SwitchSection ss in Sections)
+                       {
+                               foreach (SwitchLabel sl in ss.Labels)
+                                       if (sl.Converted == SwitchLabel.NullStringCase)
+                                               fFoundNull = true;
+                       }
+
+                       foreach (SwitchSection ss in Sections)
+                       {
+                               foreach (SwitchLabel sl in ss.Labels)
+                               {
+                                       ig.MarkLabel (sl.GetILLabel (ec));
+                                       ig.MarkLabel (sl.GetILLabelCode (ec));
+                                       if (sl.Converted == SwitchLabel.NullStringCase)
+                                               ig.MarkLabel (null_target);
+                                       else if (sl.Label == null) {
+                                               ig.MarkLabel (lblDefault);
+                                               fFoundDefault = true;
+                                               if (!fFoundNull)
+                                                       ig.MarkLabel (null_target);
+                                       }
+                               }
+                               ss.Block.Emit (ec);
+                       }
+                       
+                       if (!fFoundDefault) {
+                               ig.MarkLabel (lblDefault);
+                       }
+                       ig.MarkLabel (lblEnd);
+               }
+               //
+               // This simple emit switch works, but does not take advantage of the
+               // `switch' opcode. 
+               // TODO: remove non-string logic from here
+               // TODO: binary search strings?
+               //
+               void SimpleSwitchEmit (EmitContext ec, LocalBuilder val)
+               {
+                       ILGenerator ig = ec.ig;
+                       Label end_of_switch = ig.DefineLabel ();
+                       Label next_test = ig.DefineLabel ();
+                       bool first_test = true;
+                       bool pending_goto_end = false;
+                       bool null_marked = false;
+                       bool null_found;
+
+                       ig.Emit (OpCodes.Ldloc, val);
+                       
+                       if (Elements.Contains (SwitchLabel.NullStringCase)){
+                               ig.Emit (OpCodes.Brfalse, null_target);
+                       } else
+                               ig.Emit (OpCodes.Brfalse, default_target);
+                       
+                       ig.Emit (OpCodes.Ldloc, val);
+                       ig.Emit (OpCodes.Call, TypeManager.string_isinterneted_string);
+                       ig.Emit (OpCodes.Stloc, val);
+
+                       int section_count = Sections.Count;
+                       for (int section = 0; section < section_count; section++){
+                               SwitchSection ss = (SwitchSection) Sections [section];
+
+                               if (ss == default_section)
+                                       continue;
+
+                               Label sec_begin = ig.DefineLabel ();
+
+                               ig.Emit (OpCodes.Nop);
+
+                               if (pending_goto_end)
+                                       ig.Emit (OpCodes.Br, end_of_switch);
+
+                               int label_count = ss.Labels.Count;
+                               null_found = false;
+                               for (int label = 0; label < label_count; label++){
+                                       SwitchLabel sl = (SwitchLabel) ss.Labels [label];
+                                       ig.MarkLabel (sl.GetILLabel (ec));
+                                       
+                                       if (!first_test){
+                                               ig.MarkLabel (next_test);
+                                               next_test = ig.DefineLabel ();
+                                       }
+                                       //
+                                       // If we are the default target
+                                       //
+                                       if (sl.Label != null){
+                                               object lit = sl.Converted;
+
+                                               if (lit == SwitchLabel.NullStringCase){
+                                                       null_found = true;
+                                                       if (label + 1 == label_count)
+                                                               ig.Emit (OpCodes.Br, next_test);
+                                                       continue;
+                                               }
+                                               
+                                               ig.Emit (OpCodes.Ldloc, val);
+                                               ig.Emit (OpCodes.Ldstr, (string)lit);
+                                               if (label_count == 1)
+                                                       ig.Emit (OpCodes.Bne_Un, next_test);
+                                               else {
+                                                       if (label+1 == label_count)
+                                                               ig.Emit (OpCodes.Bne_Un, next_test);
+                                                       else
+                                                               ig.Emit (OpCodes.Beq, sec_begin);
+                                               }
+                                       }
+                               }
+                               if (null_found) {
+                                       ig.MarkLabel (null_target);
+                                       null_marked = true;
+                               }
+                               ig.MarkLabel (sec_begin);
+                               foreach (SwitchLabel sl in ss.Labels)
+                                       ig.MarkLabel (sl.GetILLabelCode (ec));
+
+                               ss.Block.Emit (ec);
+                               pending_goto_end = !ss.Block.HasRet;
+                               first_test = false;
+                       }
+                       ig.MarkLabel (next_test);
+                       ig.MarkLabel (default_target);
+                       if (!null_marked)
+                               ig.MarkLabel (null_target);
+                       if (default_section != null)
+                               default_section.Block.Emit (ec);
+                       ig.MarkLabel (end_of_switch);
+               }
+
+               SwitchSection FindSection (SwitchLabel label)
+               {
+                       foreach (SwitchSection ss in Sections){
+                               foreach (SwitchLabel sl in ss.Labels){
+                                       if (label == sl)
+                                               return ss;
+                               }
+                       }
+
+                       return null;
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       Expr = Expr.Resolve (ec);
+                       if (Expr == null)
+                               return false;
+
+                       new_expr = SwitchGoverningType (ec, Expr);
+
+#if GMCS_SOURCE
+                       if ((new_expr == null) && TypeManager.IsNullableType (Expr.Type)) {
+                               unwrap = Nullable.Unwrap.Create (Expr, ec);
+                               if (unwrap == null)
+                                       return false;
+
+                               new_expr = SwitchGoverningType (ec, unwrap);
+                       }
+#endif
+
+                       if (new_expr == null){
+                               Report.Error (151, loc, "A value of an integral type or string expected for switch");
+                               return false;
+                       }
+
+                       // Validate switch.
+                       SwitchType = new_expr.Type;
+
+                       if (!CheckSwitch (ec))
+                               return false;
+
+                       if (HaveUnwrap)
+                               Elements.Remove (SwitchLabel.NullStringCase);
+
+                       Switch old_switch = ec.Switch;
+                       ec.Switch = this;
+                       ec.Switch.SwitchType = SwitchType;
+
+                       Report.Debug (1, "START OF SWITCH BLOCK", loc, ec.CurrentBranching);
+                       ec.StartFlowBranching (FlowBranching.BranchingType.Switch, loc);
+
+                       is_constant = new_expr is Constant;
+                       if (is_constant) {
+                               object key = ((Constant) new_expr).GetValue ();
+                               SwitchLabel label = (SwitchLabel) Elements [key];
+
+                               constant_section = FindSection (label);
+                               if (constant_section == null)
+                                       constant_section = default_section;
+                       }
+
+                       bool first = true;
+                       foreach (SwitchSection ss in Sections){
+                               if (!first)
+                                       ec.CurrentBranching.CreateSibling (
+                                               null, FlowBranching.SiblingType.SwitchSection);
+                               else
+                                       first = false;
+
+                               if (is_constant && (ss != constant_section)) {
+                                       // If we're a constant switch, we're only emitting
+                                       // one single section - mark all the others as
+                                       // unreachable.
+                                       ec.CurrentBranching.CurrentUsageVector.Goto ();
+                                       if (!ss.Block.ResolveUnreachable (ec, true))
+                                               return false;
+                               } else {
+                                       if (!ss.Block.Resolve (ec))
+                                               return false;
+                               }
+                       }
+
+                       if (default_section == null)
+                               ec.CurrentBranching.CreateSibling (
+                                       null, FlowBranching.SiblingType.SwitchSection);
+
+                       FlowBranching.Reachability reachability = ec.EndFlowBranching ();
+                       ec.Switch = old_switch;
+
+                       Report.Debug (1, "END OF SWITCH BLOCK", loc, ec.CurrentBranching,
+                                     reachability);
+
+                       return true;
+               }
+               
+               protected override void DoEmit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+
+                       default_target = ig.DefineLabel ();
+                       null_target = ig.DefineLabel ();
+
+                       // Store variable for comparission purposes
+                       LocalBuilder value;
+                       if (HaveUnwrap) {
+                               value = ig.DeclareLocal (SwitchType);
+#if GMCS_SOURCE
+                               unwrap.EmitCheck (ec);
+                               ig.Emit (OpCodes.Brfalse, null_target);
+                               new_expr.Emit (ec);
+                               ig.Emit (OpCodes.Stloc, value);
+#endif
+                       } else if (!is_constant) {
+                               value = ig.DeclareLocal (SwitchType);
+                               new_expr.Emit (ec);
+                               ig.Emit (OpCodes.Stloc, value);
+                       } else
+                               value = null;
+
+                       //
+                       // Setup the codegen context
+                       //
+                       Label old_end = ec.LoopEnd;
+                       Switch old_switch = ec.Switch;
+                       
+                       ec.LoopEnd = ig.DefineLabel ();
+                       ec.Switch = this;
+
+                       // Emit Code.
+                       if (is_constant) {
+                               if (constant_section != null)
+                                       constant_section.Block.Emit (ec);
+                       } else if (SwitchType == TypeManager.string_type)
+                               SimpleSwitchEmit (ec, value);
+                       else
+                               TableSwitchEmit (ec, value);
+
+                       // Restore context state. 
+                       ig.MarkLabel (ec.LoopEnd);
+
+                       //
+                       // Restore the previous context
+                       //
+                       ec.LoopEnd = old_end;
+                       ec.Switch = old_switch;
+               }
+       }
+
+       public abstract class ExceptionStatement : Statement
+       {
+               public abstract void EmitFinally (EmitContext ec);
+
+               protected bool emit_finally = true;
+               ArrayList parent_vectors;
+
+               protected void DoEmitFinally (EmitContext ec)
+               {
+                       if (emit_finally)
+                               ec.ig.BeginFinallyBlock ();
+                       else if (ec.InIterator)
+                               ec.CurrentIterator.MarkFinally (ec, parent_vectors);
+                       EmitFinally (ec);
+               }
+
+               protected void ResolveFinally (FlowBranchingException branching)
+               {
+                       emit_finally = branching.EmitFinally;
+                       if (!emit_finally)
+                               branching.Parent.StealFinallyClauses (ref parent_vectors);
+               }
+       }
+
+       public class Lock : ExceptionStatement {
+               Expression expr;
+               public Statement Statement;
+               TemporaryVariable temp;
+                       
+               public Lock (Expression expr, Statement stmt, Location l)
+               {
+                       this.expr = expr;
+                       Statement = stmt;
+                       loc = l;
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       expr = expr.Resolve (ec);
+                       if (expr == null)
+                               return false;
+
+                       if (expr.Type.IsValueType){
+                               Report.Error (185, loc,
+                                             "`{0}' is not a reference type as required by the lock statement",
+                                             TypeManager.CSharpName (expr.Type));
+                               return false;
+                       }
+
+                       FlowBranchingException branching = ec.StartFlowBranching (this);
+                       bool ok = Statement.Resolve (ec);
+                       if (!ok) {
+                               ec.KillFlowBranching ();
+                               return false;
+                       }
+
+                       ResolveFinally (branching);
+
+                       FlowBranching.Reachability reachability = ec.EndFlowBranching ();
+                       if (!reachability.AlwaysReturns) {
+                               // Unfortunately, System.Reflection.Emit automatically emits
+                               // a leave to the end of the finally block.
+                               // This is a problem if `returns' is true since we may jump
+                               // to a point after the end of the method.
+                               // As a workaround, emit an explicit ret here.
+                               ec.NeedReturnLabel ();
+                       }
+
+                       // Avoid creating libraries that reference the internal
+                       // mcs NullType:
+                       Type t = expr.Type;
+                       if (t == TypeManager.null_type)
+                               t = TypeManager.object_type;
+                       
+                       temp = new TemporaryVariable (t, loc);
+                       temp.Resolve (ec);
+                       
+                       return true;
+               }
+               
+               protected override void DoEmit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+
+                       temp.Store (ec, expr);
+                       temp.Emit (ec);
+                       ig.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
+
+                       // try
+                       if (emit_finally)
+                               ig.BeginExceptionBlock ();
+                       Statement.Emit (ec);
+                       
+                       // finally
+                       DoEmitFinally (ec);
+                       if (emit_finally)
+                               ig.EndExceptionBlock ();
+               }
+
+               public override void EmitFinally (EmitContext ec)
+               {
+                       temp.Emit (ec);
+                       ec.ig.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object);
+               }
+       }
+
+       public class Unchecked : Statement {
+               public readonly Block Block;
+               
+               public Unchecked (Block b)
+               {
+                       Block = b;
+                       b.Unchecked = true;
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
+                               return Block.Resolve (ec);
+               }
+               
+               protected override void DoEmit (EmitContext ec)
+               {
+                       using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
+                               Block.Emit (ec);
+               }
+       }
+
+       public class Checked : Statement {
+               public readonly Block Block;
+               
+               public Checked (Block b)
+               {
+                       Block = b;
+                       b.Unchecked = false;
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
+                               return Block.Resolve (ec);
+               }
+
+               protected override void DoEmit (EmitContext ec)
+               {
+                       using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
+                               Block.Emit (ec);
+               }
+       }
+
+       public class Unsafe : Statement {
+               public readonly Block Block;
+
+               public Unsafe (Block b)
+               {
+                       Block = b;
+                       Block.Unsafe = true;
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       using (ec.With (EmitContext.Flags.InUnsafe, true))
+                               return Block.Resolve (ec);
+               }
+               
+               protected override void DoEmit (EmitContext ec)
+               {
+                       using (ec.With (EmitContext.Flags.InUnsafe, true))
+                               Block.Emit (ec);
+               }
+       }
+
+       // 
+       // Fixed statement
+       //
+       public class Fixed : Statement {
+               Expression type;
+               ArrayList declarators;
+               Statement statement;
+               Type expr_type;
+               Emitter[] data;
+               bool has_ret;
+
+               abstract class Emitter
+               {
+                       protected LocalInfo vi;
+                       protected Expression converted;
+
+                       protected Emitter (Expression expr, LocalInfo li)
+                       {
+                               converted = expr;
+                               vi = li;
+                       }
+
+                       public abstract void Emit (EmitContext ec);
+                       public abstract void EmitExit (EmitContext ec);
+               }
+
+               class ExpressionEmitter : Emitter {
+                       public ExpressionEmitter (Expression converted, LocalInfo li) :
+                               base (converted, li)
+                       {
+                       }
+
+                       public override void Emit (EmitContext ec) {
+                               //
+                               // Store pointer in pinned location
+                               //
+                               converted.Emit (ec);
+                               vi.Variable.EmitAssign (ec);
+                       }
+
+                       public override void EmitExit (EmitContext ec)
+                       {
+                               ec.ig.Emit (OpCodes.Ldc_I4_0);
+                               ec.ig.Emit (OpCodes.Conv_U);
+                               vi.Variable.EmitAssign (ec);
+                       }
+               }
+
+               class StringEmitter : Emitter {
+                       LocalBuilder pinned_string;
+                       Location loc;
+
+                       public StringEmitter (Expression expr, LocalInfo li, Location loc):
+                               base (expr, li)
+                       {
+                               this.loc = loc;
+                       }
+
+                       public override void Emit (EmitContext ec)
+                       {
+                               ILGenerator ig = ec.ig;
+                               pinned_string = TypeManager.DeclareLocalPinned (ig, TypeManager.string_type);
+                                       
+                               converted.Emit (ec);
+                               ig.Emit (OpCodes.Stloc, pinned_string);
+
+                               Expression sptr = new StringPtr (pinned_string, loc);
+                               converted = Convert.ImplicitConversionRequired (
+                                       ec, sptr, vi.VariableType, loc);
+                                       
+                               if (converted == null)
+                                       return;
+
+                               converted.Emit (ec);
+                               vi.Variable.EmitAssign (ec);
+                       }
+
+                       public override void EmitExit (EmitContext ec)
+                       {
+                               ec.ig.Emit (OpCodes.Ldnull);
+                               ec.ig.Emit (OpCodes.Stloc, pinned_string);
+                       }
+               }
+
+               public Fixed (Expression type, ArrayList decls, Statement stmt, Location l)
+               {
+                       this.type = type;
+                       declarators = decls;
+                       statement = stmt;
+                       loc = l;
+               }
+
+               public Statement Statement {
+                       get { return statement; }
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       if (!ec.InUnsafe){
+                               Expression.UnsafeError (loc);
+                               return false;
+                       }
+                       
+                       TypeExpr texpr = type.ResolveAsTypeTerminal (ec, false);
+                       if (texpr == null)
+                               return false;
+
+                       expr_type = texpr.Type;
+
+                       data = new Emitter [declarators.Count];
+
+                       if (!expr_type.IsPointer){
+                               Report.Error (209, loc, "The type of locals declared in a fixed statement must be a pointer type");
+                               return false;
+                       }
+                       
+                       int i = 0;
+                       foreach (Pair p in declarators){
+                               LocalInfo vi = (LocalInfo) p.First;
+                               Expression e = (Expression) p.Second;
+
+                               vi.VariableInfo.SetAssigned (ec);
+                               vi.SetReadOnlyContext (LocalInfo.ReadOnlyContext.Fixed);
+
+                               //
+                               // The rules for the possible declarators are pretty wise,
+                               // but the production on the grammar is more concise.
+                               //
+                               // So we have to enforce these rules here.
+                               //
+                               // We do not resolve before doing the case 1 test,
+                               // because the grammar is explicit in that the token &
+                               // is present, so we need to test for this particular case.
+                               //
+
+                               if (e is Cast){
+                                       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 (e.Location, expr_type, false);
+                                               return false;
+                                       }
+
+                                       data [i] = new ExpressionEmitter (e, vi);
+                                       i++;
+
+                                       continue;
+                               }
+
+                               ec.InFixedInitializer = true;
+                               e = e.Resolve (ec);
+                               ec.InFixedInitializer = false;
+                               if (e == null)
+                                       return false;
+
+                               //
+                               // Case 2: Array
+                               //
+                               if (e.Type.IsArray){
+                                       Type array_type = TypeManager.GetElementType (e.Type);
+                                       
+                                       //
+                                       // Provided that array_type is unmanaged,
+                                       //
+                                       if (!TypeManager.VerifyUnManaged (array_type, loc))
+                                               return false;
+
+                                       //
+                                       // and T* is implicitly convertible to the
+                                       // pointer type given in the fixed statement.
+                                       //
+                                       ArrayPtr array_ptr = new ArrayPtr (e, array_type, loc);
+                                       
+                                       Expression converted = Convert.ImplicitConversionRequired (
+                                               ec, array_ptr, vi.VariableType, loc);
+                                       if (converted == null)
+                                               return false;
+
+                                       data [i] = new ExpressionEmitter (converted, vi);
+                                       i++;
+
+                                       continue;
+                               }
+
+                               //
+                               // Case 3: string
+                               //
+                               if (e.Type == TypeManager.string_type){
+                                       data [i] = new StringEmitter (e, vi, loc);
+                                       i++;
+                                       continue;
+                               }
+
+                               // 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;
+                                       }
+                               }
+
+                               //
+                               // For other cases, flag a `this is already fixed expression'
+                               //
+                               if (e is LocalVariableReference || e is ParameterReference ||
+                                   Convert.ImplicitConversionExists (ec, e, vi.VariableType)){
+                                   
+                                       Report.Error (245, loc, "right hand expression is already fixed, no need to use fixed statement ");
+                                       return false;
+                               }
+
+                               Report.Error (245, loc, "Fixed statement only allowed on strings, arrays or address-of expressions");
+                               return false;
+                       }
+
+                       ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
+
+                       if (!statement.Resolve (ec)) {
+                               ec.KillFlowBranching ();
+                               return false;
+                       }
+
+                       FlowBranching.Reachability reachability = ec.EndFlowBranching ();
+                       has_ret = reachability.IsUnreachable;
+
+                       return true;
+               }
+               
+               protected override void DoEmit (EmitContext ec)
+               {
+                       for (int i = 0; i < data.Length; i++) {
+                               data [i].Emit (ec);
+                       }
+
+                       statement.Emit (ec);
+
+                       if (has_ret)
+                               return;
+
+                       //
+                       // Clear the pinned variable
+                       //
+                       for (int i = 0; i < data.Length; i++) {
+                               data [i].EmitExit (ec);
+                       }
+               }
+       }
+       
+       public class Catch : Statement {
+               public readonly string Name;
+               public readonly Block  Block;
+               public readonly Block  VarBlock;
+
+               Expression type_expr;
+               Type type;
+               
+               public Catch (Expression type, string name, Block block, Block var_block, Location l)
+               {
+                       type_expr = type;
+                       Name = name;
+                       Block = block;
+                       VarBlock = var_block;
+                       loc = l;
+               }
+
+               public Type CatchType {
+                       get {
+                               return type;
+                       }
+               }
+
+               public bool IsGeneral {
+                       get {
+                               return type_expr == null;
+                       }
+               }
+
+               protected override void DoEmit(EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+
+                       if (CatchType != null)
+                               ig.BeginCatchBlock (CatchType);
+                       else
+                               ig.BeginCatchBlock (TypeManager.object_type);
+
+                       if (VarBlock != null)
+                               VarBlock.Emit (ec);
+
+                       if (Name != null) {
+                               LocalInfo vi = Block.GetLocalInfo (Name);
+                               if (vi == null)
+                                       throw new Exception ("Variable does not exist in this block");
+
+                               if (vi.Variable.NeedsTemporary) {
+                                       LocalBuilder e = ig.DeclareLocal (vi.VariableType);
+                                       ig.Emit (OpCodes.Stloc, e);
+
+                                       vi.Variable.EmitInstance (ec);
+                                       ig.Emit (OpCodes.Ldloc, e);
+                                       vi.Variable.EmitAssign (ec);
+                               } else
+                                       vi.Variable.EmitAssign (ec);
+                       } else
+                               ig.Emit (OpCodes.Pop);
+
+                       Block.Emit (ec);
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       using (ec.With (EmitContext.Flags.InCatch, true)) {
+                               if (type_expr != null) {
+                                       TypeExpr te = type_expr.ResolveAsTypeTerminal (ec, false);
+                                       if (te == null)
+                                               return false;
+
+                                       type = te.Type;
+
+                                       if (type != TypeManager.exception_type && !type.IsSubclassOf (TypeManager.exception_type)){
+                                               Error (155, "The type caught or thrown must be derived from System.Exception");
+                                               return false;
+                                       }
+                               } else
+                                       type = null;
+
+                               if (!Block.Resolve (ec))
+                                       return false;
+
+                               // Even though VarBlock surrounds 'Block' we resolve it later, so that we can correctly
+                               // emit the "unused variable" warnings.
+                               if (VarBlock != null)
+                                       return VarBlock.Resolve (ec);
+
+                               return true;
+                       }
+               }
+       }
+
+       public class Try : ExceptionStatement {
+               public readonly Block Fini, Block;
+               public readonly ArrayList Specific;
+               public readonly Catch General;
+
+               bool need_exc_block;
+               
+               //
+               // specific, general and fini might all be null.
+               //
+               public Try (Block block, ArrayList specific, Catch general, Block fini, Location l)
+               {
+                       if (specific == null && general == null){
+                               Console.WriteLine ("CIR.Try: Either specific or general have to be non-null");
+                       }
+                       
+                       this.Block = block;
+                       this.Specific = specific;
+                       this.General = general;
+                       this.Fini = fini;
+                       loc = l;
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       bool ok = true;
+                       
+                       FlowBranchingException branching = ec.StartFlowBranching (this);
+
+                       Report.Debug (1, "START OF TRY BLOCK", Block.StartLocation);
+
+                       if (!Block.Resolve (ec))
+                               ok = false;
+
+                       FlowBranching.UsageVector vector = ec.CurrentBranching.CurrentUsageVector;
+
+                       Report.Debug (1, "START OF CATCH BLOCKS", vector);
+
+                       Type[] prevCatches = new Type [Specific.Count];
+                       int last_index = 0;
+                       foreach (Catch c in Specific){
+                               ec.CurrentBranching.CreateSibling (
+                                       c.Block, FlowBranching.SiblingType.Catch);
+
+                               Report.Debug (1, "STARTED SIBLING FOR CATCH", ec.CurrentBranching);
+
+                               if (c.Name != null) {
+                                       LocalInfo vi = c.Block.GetLocalInfo (c.Name);
+                                       if (vi == null)
+                                               throw new Exception ();
+
+                                       vi.VariableInfo = null;
+                               }
+
+                               if (!c.Resolve (ec))
+                                       return false;
+
+                               Type resolvedType = 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);
+                                               return false;
+                                       }
+                               }
+
+                               prevCatches [last_index++] = resolvedType;
+                               need_exc_block = true;
+                       }
+
+                       Report.Debug (1, "END OF CATCH BLOCKS", ec.CurrentBranching);
+
+                       if (General != null){
+                               if (CodeGen.Assembly.WrapNonExceptionThrows) {
+                                       foreach (Catch c in Specific){
+                                               if (c.CatchType == TypeManager.exception_type) {
+                                                       Report.Warning (1058, 1, c.loc, "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'");
+                                               }
+                                       }
+                               }
+
+                               ec.CurrentBranching.CreateSibling (
+                                       General.Block, FlowBranching.SiblingType.Catch);
+
+                               Report.Debug (1, "STARTED SIBLING FOR GENERAL", ec.CurrentBranching);
+
+                               if (!General.Resolve (ec))
+                                       ok = false;
+
+                               need_exc_block = true;
+                       }
+
+                       Report.Debug (1, "END OF GENERAL CATCH BLOCKS", ec.CurrentBranching);
+
+                       if (Fini != null) {
+                               if (ok)
+                                       ec.CurrentBranching.CreateSibling (Fini, FlowBranching.SiblingType.Finally);
+
+                               Report.Debug (1, "STARTED SIBLING FOR FINALLY", ec.CurrentBranching, vector);
+                               using (ec.With (EmitContext.Flags.InFinally, true)) {
+                                       if (!Fini.Resolve (ec))
+                                               ok = false;
+                               }
+
+                               if (!ec.InIterator)
+                                       need_exc_block = true;
+                       }
+
+                       if (ec.InIterator) {
+                               ResolveFinally (branching);
+                               need_exc_block |= emit_finally;
+                       } else
+                               emit_finally = Fini != null;
+
+                       FlowBranching.Reachability reachability = ec.EndFlowBranching ();
+
+                       FlowBranching.UsageVector f_vector = ec.CurrentBranching.CurrentUsageVector;
+
+                       Report.Debug (1, "END OF TRY", ec.CurrentBranching, reachability, vector, f_vector);
+
+                       if (!reachability.AlwaysReturns) {
+                               // Unfortunately, System.Reflection.Emit automatically emits
+                               // a leave to the end of the finally block.  This is a problem
+                               // if `returns' is true since we may jump to a point after the
+                               // end of the method.
+                               // As a workaround, emit an explicit ret here.
+                               ec.NeedReturnLabel ();
+                       }
+
+                       return ok;
+               }
+               
+               protected override void DoEmit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+
+                       if (need_exc_block)
+                               ig.BeginExceptionBlock ();
+                       Block.Emit (ec);
+
+                       foreach (Catch c in Specific)
+                               c.Emit (ec);
+
+                       if (General != null)
+                               General.Emit (ec);
+
+                       DoEmitFinally (ec);
+                       if (need_exc_block)
+                               ig.EndExceptionBlock ();
+               }
+
+               public override void EmitFinally (EmitContext ec)
+               {
+                       if (Fini != null)
+                               Fini.Emit (ec);
+               }
+
+               public bool HasCatch
+               {
+                       get {
+                               return General != null || Specific.Count > 0;
+                       }
+               }
+       }
+
+       public class Using : ExceptionStatement {
+               object expression_or_block;
+               public Statement Statement;
+               ArrayList var_list;
+               Expression expr;
+               Type expr_type;
+               Expression [] resolved_vars;
+               Expression [] converted_vars;
+               ExpressionStatement [] assign;
+               TemporaryVariable local_copy;
+               
+               public Using (object expression_or_block, Statement stmt, Location l)
+               {
+                       this.expression_or_block = expression_or_block;
+                       Statement = stmt;
+                       loc = l;
+               }
+
+               //
+               // Resolves for the case of using using a local variable declaration.
+               //
+               bool ResolveLocalVariableDecls (EmitContext ec)
+               {
+                       int i = 0;
+
+                       TypeExpr 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];
+
+                       bool need_conv = !TypeManager.ImplementsInterface (
+                               expr_type, TypeManager.idisposable_type);
+
+                       foreach (DictionaryEntry e in var_list){
+                               Expression var = (Expression) e.Key;
+
+                               var = var.ResolveLValue (ec, new EmptyExpression (), loc);
+                               if (var == null)
+                                       return false;
+
+                               resolved_vars [i] = var;
+
+                               if (!need_conv) {
+                                       i++;
+                                       continue;
+                               }
+
+                               converted_vars [i] = Convert.ImplicitConversion (
+                                       ec, var, TypeManager.idisposable_type, loc);
+
+                               if (converted_vars [i] == null) {
+                                       Error_IsNotConvertibleToIDisposable ();
+                                       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++;
+                       }
+
+                       return true;
+               }
+
+               void Error_IsNotConvertibleToIDisposable ()
+               {
+                       Report.Error (1674, loc, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
+                               TypeManager.CSharpName (expr_type));
+               }
+
+               bool ResolveExpression (EmitContext ec)
+               {
+                       if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)){
+                               if (Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) {
+                                       Error_IsNotConvertibleToIDisposable ();
+                                       return false;
+                               }
+                       }
+
+                       local_copy = new TemporaryVariable (expr_type, loc);
+                       local_copy.Resolve (ec);
+
+                       return true;
+               }
+               
+               //
+               // Emits the code for the case of using using a local variable declaration.
+               //
+               void EmitLocalVariableDecls (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+                       int i = 0;
+
+                       for (i = 0; i < assign.Length; i++) {
+                               assign [i].EmitStatement (ec);
+
+                               if (emit_finally)
+                                       ig.BeginExceptionBlock ();
+                       }
+                       Statement.Emit (ec);
+
+                       var_list.Reverse ();
+
+                       DoEmitFinally (ec);
+               }
+
+               void EmitLocalVariableDeclFinally (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+
+                       int i = assign.Length;
+                       for (int ii = 0; ii < var_list.Count; ++ii){
+                               Expression var = resolved_vars [--i];
+                               Label skip = ig.DefineLabel ();
+
+                               if (emit_finally)
+                                       ig.BeginFinallyBlock ();
+                               
+                               if (!var.Type.IsValueType) {
+                                       var.Emit (ec);
+                                       ig.Emit (OpCodes.Brfalse, skip);
+                                       converted_vars [i].Emit (ec);
+                                       ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
+                               } else {
+                                       Expression ml = Expression.MemberLookup(ec.ContainerType, TypeManager.idisposable_type, var.Type, "Dispose", Mono.CSharp.Location.Null);
+
+                                       if (!(ml is MethodGroupExpr)) {
+                                               var.Emit (ec);
+                                               ig.Emit (OpCodes.Box, var.Type);
+                                               ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
+                                       } else {
+                                               MethodInfo mi = null;
+
+                                               foreach (MethodInfo mk in ((MethodGroupExpr) ml).Methods) {
+                                                       if (TypeManager.GetParameterData (mk).Count == 0) {
+                                                               mi = mk;
+                                                               break;
+                                                       }
+                                               }
+
+                                               if (mi == null) {
+                                                       Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters.");
+                                                       return;
+                                               }
+
+                                               IMemoryLocation mloc = (IMemoryLocation) var;
+
+                                               mloc.AddressOf (ec, AddressOp.Load);
+                                               ig.Emit (OpCodes.Call, mi);
+                                       }
+                               }
+
+                               ig.MarkLabel (skip);
+
+                               if (emit_finally) {
+                                       ig.EndExceptionBlock ();
+                                       if (i > 0)
+                                               ig.BeginFinallyBlock ();
+                               }
+                       }
+               }
+
+               void EmitExpression (EmitContext ec)
+               {
+                       //
+                       // Make a copy of the expression and operate on that.
+                       //
+                       ILGenerator ig = ec.ig;
+
+                       local_copy.Store (ec, expr);
+
+                       if (emit_finally)
+                               ig.BeginExceptionBlock ();
+
+                       Statement.Emit (ec);
+                       
+                       DoEmitFinally (ec);
+                       if (emit_finally)
+                               ig.EndExceptionBlock ();
+               }
+
+               void EmitExpressionFinally (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+                       if (!expr_type.IsValueType) {
+                               Label skip = ig.DefineLabel ();
+                               local_copy.Emit (ec);
+                               ig.Emit (OpCodes.Brfalse, skip);
+                               local_copy.Emit (ec);
+                               ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
+                               ig.MarkLabel (skip);
+                       } else {
+                               Expression ml = Expression.MemberLookup (
+                                       ec.ContainerType, TypeManager.idisposable_type, expr_type,
+                                       "Dispose", Location.Null);
+
+                               if (!(ml is MethodGroupExpr)) {
+                                       local_copy.Emit (ec);
+                                       ig.Emit (OpCodes.Box, expr_type);
+                                       ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
+                               } else {
+                                       MethodInfo mi = null;
+
+                                       foreach (MethodInfo mk in ((MethodGroupExpr) ml).Methods) {
+                                               if (TypeManager.GetParameterData (mk).Count == 0) {
+                                                       mi = mk;
+                                                       break;
+                                               }
+                                       }
+
+                                       if (mi == null) {
+                                               Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters.");
+                                               return;
+                                       }
+
+                                       local_copy.AddressOf (ec, AddressOp.Load);
+                                       ig.Emit (OpCodes.Call, mi);
+                               }
+                       }
+               }
+               
+               public override bool Resolve (EmitContext ec)
+               {
+                       if (expression_or_block is DictionaryEntry){
+                               expr = (Expression) ((DictionaryEntry) expression_or_block).Key;
+                               var_list = (ArrayList)((DictionaryEntry)expression_or_block).Value;
+
+                               if (!ResolveLocalVariableDecls (ec))
+                                       return false;
+
+                       } else if (expression_or_block is Expression){
+                               expr = (Expression) expression_or_block;
+
+                               expr = expr.Resolve (ec);
+                               if (expr == null)
+                                       return false;
+
+                               expr_type = expr.Type;
+
+                               if (!ResolveExpression (ec))
+                                       return false;
+                       }
+
+                       FlowBranchingException branching = ec.StartFlowBranching (this);
+
+                       bool ok = Statement.Resolve (ec);
+
+                       if (!ok) {
+                               ec.KillFlowBranching ();
+                               return false;
+                       }
+
+                       ResolveFinally (branching);
+                       FlowBranching.Reachability reachability = ec.EndFlowBranching ();
+
+                       if (!reachability.AlwaysReturns) {
+                               // Unfortunately, System.Reflection.Emit automatically emits a leave
+                               // to the end of the finally block.  This is a problem if `returns'
+                               // is true since we may jump to a point after the end of the method.
+                               // As a workaround, emit an explicit ret here.
+                               ec.NeedReturnLabel ();
+                       }
+
+                       return true;
+               }
+               
+               protected override void DoEmit (EmitContext ec)
+               {
+                       if (expression_or_block is DictionaryEntry)
+                               EmitLocalVariableDecls (ec);
+                       else if (expression_or_block is Expression)
+                               EmitExpression (ec);
+               }
+
+               public override void EmitFinally (EmitContext ec)
+               {
+                       if (expression_or_block is DictionaryEntry)
+                               EmitLocalVariableDeclFinally (ec);
+                       else if (expression_or_block is Expression)
+                               EmitExpressionFinally (ec);
+               }
+       }
+
+       /// <summary>
+       ///   Implementation of the foreach C# statement
+       /// </summary>
+       public class Foreach : Statement {
+               Expression type;
+               Expression variable;
+               Expression expr;
+               Statement statement;
+               ArrayForeach array;
+               CollectionForeach collection;
+               
+               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;
+
+                       Constant c = expr as Constant;
+                       if (c != null && c.GetValue () == null) {
+                               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);
+                               return false;
+                       }
+
+                       //
+                       // We need an instance variable.  Not sure this is the best
+                       // way of doing this.
+                       //
+                       // FIXME: When we implement propertyaccess, will those turn
+                       // out to return values in ExprClass?  I think they should.
+                       //
+                       if (!(expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.Value ||
+                             expr.eclass == ExprClass.PropertyAccess || expr.eclass == ExprClass.IndexerAccess)){
+                               collection.Error_Enumerator ();
+                               return false;
+                       }
+
+                       if (expr.Type.IsArray) {
+                               array = new ArrayForeach (var_type, variable, expr, statement, loc);
+                               return array.Resolve (ec);
+                       } else {
+                               collection = new CollectionForeach (
+                                       var_type, variable, expr, statement, loc);
+                               return collection.Resolve (ec);
+                       }
+               }
+
+               protected override void DoEmit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+                       
+                       Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
+                       ec.LoopBegin = ig.DefineLabel ();
+                       ec.LoopEnd = ig.DefineLabel ();
+
+                       if (collection != null)
+                               collection.Emit (ec);
+                       else
+                               array.Emit (ec);
+                       
+                       ec.LoopBegin = old_begin;
+                       ec.LoopEnd = old_end;
+               }
+
+               protected class ArrayCounter : TemporaryVariable
+               {
+                       public ArrayCounter (Location loc)
+                               : base (TypeManager.int32_type, loc)
+                       { }
+
+                       public void Initialize (EmitContext ec)
+                       {
+                               EmitThis (ec);
+                               ec.ig.Emit (OpCodes.Ldc_I4_0);
+                               EmitStore (ec);
+                       }
+
+                       public void Increment (EmitContext ec)
+                       {
+                               EmitThis (ec);
+                               Emit (ec);
+                               ec.ig.Emit (OpCodes.Ldc_I4_1);
+                               ec.ig.Emit (OpCodes.Add);
+                               EmitStore (ec);
+                       }
+               }
+
+               protected class ArrayForeach : Statement
+               {
+                       Expression variable, expr, conv;
+                       Statement statement;
+                       Type array_type;
+                       Type var_type;
+                       TemporaryVariable[] lengths;
+                       ArrayCounter[] counter;
+                       int rank;
+
+                       TemporaryVariable copy;
+                       Expression access;
+
+                       public ArrayForeach (Type var_type, Expression var,
+                                            Expression expr, Statement stmt, Location l)
+                       {
+                               this.var_type = var_type;
+                               this.variable = var;
+                               this.expr = expr;
+                               statement = stmt;
+                               loc = l;
+                       }
+
+                       public override bool Resolve (EmitContext ec)
+                       {
+                               array_type = expr.Type;
+                               rank = array_type.GetArrayRank ();
+
+                               copy = new TemporaryVariable (array_type, loc);
+                               copy.Resolve (ec);
+
+                               counter = new ArrayCounter [rank];
+                               lengths = new TemporaryVariable [rank];
+
+                               ArrayList list = new ArrayList ();
+                               for (int i = 0; i < rank; i++) {
+                                       counter [i] = new ArrayCounter (loc);
+                                       counter [i].Resolve (ec);
+
+                                       lengths [i] = new TemporaryVariable (TypeManager.int32_type, loc);
+                                       lengths [i].Resolve (ec);
+
+                                       list.Add (counter [i]);
+                               }
+
+                               access = new ElementAccess (copy, list).Resolve (ec);
+                               if (access == null)
+                                       return false;
+
+                               conv = Convert.ExplicitConversion (ec, access, var_type, loc);
+                               if (conv == null)
+                                       return false;
+
+                               bool ok = true;
+
+                               ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
+                               ec.CurrentBranching.CreateSibling ();
+
+                               variable = variable.ResolveLValue (ec, conv, loc);
+                               if (variable == null)
+                                       ok = false;
+
+                               ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
+                               if (!statement.Resolve (ec))
+                                       ok = false;
+                               ec.EndFlowBranching ();
+
+                               // There's no direct control flow from the end of the embedded statement to the end of the loop
+                               ec.CurrentBranching.CurrentUsageVector.Goto ();
+
+                               ec.EndFlowBranching ();
+
+                               return ok;
+                       }
+
+                       protected override void DoEmit (EmitContext ec)
+                       {
+                               ILGenerator ig = ec.ig;
+
+                               copy.Store (ec, expr);
+
+                               Label[] test = new Label [rank];
+                               Label[] loop = new Label [rank];
+
+                               for (int i = 0; i < rank; i++) {
+                                       test [i] = ig.DefineLabel ();
+                                       loop [i] = ig.DefineLabel ();
+
+                                       lengths [i].EmitThis (ec);
+                                       ((ArrayAccess) access).EmitGetLength (ec, i);
+                                       lengths [i].EmitStore (ec);
+                               }
+
+                               for (int i = 0; i < rank; i++) {
+                                       counter [i].Initialize (ec);
+
+                                       ig.Emit (OpCodes.Br, test [i]);
+                                       ig.MarkLabel (loop [i]);
+                               }
+
+                               ((IAssignMethod) variable).EmitAssign (ec, conv, false, false);
+
+                               statement.Emit (ec);
+
+                               ig.MarkLabel (ec.LoopBegin);
+
+                               for (int i = rank - 1; i >= 0; i--){
+                                       counter [i].Increment (ec);
+
+                                       ig.MarkLabel (test [i]);
+                                       counter [i].Emit (ec);
+                                       lengths [i].Emit (ec);
+                                       ig.Emit (OpCodes.Blt, loop [i]);
+                               }
+
+                               ig.MarkLabel (ec.LoopEnd);
+                       }
+               }
+
+               protected class CollectionForeach : ExceptionStatement
+               {
+                       Expression variable, expr;
+                       Statement statement;
+
+                       TemporaryVariable enumerator;
+                       Expression init;
+                       Statement loop;
+
+                       MethodGroupExpr get_enumerator;
+                       PropertyExpr get_current;
+                       MethodInfo move_next;
+                       Type var_type, enumerator_type;
+                       bool is_disposable;
+                       bool enumerator_found;
+
+                       public CollectionForeach (Type var_type, Expression var,
+                                                 Expression expr, Statement stmt, Location l)
+                       {
+                               this.var_type = var_type;
+                               this.variable = var;
+                               this.expr = expr;
+                               statement = stmt;
+                               loc = l;
+                       }
+
+                       bool GetEnumeratorFilter (EmitContext ec, MethodInfo mi)
+                       {
+                               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'
+                               //
+
+                               if (return_type == TypeManager.ienumerator_type ||
+                                   TypeManager.ienumerator_type.IsAssignableFrom (return_type) ||
+                                   (!RootContext.StdLib && TypeManager.ImplementsInterface (return_type, TypeManager.ienumerator_type))) {
+                                       //
+                                       // If it is not an interface, lets try to find the methods ourselves.
+                                       // For example, if we have:
+                                       // public class Foo : IEnumerator { public bool MoveNext () {} public int Current { get {}}}
+                                       // We can avoid the iface call. This is a runtime perf boost.
+                                       // even bigger if we have a ValueType, because we avoid the cost
+                                       // of boxing.
+                                       //
+                                       // We have to make sure that both methods exist for us to take
+                                       // this path. If one of the methods does not exist, we will just
+                                       // use the interface. Sadly, this complex if statement is the only
+                                       // way I could do this without a goto
+                                       //
+
+#if GMCS_SOURCE
+                                       //
+                                       // Prefer a generic enumerator over a non-generic one.
+                                       //
+                                       if (return_type.IsInterface && return_type.IsGenericType) {
+                                               enumerator_type = return_type;
+                                               if (!FetchGetCurrent (ec, return_type))
+                                                       get_current = new PropertyExpr (
+                                                               ec.ContainerType, TypeManager.ienumerator_getcurrent, loc);
+                                               if (!FetchMoveNext (return_type))
+                                                       move_next = TypeManager.bool_movenext_void;
+                                               return true;
+                                       }
+#endif
+
+                                       if (return_type.IsInterface ||
+                                           !FetchMoveNext (return_type) ||
+                                           !FetchGetCurrent (ec, return_type)) {
+                                               enumerator_type = return_type;
+                                               move_next = TypeManager.bool_movenext_void;
+                                               get_current = new PropertyExpr (
+                                                       ec.ContainerType, TypeManager.ienumerator_getcurrent, loc);
+                                               return true;
+                                       }
+                               } else {
+                                       //
+                                       // Ok, so they dont return an IEnumerable, we will have to
+                                       // find if they support the GetEnumerator pattern.
+                                       //
+
+                                       if (TypeManager.HasElementType (return_type) || !FetchMoveNext (return_type) || !FetchGetCurrent (ec, return_type)) {
+                                               Report.Error (202, loc, "foreach statement requires that the return type `{0}' of `{1}' must have a suitable public MoveNext method and public Current property",
+                                                       TypeManager.CSharpName (return_type), TypeManager.CSharpSignature (mi));
+                                               return false;
+                                       }
+                               }
+
+                               enumerator_type = return_type;
+                               is_disposable = !enumerator_type.IsSealed ||
+                                       TypeManager.ImplementsInterface (
+                                               enumerator_type, TypeManager.idisposable_type);
+
+                               return true;
+                       }
+
+                       //
+                       // Retrieves a `public bool MoveNext ()' method from the Type `t'
+                       //
+                       bool FetchMoveNext (Type t)
+                       {
+                               MemberList move_next_list;
+
+                               move_next_list = TypeContainer.FindMembers (
+                                       t, MemberTypes.Method,
+                                       BindingFlags.Public | BindingFlags.Instance,
+                                       Type.FilterName, "MoveNext");
+                               if (move_next_list.Count == 0)
+                                       return false;
+
+                               foreach (MemberInfo m in move_next_list){
+                                       MethodInfo mi = (MethodInfo) m;
+                               
+                                       if ((TypeManager.GetParameterData (mi).Count == 0) &&
+                                           TypeManager.TypeToCoreType (mi.ReturnType) == TypeManager.bool_type) {
+                                               move_next = mi;
+                                               return true;
+                                       }
+                               }
+
+                               return false;
+                       }
+               
+                       //
+                       // Retrieves a `public T get_Current ()' method from the Type `t'
+                       //
+                       bool FetchGetCurrent (EmitContext ec, Type t)
+                       {
+                               PropertyExpr pe = Expression.MemberLookup (
+                                       ec.ContainerType, t, "Current", MemberTypes.Property,
+                                       Expression.AllBindingFlags, loc) as PropertyExpr;
+                               if (pe == null)
+                                       return false;
+
+                               get_current = pe;
+                               return true;
+                       }
+
+                       // 
+                       // Retrieves a `public void Dispose ()' method from the Type `t'
+                       //
+                       static MethodInfo FetchMethodDispose (Type t)
+                       {
+                               MemberList dispose_list;
+
+                               dispose_list = TypeContainer.FindMembers (
+                                       t, MemberTypes.Method,
+                                       BindingFlags.Public | BindingFlags.Instance,
+                                       Type.FilterName, "Dispose");
+                               if (dispose_list.Count == 0)
+                                       return null;
+
+                               foreach (MemberInfo m in dispose_list){
+                                       MethodInfo mi = (MethodInfo) m;
+
+                                       if (TypeManager.GetParameterData (mi).Count == 0){
+                                               if (mi.ReturnType == TypeManager.void_type)
+                                                       return mi;
+                                       }
+                               }
+                               return null;
+                       }
+
+                       public void Error_Enumerator ()
+                       {
+                               if (enumerator_found) {
+                                       return;
+                               }
+
+                           Report.Error (1579, loc,
+                                       "foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `GetEnumerator' or is not accessible",
+                                       TypeManager.CSharpName (expr.Type));
+                       }
+
+                       bool TryType (EmitContext ec, Type t)
+                       {
+                               MethodGroupExpr mg = Expression.MemberLookup (
+                                       ec.ContainerType, t, "GetEnumerator", MemberTypes.Method,
+                                       Expression.AllBindingFlags, loc) as MethodGroupExpr;
+                               if (mg == null)
+                                       return false;
+
+                               MethodInfo result = null;
+                               MethodInfo tmp_move_next = null;
+                               PropertyExpr tmp_get_cur = null;
+                               Type tmp_enumerator_type = enumerator_type;
+                               foreach (MethodInfo mi in mg.Methods) {
+                                       if (TypeManager.GetParameterData (mi).Count != 0)
+                                               continue;
+                       
+                                       // Check whether GetEnumerator is public
+                                       if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
+                                               continue;
+
+                                       if (TypeManager.IsOverride (mi))
+                                               continue;
+
+                                       enumerator_found = true;
+
+                                       if (!GetEnumeratorFilter (ec, mi))
+                                               continue;
+
+                                       if (result != null) {
+                                               if (TypeManager.IsGenericType (result.ReturnType)) {
+                                                       if (!TypeManager.IsGenericType (mi.ReturnType))
+                                                               continue;
+
+                                                       Report.SymbolRelatedToPreviousError(t);
+                                                       Report.Error(1640, loc, "foreach statement cannot operate on variables of type `{0}' " +
+                                                               "because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
+                                                               TypeManager.CSharpName (t), TypeManager.CSharpSignature (mi));
+                                                       return false;
+                                               }
+                                               Report.SymbolRelatedToPreviousError (result);
+                                               Report.SymbolRelatedToPreviousError (mi);
+                                               Report.Warning (278, 2, loc, "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
+                                                       TypeManager.CSharpName (t), "enumerable", TypeManager.CSharpSignature (result), TypeManager.CSharpSignature (mi));
+                                       }
+                                       result = mi;
+                                       tmp_move_next = move_next;
+                                       tmp_get_cur = get_current;
+                                       tmp_enumerator_type = enumerator_type;
+                                       if (mi.DeclaringType == t)
+                                               break;
+                               }
+
+                               if (result != null) {
+                                       move_next = tmp_move_next;
+                                       get_current = tmp_get_cur;
+                                       enumerator_type = tmp_enumerator_type;
+                                       MethodInfo[] mi = new MethodInfo[] { (MethodInfo) result };
+                                       get_enumerator = new MethodGroupExpr (mi, loc);
+
+                                       if (t != expr.Type) {
+                                               expr = Convert.ExplicitConversion (
+                                                       ec, expr, t, loc);
+                                               if (expr == null)
+                                                       throw new InternalErrorException ();
+                                       }
+
+                                       get_enumerator.InstanceExpression = expr;
+                                       get_enumerator.IsBase = t != expr.Type;
+
+                                       return true;
+                               }
+
+                               return false;
+                       }               
+
+                       bool ProbeCollectionType (EmitContext ec, Type t)
+                       {
+                               int errors = Report.Errors;
+                               for (Type tt = t; tt != null && tt != TypeManager.object_type;){
+                                       if (TryType (ec, tt))
+                                               return true;
+                                       tt = tt.BaseType;
+                               }
+
+                               if (Report.Errors > errors)
+                                       return false;
+
+                               //
+                               // Now try to find the method in the interfaces
+                               //
+                               while (t != null){
+                                       Type [] ifaces = t.GetInterfaces ();
+
+                                       foreach (Type i in ifaces){
+                                               if (TryType (ec, i))
+                                                       return true;
+                                       }
+                               
+                                       //
+                                       // Since TypeBuilder.GetInterfaces only returns the interface
+                                       // types for this type, we have to keep looping, but once
+                                       // we hit a non-TypeBuilder (ie, a Type), then we know we are
+                                       // done, because it returns all the types
+                                       //
+                                       if ((t is TypeBuilder))
+                                               t = t.BaseType;
+                                       else
+                                               break;
+                               }
+
+                               return false;
+                       }
+
+                       public override bool Resolve (EmitContext ec)
+                       {
+                               enumerator_type = TypeManager.ienumerator_type;
+                               is_disposable = true;
+
+                               if (!ProbeCollectionType (ec, expr.Type)) {
+                                       Error_Enumerator ();
+                                       return false;
+                               }
+
+                               enumerator = new TemporaryVariable (enumerator_type, loc);
+                               enumerator.Resolve (ec);
+
+                               init = new Invocation (get_enumerator, new ArrayList ());
+                               init = init.Resolve (ec);
+                               if (init == null)
+                                       return false;
+
+                               Expression move_next_expr;
+                               {
+                                       MemberInfo[] mi = new MemberInfo[] { move_next };
+                                       MethodGroupExpr mg = new MethodGroupExpr (mi, loc);
+                                       mg.InstanceExpression = enumerator;
+
+                                       move_next_expr = new Invocation (mg, new ArrayList ());
+                               }
+
+                               get_current.InstanceExpression = enumerator;
+
+                               Statement block = new CollectionForeachStatement (
+                                       var_type, variable, get_current, statement, loc);
+
+                               loop = new While (move_next_expr, block, loc);
+
+                               bool ok = true;
+
+                               FlowBranchingException branching = null;
+                               if (is_disposable)
+                                       branching = ec.StartFlowBranching (this);
+
+                               if (!loop.Resolve (ec))
+                                       ok = false;
+
+                               if (is_disposable) {
+                                       ResolveFinally (branching);
+                                       ec.EndFlowBranching ();
+                               } else
+                                       emit_finally = true;
+
+                               return ok;
+                       }
+
+                       protected override void DoEmit (EmitContext ec)
+                       {
+                               ILGenerator ig = ec.ig;
+
+                               enumerator.Store (ec, init);
+
+                               //
+                               // Protect the code in a try/finalize block, so that
+                               // if the beast implement IDisposable, we get rid of it
+                               //
+                               if (is_disposable && emit_finally)
+                                       ig.BeginExceptionBlock ();
+                       
+                               loop.Emit (ec);
+
+                               //
+                               // Now the finally block
+                               //
+                               if (is_disposable) {
+                                       DoEmitFinally (ec);
+                                       if (emit_finally)
+                                               ig.EndExceptionBlock ();
+                               }
+                       }
+
+
+                       public override void EmitFinally (EmitContext ec)
+                       {
+                               ILGenerator ig = ec.ig;
+
+                               if (enumerator_type.IsValueType) {
+                                       MethodInfo mi = FetchMethodDispose (enumerator_type);
+                                       if (mi != null) {
+                                               enumerator.EmitLoadAddress (ec);
+                                               ig.Emit (OpCodes.Call, mi);
+                                       } else {
+                                               enumerator.Emit (ec);
+                                               ig.Emit (OpCodes.Box, enumerator_type);
+                                               ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
+                                       }
+                               } else {
+                                       Label call_dispose = ig.DefineLabel ();
+
+                                       enumerator.Emit (ec);
+                                       ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
+                                       ig.Emit (OpCodes.Dup);
+                                       ig.Emit (OpCodes.Brtrue_S, call_dispose);
+                                       ig.Emit (OpCodes.Pop);
+
+                                       Label end_finally = ig.DefineLabel ();
+                                       ig.Emit (OpCodes.Br, end_finally);
+
+                                       ig.MarkLabel (call_dispose);
+                                       ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
+                                       ig.MarkLabel (end_finally);
+                               }
+                       }
+               }
+
+               protected 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;
+                       }
+
+                       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 Assign (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);
+                       }
+               }
+       }
+}