Added few unsafe tests.
[mono.git] / mcs / mcs / expression.cs
index baaab4fc0fde1c10903afaa605229d625e472def..90d72ecf3ece0079f028bb466b27c4a3442ea17d 100644 (file)
@@ -5,8 +5,8 @@
 //   Miguel de Icaza (miguel@ximian.com)
 //   Marek Safar (marek.safar@seznam.cz)
 //
-// (C) 2001, 2002, 2003 Ximian, Inc.
-// (C) 2003, 2004 Novell, Inc.
+// Copyright 2001, 2002, 2003 Ximian, Inc.
+// Copyright 2003-2008 Novell, Inc.
 //
 #define USE_OLD
 
@@ -17,23 +17,41 @@ namespace Mono.CSharp {
        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;
+       //
+       // This is an user operator expression, automatically created during
+       // resolve phase
+       //
+       public class UserOperatorCall : Expression {
+               public delegate Expression ExpressionTreeExpression (EmitContext ec, MethodGroupExpr mg);
 
-               public StaticCallExpr (MethodInfo m, ArrayList a, Location l)
+               protected readonly ArrayList arguments;
+               protected readonly MethodGroupExpr mg;
+               readonly ExpressionTreeExpression expr_tree;
+
+               public UserOperatorCall (MethodGroupExpr mg, ArrayList args, ExpressionTreeExpression expr_tree, Location loc)
                {
-                       mi = m;
-                       args = a;
+                       this.mg = mg;
+                       this.arguments = args;
+                       this.expr_tree = expr_tree;
 
-                       type = m.ReturnType;
+                       type = TypeManager.TypeToCoreType (((MethodInfo) mg).ReturnType);
                        eclass = ExprClass.Value;
-                       loc = l;
+                       this.loc = loc;
+               }
+
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       if (expr_tree != null)
+                               return expr_tree (ec, mg);
+
+                       ArrayList args = new ArrayList (arguments.Count + 1);
+                       args.Add (new Argument (new NullLiteral (loc)));
+                       args.Add (new Argument (mg.CreateExpressionTree (ec)));
+                       foreach (Argument a in arguments) {
+                               args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
+                       }
+
+                       return CreateExpressionFactoryCall ("Call", args);
                }
 
                public override Expression DoResolve (EmitContext ec)
@@ -46,12 +64,11 @@ namespace Mono.CSharp {
 
                public override void Emit (EmitContext ec)
                {
-                       Invocation.EmitArguments (ec, args, false, null);
-                       ec.ig.Emit (OpCodes.Call, mi);
-                       return;
+                       mg.EmitCall (ec, arguments);
                }
-               
-               static public StaticCallExpr MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
+
+               [Obsolete ("It may not be compatible with expression trees")]
+               static public UserOperatorCall MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
                                                         Expression e, Location loc)
                {
                        ArrayList args;
@@ -69,18 +86,11 @@ namespace Mono.CSharp {
                        if (mg == null)
                                return null;
 
-                       return new StaticCallExpr ((MethodInfo) mg, args, loc);
+                       return new UserOperatorCall (mg, args, null, 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 MethodGroupExpr Method {
+                       get { return mg; }
                }
        }
 
@@ -125,11 +135,15 @@ namespace Mono.CSharp {
        public class Unary : Expression {
                public enum Operator : byte {
                        UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
-                       Indirection, AddressOf,  TOP
+                       AddressOf,  TOP
                }
 
+               public static readonly string [] oper_names;
+               static Type [] [] predefined_operators;
+
                public readonly Operator Oper;
                public Expression Expr;
+               Expression enum_conversion;
 
                public Unary (Operator op, Expression expr, Location loc)
                {
@@ -138,31 +152,6 @@ namespace Mono.CSharp {
                        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];
@@ -171,32 +160,20 @@ namespace Mono.CSharp {
                        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);
-               }
-
                // <summary>
                //   This routine will attempt to simplify the unary expression when the
                //   argument is a constant.
                // </summary>
                Constant TryReduceConstant (EmitContext ec, Constant e)
                {
+                       if (e is SideEffectConstant) {
+                               Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
+                               return r == null ? null : new SideEffectConstant (r, e, r.Location);
+                       }
+
                        Type expr_type = e.Type;
                        
                        switch (Oper){
@@ -306,8 +283,8 @@ namespace Mono.CSharp {
                                        if (expr_type != TypeManager.bool_type)
                                                return null;
                                        
-                                       BoolConstant b = (BoolConstant) e;
-                                       return new BoolConstant (!(b.Value), b.Location);
+                                       bool b = (bool)e.GetValue ();
+                                       return new BoolConstant (!b, e.Location);
                                
                                case Operator.OnesComplement:
                                        // Unary numeric promotions
@@ -339,233 +316,147 @@ namespace Mono.CSharp {
                                                return e;
                                        }
                                        return null;
-
-                               case Operator.AddressOf:
-                                       return e;
-
-                               case Operator.Indirection:
-                                       return e;
                        }
                        throw new Exception ("Can not constant fold: " + Oper.ToString());
                }
 
-               Expression ResolveOperator (EmitContext ec)
+               protected Expression ResolveOperator (EmitContext ec, Expression expr)
                {
-                       //
-                       // Step 1: Default operations on CLI native types.
-                       //
+                       eclass = ExprClass.Value;
 
-                       // Attempt to use a constant folding operation.
-                       Constant cexpr = Expr as Constant;
-                       if (cexpr != null) {
-                               cexpr = TryReduceConstant (ec, cexpr);
-                               if (cexpr != null) {
-                                       return cexpr;
-                               }
-                       }
+                       if (predefined_operators == null)
+                               CreatePredefinedOperatorsTable ();
+
+                       Type expr_type = expr.Type;
+                       Expression best_expr;
 
                        //
-                       // Step 2: Perform Operator Overload location
+                       // Primitive types first
                        //
-                       Type expr_type = Expr.Type;
-                       string op_name = oper_names [(int) Oper];
-
-                       Expression 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);
+                       if (TypeManager.IsPrimitiveType (expr_type)) {
+                               best_expr = ResolvePrimitivePredefinedType (expr);
+                               if (best_expr == null)
                                        return null;
-                               }
-                               
-                               return e;
-                       }
 
-                       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;
+                               type = best_expr.Type;
+                               Expr = best_expr;
                                return this;
+                       }
 
-                       case Operator.OnesComplement:
-                               // Unary numeric promotions
-                               if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
-                                       expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
-                                       expr_type == TypeManager.char_type) 
-                               {
-                                       type = TypeManager.int32_type;
-                                       return EmptyCast.Create (this, type);
-                               }
-
-                               // Predefined operators
-                               if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
-                                       expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
-                                       TypeManager.IsEnumType (expr_type))
-                               {
-                                       type = expr_type;
-                                       return this;
-                               }
+                       //
+                       // E operator ~(E x);
+                       //
+                       if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
+                               return ResolveEnumOperator (ec, expr);
 
-                               type = TypeManager.int32_type;
-                               Expr = Convert.ImplicitUserConversion(ec, Expr, type, loc);
-                               if (Expr != null)
-                                       return this;
+                       return ResolveUserType (ec, expr);
+               }
 
-                               Error23 (expr_type);
+               protected virtual Expression ResolveEnumOperator (EmitContext ec, Expression expr)
+               {
+                       Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
+                       Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
+                       if (best_expr == null)
                                return null;
 
-                       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);
-                               }
+                       Expr = best_expr;
+                       enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
+                       type = expr.Type;
+                       return EmptyCast.Create (this, type);
+               }
 
-                               type = TypeManager.GetPointerType (Expr.Type);
-                               return this;
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       return CreateExpressionTree (ec, null);
+               }
 
-                       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);
-                       
+               Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr user_op)
+               {
+                       string method_name;
+                       switch (Oper) {
+                       case Operator.AddressOf:
+                               Error_PointerInsideExpressionTree ();
+                               return null;
+                       case Operator.UnaryNegation:
+                               if (ec.CheckState && user_op == null && !IsFloat (type))
+                                       method_name = "NegateChecked";
+                               else
+                                       method_name = "Negate";
+                               break;
+                       case Operator.OnesComplement:
+                       case Operator.LogicalNot:
+                               method_name = "Not";
+                               break;
                        case Operator.UnaryPlus:
-                               // Unary numeric promotions
-                               if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
-                                       expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
-                                       expr_type == TypeManager.char_type) 
-                               {
-                                       return EmptyCast.Create (Expr, TypeManager.int32_type);
-                               }
-
-                               // Predefined operators
-                               if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
-                                       expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
-                                       expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
-                                       expr_type == TypeManager.decimal_type)
-                               {
-                                       return Expr;
-                               }
-
-                               Expr = Convert.ImplicitUserConversion(ec, Expr, TypeManager.int32_type, loc);
-                               if (Expr != null) {
-                                        // Because we can completely ignore unary +
-                                       return Expr;
-                               }
+                               method_name = "UnaryPlus";
+                               break;
+                       default:
+                               throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
+                       }
 
-                               Error23 (expr_type);
-                               return null;
+                       ArrayList args = new ArrayList (2);
+                       args.Add (new Argument (Expr.CreateExpressionTree (ec)));
+                       if (user_op != null)
+                               args.Add (new Argument (user_op.CreateExpressionTree (ec)));
+                       return CreateExpressionFactoryCall (method_name, args);
+               }
 
-                       case Operator.UnaryNegation:
-                               //
-                               // transform - - expr into expr
-                               //
-                               Unary u = Expr as Unary;
-                               if (u != null && u.Oper == Operator.UnaryNegation) {
-                                       return u.Expr;
-                               }
+               static void CreatePredefinedOperatorsTable ()
+               {
+                       predefined_operators = new Type [(int) Operator.TOP] [];
 
-                               // Unary numeric promotions
-                               if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
-                                       expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
-                                       expr_type == TypeManager.char_type) 
-                               {
-                                       type = TypeManager.int32_type;
-                                       return EmptyCast.Create (this, type);
-                               }
+                       //
+                       // 7.6.1 Unary plus operator
+                       //
+                       predefined_operators [(int) Operator.UnaryPlus] = new Type [] {
+                               TypeManager.int32_type, TypeManager.uint32_type,
+                               TypeManager.int64_type, TypeManager.uint64_type,
+                               TypeManager.float_type, TypeManager.double_type,
+                               TypeManager.decimal_type
+                       };
 
-                               //
-                               // Predefined operators
-                               //
-                               if (expr_type == TypeManager.uint32_type) {
-                                       type = TypeManager.int64_type;
-                                       Expr = Convert.ImplicitNumericConversion (Expr, type);
-                                       return this;
-                               }
+                       //
+                       // 7.6.2 Unary minus operator
+                       //
+                       predefined_operators [(int) Operator.UnaryNegation] = new Type [] {
+                               TypeManager.int32_type, 
+                               TypeManager.int64_type,
+                               TypeManager.float_type, TypeManager.double_type,
+                               TypeManager.decimal_type
+                       };
 
-                               if (expr_type == TypeManager.int32_type || expr_type == TypeManager.int64_type || 
-                                       expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
-                                       expr_type == TypeManager.decimal_type)
-                               {
-                                       type = expr_type;
-                                       return this;
-                               }
+                       //
+                       // 7.6.3 Logical negation operator
+                       //
+                       predefined_operators [(int) Operator.LogicalNot] = new Type [] {
+                               TypeManager.bool_type
+                       };
 
-                               //
-                               // User conversion
+                       //
+                       // 7.6.4 Bitwise complement operator
+                       //
+                       predefined_operators [(int) Operator.OnesComplement] = new Type [] {
+                               TypeManager.int32_type, TypeManager.uint32_type,
+                               TypeManager.int64_type, TypeManager.uint64_type
+                       };
+               }
 
-                               type = TypeManager.int32_type;
-                               Expr = Convert.ImplicitUserConversion(ec, Expr, type, loc);
-                               if (Expr != null)
-                                       return this;
+               //
+               // Unary numeric promotions
+               //
+               static Expression DoNumericPromotion (Operator op, Expression expr)
+               {
+                       Type expr_type = expr.Type;
+                       if ((op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) &&
+                               expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
+                               expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
+                               expr_type == TypeManager.char_type)
+                               return Convert.ImplicitNumericConversion (expr, TypeManager.int32_type);
 
-                               Error23 (expr_type);
-                               return null;
-                       }
+                       if (op == Operator.UnaryNegation && expr_type == TypeManager.uint32_type)
+                               return Convert.ImplicitNumericConversion (expr, TypeManager.int64_type);
 
-                       Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
-                              TypeManager.CSharpName (expr_type) + "'");
-                       return null;
+                       return expr;
                }
 
                public override Expression DoResolve (EmitContext ec)
@@ -577,40 +468,61 @@ namespace Mono.CSharp {
                                        Error (211, "Cannot take the address of the given expression");
                                        return null;
                                }
+
+                               return ResolveAddressOf (ec);
                        }
-                       else
-                               Expr = Expr.Resolve (ec);
 
+                       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);
+                       //
+                       // Attempt to use a constant folding operation.
+                       //
+                       Constant cexpr = Expr as Constant;
+                       if (cexpr != null) {
+                               cexpr = TryReduceConstant (ec, cexpr);
+                               if (cexpr != null)
+                                       return cexpr;
+                       }
+
+                       Expression expr = ResolveOperator (ec, Expr);
+                       if (expr == null)
+                               Error_OperatorCannotBeApplied (loc, OperName (Oper), Expr.Type);
+                       
+                       //
+                       // Reduce unary operator on predefined types
+                       //
+                       if (expr == this && Oper == Operator.UnaryPlus)
+                               return Expr;
+
+                       return expr;
                }
 
                public override Expression DoResolveLValue (EmitContext ec, Expression right)
                {
-                       if (Oper == Operator.Indirection)
-                               return DoResolve (ec);
-
                        return null;
                }
 
                public override void Emit (EmitContext ec)
+               {
+                       EmitOperator (ec, type);
+               }
+
+               protected void EmitOperator (EmitContext ec, Type type)
                {
                        ILGenerator ig = ec.ig;
-                       
+
                        switch (Oper) {
                        case Operator.UnaryPlus:
-                               throw new Exception ("This should be caught by Resolve");
+                               Expr.Emit (ec);
+                               break;
                                
                        case Operator.UnaryNegation:
-                               if (ec.CheckState && type != TypeManager.float_type && type != TypeManager.double_type) {
+                               if (ec.CheckState && !IsFloat (type)) {
                                        ig.Emit (OpCodes.Ldc_I4_0);
                                        if (type == TypeManager.int64_type)
                                                ig.Emit (OpCodes.Conv_U8);
@@ -642,6 +554,12 @@ namespace Mono.CSharp {
                                throw new Exception ("This should not happen: Operator = "
                                                     + Oper.ToString ());
                        }
+
+                       //
+                       // Same trick as in Binary expression
+                       //
+                       if (enum_conversion != null)
+                               enum_conversion.Emit (ec);
                }
 
                public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
@@ -652,24 +570,197 @@ namespace Mono.CSharp {
                                base.EmitBranchable (ec, target, on_true);
                }
 
-               public override string ToString ()
+               public override void EmitSideEffect (EmitContext ec)
                {
-                       return "Unary (" + Oper + ", " + Expr + ")";
+                       Expr.EmitSideEffect (ec);
                }
 
-               protected override void CloneTo (CloneContext clonectx, Expression t)
+               public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
                {
-                       Unary target = (Unary) t;
+                       Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
+                               oper, TypeManager.CSharpName (t));
+               }
 
-                       target.Expr = Expr.Clone (clonectx);
+               static bool IsFloat (Type t)
+               {
+                       return t == TypeManager.float_type || t == TypeManager.double_type;
                }
-       }
 
-       //
-       // Unary operators are turned into Indirection expressions
-       // after semantic analysis (this is so we can take the address
-       // of an indirection).
-       //
+               //
+               // Returns a stringified representation of the Operator
+               //
+               public static 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 "&";
+                       }
+
+                       throw new NotImplementedException (oper.ToString ());
+               }
+
+               Expression ResolveAddressOf (EmitContext ec)
+               {
+                       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);
+                       eclass = ExprClass.Value;
+                       return this;
+               }
+
+               Expression ResolvePrimitivePredefinedType (Expression expr)
+               {
+                       expr = DoNumericPromotion (Oper, expr);
+                       Type expr_type = expr.Type;
+                       Type[] predefined = predefined_operators [(int) Oper];
+                       foreach (Type t in predefined) {
+                               if (t == expr_type)
+                                       return expr;
+                       }
+                       return null;
+               }
+
+               //
+               // Perform user-operator overload resolution
+               //
+               protected virtual Expression ResolveUserOperator (EmitContext ec, Expression expr)
+               {
+                       string op_name = oper_names [(int) Oper];
+                       MethodGroupExpr user_op = MemberLookup (ec.ContainerType, expr.Type, op_name, MemberTypes.Method, AllBindingFlags, expr.Location) as MethodGroupExpr;
+                       if (user_op == null)
+                               return null;
+
+                       ArrayList args = new ArrayList (1);
+                       args.Add (new Argument (expr));
+                       user_op = user_op.OverloadResolve (ec, ref args, false, expr.Location);
+
+                       if (user_op == null)
+                               return null;
+
+                       Expr = ((Argument) args [0]).Expr;
+                       return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
+               }
+
+               //
+               // Unary user type overload resolution
+               //
+               Expression ResolveUserType (EmitContext ec, Expression expr)
+               {
+                       Expression best_expr = ResolveUserOperator (ec, expr);
+                       if (best_expr != null)
+                               return best_expr;
+
+                       Type[] predefined = predefined_operators [(int) Oper];
+                       foreach (Type t in predefined) {
+                               Expression oper_expr = Convert.UserDefinedConversion (ec, expr, t, expr.Location, false);
+                               if (oper_expr == null)
+                                       continue;
+
+                               //
+                               // decimal type is predefined but has user-operators
+                               //
+                               if (oper_expr.Type == TypeManager.decimal_type)
+                                       oper_expr = ResolveUserType (ec, oper_expr);
+                               else
+                                       oper_expr = ResolvePrimitivePredefinedType (oper_expr);
+
+                               if (oper_expr == null)
+                                       continue;
+
+                               if (best_expr == null) {
+                                       best_expr = oper_expr;
+                                       continue;
+                               }
+
+                               int result = MethodGroupExpr.BetterTypeConversion (ec, best_expr.Type, t);
+                               if (result == 0) {
+                                       Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
+                                               OperName (Oper), TypeManager.CSharpName (expr.Type));
+                                       break;
+                               }
+
+                               if (result == 2)
+                                       best_expr = oper_expr;
+                       }
+                       
+                       if (best_expr == null)
+                               return null;
+                       
+                       //
+                       // HACK: Decimal user-operator is included in standard operators
+                       //
+                       if (best_expr.Type == TypeManager.decimal_type)
+                               return best_expr;                       
+
+                       Expr = best_expr;
+                       type = best_expr.Type;
+                       return this;                    
+               }
+
+               protected override void CloneTo (CloneContext clonectx, Expression t)
+               {
+                       Unary target = (Unary) t;
+
+                       target.Expr = Expr.Clone (clonectx);
+               }
+       }
+
+       //
+       // 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;
@@ -678,10 +769,14 @@ namespace Mono.CSharp {
                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 Expression CreateExpressionTree (EmitContext ec)
+               {
+                       Error_PointerInsideExpressionTree ();
+                       return null;
+               }
                
                public override void Emit (EmitContext ec)
                {
@@ -737,9 +832,20 @@ namespace Mono.CSharp {
 
                public override Expression DoResolve (EmitContext ec)
                {
-                       //
-                       // Born fully resolved
-                       //
+                       expr = expr.Resolve (ec);
+                       if (expr == null)
+                               return null;
+
+                       if (!ec.InUnsafe)
+                               UnsafeError (loc);
+
+                       if (!expr.Type.IsPointer) {
+                               Error (193, "The * or -> operator must be applied to a pointer");
+                               return null;
+                       }
+
+                       type = TypeManager.GetElementType (expr.Type);
+                       eclass = ExprClass.Variable;
                        return this;
                }
                
@@ -800,7 +906,7 @@ namespace Mono.CSharp {
                //
                // This is expensive for the simplest case.
                //
-               StaticCallExpr method;
+               UserOperatorCall method;
 
                public UnaryMutator (Mode m, Expression e, Location l)
                {
@@ -832,7 +938,7 @@ namespace Mono.CSharp {
                                (t == TypeManager.int64_type) ||
                                (t == TypeManager.uint64_type) ||
                                (t == TypeManager.char_type) ||
-                               (t.IsSubclassOf (TypeManager.enum_type)) ||
+                               (TypeManager.IsSubclassOf (t, TypeManager.enum_type)) ||
                                (t == TypeManager.float_type) ||
                                (t == TypeManager.double_type) ||
                                (t.IsPointer && t != TypeManager.void_ptr_type);
@@ -856,7 +962,7 @@ namespace Mono.CSharp {
                        mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
 
                        if (mg != null) {
-                               method = StaticCallExpr.MakeSimpleCall (
+                               method = UserOperatorCall.MakeSimpleCall (
                                        ec, (MethodGroupExpr) mg, expr, loc);
 
                                type = method.Type;
@@ -890,6 +996,11 @@ namespace Mono.CSharp {
                        return this;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       return new SimpleAssign (this, this).CreateExpressionTree (ec);
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        expr = expr.Resolve (ec);
@@ -1008,7 +1119,7 @@ namespace Mono.CSharp {
                                if (method == null)
                                        LoadOneAndEmitOp (ec, expr.Type);
                                else
-                                       ec.ig.Emit (OpCodes.Call, method.Method);
+                                       ec.ig.Emit (OpCodes.Call, (MethodInfo)method.Method);
                                recurse = false;
                                return;
                        }
@@ -1100,6 +1211,14 @@ namespace Mono.CSharp {
                        : base (expr, probe_type, l)
                {
                }
+
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       ArrayList args = new ArrayList (2);
+                       args.Add (new Argument (expr.CreateExpressionTree (ec)));
+                       args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
+                       return CreateExpressionFactoryCall ("TypeIs", args);
+               }
                
                public override void Emit (EmitContext ec)
                {
@@ -1119,7 +1238,7 @@ namespace Mono.CSharp {
                        ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
                        ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
                }
-
+               
                Expression CreateConstantResult (bool result)
                {
                        if (result)
@@ -1129,7 +1248,7 @@ namespace Mono.CSharp {
                                Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
                                        TypeManager.CSharpName (probe_type_expr.Type));
 
-                       return new BoolConstant (result, loc);
+                       return ReducedExpression.Create (new BoolConstant (result, loc), this);
                }
 
                public override Expression DoResolve (EmitContext ec)
@@ -1236,14 +1355,22 @@ namespace Mono.CSharp {
        ///   Implementation of the `as' operator.
        /// </summary>
        public class As : Probe {
+               bool do_isinst;
+               Expression resolved_type;
+               
                public As (Expression expr, Expression probe_type, Location l)
                        : base (expr, probe_type, l)
                {
                }
 
-               bool do_isinst = false;
-               Expression resolved_type;
-               
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       ArrayList args = new ArrayList (2);
+                       args.Add (new Argument (expr.CreateExpressionTree (ec)));
+                       args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
+                       return CreateExpressionFactoryCall ("TypeAs", args);
+               }
+
                public override void Emit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
@@ -1280,8 +1407,8 @@ namespace Mono.CSharp {
                        Type etype = expr.Type;
 
                        if (type.IsValueType && !TypeManager.IsNullableType (type)) {
-                               Report.Error (77, loc, "The as operator must be used with a reference type (`" +
-                                             TypeManager.CSharpName (type) + "' is a value type)");
+                               Report.Error (77, loc, "The `as' operator cannot be used with a non-nullable value type `{0}'",
+                                             TypeManager.CSharpName (type));
                                return null;
                        
                        }
@@ -1312,8 +1439,7 @@ namespace Mono.CSharp {
                        }
 #endif
                        if (expr.IsNull && TypeManager.IsNullableType (type)) {
-                               Report.Warning (458, 2, loc, "The result of the expression is always `null' of type `{0}'",
-                                       TypeManager.CSharpName (type));
+                               return Nullable.LiftedNull.CreateFromExpression (this);
                        }
                        
                        Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
@@ -1446,6 +1572,14 @@ namespace Mono.CSharp {
                        this.loc = loc;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       ArrayList args = new ArrayList (2);
+                       args.Add (new Argument (this));
+                       args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
+                       return CreateExpressionFactoryCall ("Constant", args);
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
@@ -1459,20 +1593,17 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       if (TypeManager.IsGenericParameter (type))
-                       {
+                       if (TypeManager.IsGenericParameter (type)) {
                                GenericConstraints constraints = TypeManager.GetTypeParameterConstraints(type);
                                if (constraints != null && constraints.IsReferenceType)
-                                       return new NullDefault (new NullLiteral (Location), type);
-                       }
-                       else
-                       {
-                               Constant c = New.Constantify(type);
+                                       return new EmptyConstantCast (new NullLiteral (Location), type);
+                       } else {
+                               Constant c = New.Constantify (type);
                                if (c != null)
-                                       return new NullDefault (c, type);
+                                       return new EmptyConstantCast (c, type);
 
                                if (!TypeManager.IsValueType (type))
-                                       return new NullDefault (new NullLiteral (Location), type);
+                                       return new EmptyConstantCast (new NullLiteral (Location), type);
                        }
                        eclass = ExprClass.Variable;
                        return this;
@@ -1499,79 +1630,307 @@ namespace Mono.CSharp {
        ///   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
-               }
 
-               readonly Operator oper;
-               protected Expression left, right;
-               readonly bool is_compound;
+               protected class PredefinedOperator {
+                       protected readonly Type left;
+                       protected readonly Type right;
+                       public readonly Operator OperatorsMask;
+                       public Type ReturnType;
 
-               // 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 PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
+                               : this (ltype, rtype, op_mask, ltype)
+                       {
+                       }
 
-               public Binary (Operator oper, Expression left, Expression right, bool isCompound)
-                       : this (oper, left, right)
-               {
-                       this.is_compound = isCompound;
+                       public PredefinedOperator (Type type, Operator op_mask, Type return_type)
+                               : this (type, type, op_mask, return_type)
+                       {
+                       }
+
+                       public PredefinedOperator (Type type, Operator op_mask)
+                               : this (type, type, op_mask, type)
+                       {
+                       }
+
+                       public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
+                       {
+                               if ((op_mask & Operator.ValuesOnlyMask) != 0)
+                                       throw new InternalErrorException ("Only masked values can be used");
+
+                               this.left = ltype;
+                               this.right = rtype;
+                               this.OperatorsMask = op_mask;
+                               this.ReturnType = return_type;
+                       }
+
+                       public virtual Expression ConvertResult (EmitContext ec, Binary b)
+                       {
+                               b.type = ReturnType;
+
+                               if (left != null)
+                                       b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
+
+                               if (right != null)
+                                       b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
+
+                               return b;
+                       }
+
+                       public bool IsPrimitiveApplicable (Type type)
+                       {
+                               //
+                               // We are dealing with primitive types only
+                               //
+                               return left == type;
+                       }
+
+                       public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
+                       {
+                               if (TypeManager.IsEqual (left, lexpr.Type) &&
+                                       TypeManager.IsEqual (right, rexpr.Type))
+                                       return true;
+
+                               return Convert.ImplicitConversionExists (ec, lexpr, left) &&
+                                       Convert.ImplicitConversionExists (ec, rexpr, right);
+                       }
+
+                       public PredefinedOperator ResolveBetterOperator (EmitContext ec, Expression lexpr, Expression rexpr, PredefinedOperator best_operator)
+                       {
+                               int result = 0;
+                               if (left != null && best_operator.left != null) {
+                                       result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
+                               }
+
+                               //
+                               // When second arguments are same as the first one, the result is same
+                               //
+                               if (left != right || best_operator.left != best_operator.right) {
+                                       result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
+                               }
+
+                               if (result == 0 || result > 2)
+                                       return null;
+
+                               return result == 1 ? best_operator : this;
+                       }
                }
 
-               public Binary (Operator oper, Expression left, Expression right)
-               {
-                       this.oper = oper;
-                       this.left = left;
-                       this.right = right;
-                       this.loc = left.Location;
+               class PredefinedStringOperator : PredefinedOperator {
+                       public PredefinedStringOperator (Type type, Operator op_mask)
+                               : base (type, op_mask, type)
+                       {
+                               ReturnType = TypeManager.string_type;
+                       }
+
+                       public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
+                               : base (ltype, rtype, op_mask)
+                       {
+                               ReturnType = TypeManager.string_type;
+                       }
+
+                       public override Expression ConvertResult (EmitContext ec, Binary b)
+                       {
+                               //
+                               // Use original expression for nullable arguments
+                               //
+                               Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
+                               if (unwrap != null)
+                                       b.left = unwrap.Original;
+
+                               unwrap = b.right as Nullable.Unwrap;
+                               if (unwrap != null)
+                                       b.right = unwrap.Original;
+
+                               b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
+                               b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
+
+                               //
+                               // Start a new concat expression using converted expression
+                               //
+                               return new StringConcat (ec, b.loc, b.left, b.right).Resolve (ec);
+                       }
                }
 
-               public Operator Oper {
-                       get {
-                               return oper;
+               class PredefinedShiftOperator : PredefinedOperator {
+                       public PredefinedShiftOperator (Type ltype, Operator op_mask) :
+                               base (ltype, TypeManager.int32_type, op_mask)
+                       {
+                       }
+
+                       public override Expression ConvertResult (EmitContext ec, Binary b)
+                       {
+                               b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
+
+                               Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
+
+                               int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
+
+                               //
+                               // b = b.left >> b.right & (0x1f|0x3f)
+                               //
+                               b.right = new Binary (Operator.BitwiseAnd,
+                                       b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
+
+                               //
+                               // Expression tree representation does not use & mask
+                               //
+                               b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
+                               b.type = ReturnType;
+                               return b;
                        }
                }
-               
-               /// <summary>
-               ///   Returns a stringified representation of the Operator
-               /// </summary>
-               string OperName (Operator oper)
-               {
-                       string s;
-                       switch (oper){
-                       case Operator.Multiply:
+
+               class PredefinedPointerOperator : PredefinedOperator {
+                       public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
+                               : base (ltype, rtype, op_mask)
+                       {
+                       }
+
+                       public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
+                               : base (type, op_mask, return_type)
+                       {
+                       }
+
+                       public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
+                       {
+                               if (left == null) {
+                                       if (!lexpr.Type.IsPointer)
+                                               return false;
+                               } else {
+                                       if (!Convert.ImplicitConversionExists (ec, lexpr, left))
+                                               return false;
+                               }
+
+                               if (right == null) {
+                                       if (!rexpr.Type.IsPointer)
+                                               return false;
+                               } else {
+                                       if (!Convert.ImplicitConversionExists (ec, rexpr, right))
+                                               return false;
+                               }
+
+                               return true;
+                       }
+
+                       public override Expression ConvertResult (EmitContext ec, Binary b)
+                       {
+                               base.ConvertResult (ec, b);
+
+                               Type r_type = ReturnType;
+                               if (r_type == null) {
+                                       r_type = b.left.Type;
+                                       if (r_type == null)
+                                               r_type = b.right.Type;
+                               }
+
+                               return new PointerArithmetic (b.oper == Operator.Addition,
+                                       b.left, b.right, r_type, b.loc).Resolve (ec);
+                       }
+               }
+
+               [Flags]
+               public enum Operator {
+                       Multiply        = 0 | ArithmeticMask,
+                       Division        = 1 | ArithmeticMask,
+                       Modulus         = 2 | ArithmeticMask,
+                       Addition        = 3 | ArithmeticMask | AdditionMask,
+                       Subtraction = 4 | ArithmeticMask | SubtractionMask,
+
+                       LeftShift       = 5 | ShiftMask,
+                       RightShift      = 6 | ShiftMask,
+
+                       LessThan        = 7 | ComparisonMask | RelationalMask,
+                       GreaterThan     = 8 | ComparisonMask | RelationalMask,
+                       LessThanOrEqual         = 9 | ComparisonMask | RelationalMask,
+                       GreaterThanOrEqual      = 10 | ComparisonMask | RelationalMask,
+                       Equality        = 11 | ComparisonMask | EqualityMask,
+                       Inequality      = 12 | ComparisonMask | EqualityMask,
+
+                       BitwiseAnd      = 13 | BitwiseMask,
+                       ExclusiveOr     = 14 | BitwiseMask,
+                       BitwiseOr       = 15 | BitwiseMask,
+
+                       LogicalAnd      = 16 | LogicalMask,
+                       LogicalOr       = 17 | LogicalMask,
+
+                       //
+                       // Operator masks
+                       //
+                       ValuesOnlyMask  = ArithmeticMask - 1,
+                       ArithmeticMask  = 1 << 5,
+                       ShiftMask               = 1 << 6,
+                       ComparisonMask  = 1 << 7,
+                       EqualityMask    = 1 << 8,
+                       BitwiseMask             = 1 << 9,
+                       LogicalMask             = 1 << 10,
+                       AdditionMask    = 1 << 11,
+                       SubtractionMask = 1 << 12,
+                       RelationalMask  = 1 << 13
+               }
+
+               readonly Operator oper;
+               protected Expression left, right;
+               readonly bool is_compound;
+               Expression enum_conversion;
+
+               // This must be kept in sync with Operator!!!
+               public static readonly string [] oper_names;
+
+               static PredefinedOperator [] standard_operators;
+               static PredefinedOperator [] pointer_operators;
+               
+               static Binary ()
+               {
+                       oper_names = new string [18];
+
+                       oper_names [(int) (Operator.Multiply & Operator.ValuesOnlyMask)] = "op_Multiply";
+                       oper_names [(int) (Operator.Division & Operator.ValuesOnlyMask)] = "op_Division";
+                       oper_names [(int) (Operator.Modulus & Operator.ValuesOnlyMask)] = "op_Modulus";
+                       oper_names [(int) (Operator.Addition & Operator.ValuesOnlyMask)] = "op_Addition";
+                       oper_names [(int) (Operator.Subtraction & Operator.ValuesOnlyMask)] = "op_Subtraction";
+                       oper_names [(int) (Operator.LeftShift & Operator.ValuesOnlyMask)] = "op_LeftShift";
+                       oper_names [(int) (Operator.RightShift & Operator.ValuesOnlyMask)] = "op_RightShift";
+                       oper_names [(int) (Operator.LessThan & Operator.ValuesOnlyMask)] = "op_LessThan";
+                       oper_names [(int) (Operator.GreaterThan & Operator.ValuesOnlyMask)] = "op_GreaterThan";
+                       oper_names [(int) (Operator.LessThanOrEqual & Operator.ValuesOnlyMask)] = "op_LessThanOrEqual";
+                       oper_names [(int) (Operator.GreaterThanOrEqual & Operator.ValuesOnlyMask)] = "op_GreaterThanOrEqual";
+                       oper_names [(int) (Operator.Equality & Operator.ValuesOnlyMask)] = "op_Equality";
+                       oper_names [(int) (Operator.Inequality & Operator.ValuesOnlyMask)] = "op_Inequality";
+                       oper_names [(int) (Operator.BitwiseAnd & Operator.ValuesOnlyMask)] = "op_BitwiseAnd";
+                       oper_names [(int) (Operator.BitwiseOr & Operator.ValuesOnlyMask)] = "op_BitwiseOr";
+                       oper_names [(int) (Operator.ExclusiveOr & Operator.ValuesOnlyMask)] = "op_ExclusiveOr";
+                       oper_names [(int) (Operator.LogicalOr & Operator.ValuesOnlyMask)] = "op_LogicalOr";
+                       oper_names [(int) (Operator.LogicalAnd & Operator.ValuesOnlyMask)] = "op_LogicalAnd";
+               }
+
+               public Binary (Operator oper, Expression left, Expression right, bool isCompound)
+                       : this (oper, left, right)
+               {
+                       this.is_compound = isCompound;
+               }
+
+               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;
+                       }
+               }
+               
+               /// <summary>
+               ///   Returns a stringified representation of the Operator
+               /// </summary>
+               string OperName (Operator oper)
+               {
+                       string s;
+                       switch (oper){
+                       case Operator.Multiply:
                                s = "*";
                                break;
                        case Operator.Division:
@@ -1636,949 +1995,889 @@ namespace Mono.CSharp {
                        return s;
                }
 
-               public override string ToString ()
+               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)
                {
-                       return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
-                               right.ToString () + ")";
+                       Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
+                               name, left, right);
                }
                
-               Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
+               protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
                {
-                       if (expr.Type == target_type)
-                               return expr;
+                       string l, r;
+                       // TODO: This should be handled as Type of method group in CSharpName
+                       if (left.eclass == ExprClass.MethodGroup)
+                               l = left.ExprClassName;
+                       else
+                               l = TypeManager.CSharpName (left.Type);
 
-                       return Convert.ImplicitConversion (ec, expr, target_type, loc);
-               }
+                       if (right.eclass == ExprClass.MethodGroup)
+                               r = right.ExprClassName;
+                       else
+                               r = TypeManager.CSharpName (right.Type);
 
-               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)
-                               + "'");
+                       Error_OperatorCannotBeApplied (Location, OperName (oper), l, r);
                }
 
-               bool IsConvertible (EmitContext ec, Expression le, Expression re, Type t)
+               public static string GetOperatorMetadataName (Operator op)
                {
-                       return Convert.ImplicitConversionExists (ec, le, t) && Convert.ImplicitConversionExists (ec, re, t);
+                       return oper_names [(int)(op & Operator.ValuesOnlyMask)];
                }
 
-               bool VerifyApplicable_Predefined (EmitContext ec, Type t)
+               static bool IsUnsigned (Type t)
                {
-                       if (!IsConvertible (ec, left, right, t))
-                               return false;
-                       left = ForceConversion (ec, left, t);
-                       right = ForceConversion (ec, right, t);
-                       type = t;
-                       return true;
+                       while (t.IsPointer)
+                               t = TypeManager.GetElementType (t);
+
+                       return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
+                               t == TypeManager.ushort_type || t == TypeManager.byte_type);
                }
 
-               bool IsApplicable_String (EmitContext ec, Expression le, Expression re, Operator oper)
+               static bool IsFloat (Type t)
                {
-                       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;
+                       return t == TypeManager.float_type || t == TypeManager.double_type;
                }
 
-               bool OverloadResolve_PredefinedString (EmitContext ec, Operator oper)
+               Expression ResolveOperator (EmitContext ec)
                {
-                       if (!IsApplicable_String (ec, left, right, oper))
-                               return false;
-                       
                        Type l = left.Type;
                        Type r = right.Type;
-                       if (OverloadResolve_PredefinedIntegral (ec) ||
-                               OverloadResolve_PredefinedFloating (ec)) {
-                               Error_OperatorAmbiguous (loc, oper, l, r);
-                       }
-                       
-                       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;
-               }
+                       Expression expr;
+                       bool primitives_only = false;
 
-               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;
-               }
+                       if (standard_operators == null)
+                               CreateStandardOperatorsTable ();
 
-               bool OverloadResolve_PredefinedFloating (EmitContext ec)
-               {
-                       return VerifyApplicable_Predefined (ec, TypeManager.float_type) ||
-                               VerifyApplicable_Predefined (ec, TypeManager.double_type) ||
-                               false;
-               }
+                       //
+                       // Handles predefined primitive types
+                       //
+                       if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
+                               if ((oper & Operator.ShiftMask) == 0) {
+                                       if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
+                                               return null;
 
-               static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
-               {
-                       Error_OperatorCannotBeApplied (loc, name, TypeManager.CSharpName (l), TypeManager.CSharpName (r));
-               }
+                                       primitives_only = true;
+                               }
+                       } else {
+                               // Pointers
+                               if (l.IsPointer || r.IsPointer)
+                                       return ResolveOperatorPointer (ec, l, 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);
-               }
-               
-               protected void Error_OperatorCannotBeApplied ()
-               {
-                       Error_OperatorCannotBeApplied (Location, OperName (oper), TypeManager.CSharpName (left.Type),
-                               TypeManager.CSharpName(right.Type));
-               }
+                               // Enums
+                               bool lenum = TypeManager.IsEnumType (l);
+                               bool renum = TypeManager.IsEnumType (r);
+                               if (lenum || renum) {
+                                       expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
 
-               static bool IsUnsigned (Type t)
-               {
-                       while (t.IsPointer)
-                               t = t.GetElementType ();
+                                       // TODO: Can this be ambiguous
+                                       if (expr != null)
+                                               return expr;
+                               }
 
-                       return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
-                               t == TypeManager.ushort_type || t == TypeManager.byte_type);
-               }
+                               // Delegates
+                               if (oper == Operator.Addition || oper == Operator.Subtraction) {
+                                       if (TypeManager.IsDelegateType (l))
+                                               return ResolveOperatorDelegateBinary (ec, l, r);
+                               }
 
-               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;
+                               // User operators
+                               expr = ResolveUserOperator (ec, l, r);
+                               if (expr != null)
+                                       return expr;
+
+                               // Predefined reference types equality
+                               if ((oper & Operator.EqualityMask) != 0) {
+                                       expr = ResolveOperatorEqualityRerefence (ec, l, r);
+                                       if (expr != null)
+                                               return expr;
+                               }
+                       }
+
+                       return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
                }
-                                       
-               Expression CheckShiftArguments (EmitContext ec)
+
+               // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
+               // if 'left' is not an enumeration constant, create one from the type of 'right'
+               Constant EnumLiftUp (EmitContext ec, Constant left, Constant right, Location loc)
                {
-                       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;
+                       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 (TypeManager.IsEnumType (left.Type))
+                                       return left;
+                               
+                               if (left.IsZeroInteger)
+                                       return left.TryReduce (ec, right.Type, loc);
+                               
+                               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 (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
+                                       break;
+                               return left;
                        }
-                       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;
+                       Error_OperatorCannotBeApplied (this.left, this.right);
+                       return null;
                }
 
                //
-               // This is used to check if a test 'x == null' can be optimized to a reference equals,
-               // i.e., not invoke op_Equality.
+               // The `|' operator used on types which were extended is dangerous
                //
-               static bool EqualsNullIsReferenceEquals (Type t)
+               void CheckBitwiseOrOnSignExtended ()
                {
-                       return t == TypeManager.object_type || t == TypeManager.string_type ||
-                               t == TypeManager.delegate_type || t.IsSubclassOf (TypeManager.delegate_type);
-               }
+                       OpcodeCast lcast = left as OpcodeCast;
+                       if (lcast != null) {
+                               if (IsUnsigned (lcast.UnderlyingType))
+                                       lcast = null;
+                       }
 
-               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));
+                       OpcodeCast rcast = right as OpcodeCast;
+                       if (rcast != null) {
+                               if (IsUnsigned (rcast.UnderlyingType))
+                                       rcast = null;
+                       }
+
+                       if (lcast == null && rcast == null)
+                               return;
+
+                       // FIXME: consider constants
+
+                       Report.Warning (675, 3, loc,
+                               "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
+                               TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
                }
 
-               static void Warning_Constant_Result (Location loc, bool result, Type type)
+               static void CreatePointerOperatorsTable ()
                {
-                       Report.Warning (472, 2, loc, "The result of comparing `{0}' against null is always `{1}'. " +
-                                       "This operation is undocumented and it is temporary supported for compatibility reasons only",
-                                       TypeManager.CSharpName (type), result ? "true" : "false"); 
+                       ArrayList temp = new ArrayList ();
+
+                       //
+                       // Pointer arithmetic:
+                       //
+                       // T* operator + (T* x, int y);         T* operator - (T* x, int y);
+                       // T* operator + (T* x, uint y);        T* operator - (T* x, uint y);
+                       // T* operator + (T* x, long y);        T* operator - (T* x, long y);
+                       // T* operator + (T* x, ulong y);       T* operator - (T* x, ulong y);
+                       //
+                       temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
+                       temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
+                       temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
+                       temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
+
+                       //
+                       // T* operator + (int y,   T* x);
+                       // T* operator + (uint y,  T *x);
+                       // T* operator + (long y,  T *x);
+                       // T* operator + (ulong y, T *x);
+                       //
+                       temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask));
+                       temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask));
+                       temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask));
+                       temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask));
+
+                       //
+                       // long operator - (T* x, T *y)
+                       //
+                       temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
+
+                       pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
                }
-                       
-               Expression ResolveOperator (EmitContext ec)
+
+               static void CreateStandardOperatorsTable ()
                {
-                       Type l = left.Type;
-                       Type r = right.Type;
+                       ArrayList temp = new ArrayList ();
+                       Type bool_type = TypeManager.bool_type;
 
-                       if (oper == Operator.Equality || oper == Operator.Inequality){
-                               if (right.Type == TypeManager.null_type){
-                                       if (TypeManager.IsGenericParameter (l)){
-                                               if (l.BaseType == TypeManager.value_type) {
-                                                       Error_OperatorCannotBeApplied ();
-                                                       return null;
-                                               }
-                                               
-                                               left = new BoxedCast (left, TypeManager.object_type);
-                                               Type = TypeManager.bool_type;
-                                               return this;
-                                       } 
+                       temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
+                       temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
+                       temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
+                       temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
+                       temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
+                       temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
 
-                                       //
-                                       // 7.9.9 Equality operators and null
-                                       //
-                                       // CSC 2 has this behavior, it allows structs to be compared
-                                       // with the null literal *outside* of a generics context and
-                                       // inlines that as true or false.
-                                       //
-                                       // This is, in my opinion, completely wrong.
-                                       //
-                                       if (RootContext.Version != LanguageVersion.ISO_1 && l.IsValueType) {
-                                               if (!TypeManager.IsPrimitiveType (l) && !TypeManager.IsEnumType (l)) {
-                                                       if (MemberLookup (ec.ContainerType, l, oper_names [(int)Operator.Equality], MemberTypes.Method, AllBindingFlags, loc) == null &&
-                                                               MemberLookup (ec.ContainerType, l, oper_names [(int)Operator.Inequality], MemberTypes.Method, AllBindingFlags, loc) == null) {
-                                                               Error_OperatorCannotBeApplied ();
-                                                               return null;
-                                                       }
-                                               }
+                       temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
+                       temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
+                       temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
+                       temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
+                       temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
+                       temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
 
-                                               Warning_Constant_Result (loc, oper == Operator.Inequality, l);
-                                               return new BoolConstant (oper == Operator.Inequality, loc);
-                                       }
-                               }
+                       temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
 
-                               if (left is NullLiteral){
-                                       if (TypeManager.IsGenericParameter (r)){
-                                               if (r.BaseType == TypeManager.value_type) {
-                                                       Error_OperatorCannotBeApplied ();
-                                                       return null;
-                                               }
-                                               
-                                               right = new BoxedCast (right, TypeManager.object_type);
-                                               Type = TypeManager.bool_type;
-                                               return this;
-                                       }
+                       temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
+                       temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
+                       temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
 
-                                       //
-                                       // 7.9.9 Equality operators and null
-                                       //
-                                       // CSC 2 has this behavior, it allows structs to be compared
-                                       // with the null literal *outside* of a generics context and
-                                       // inlines that as true or false.
-                                       //
-                                       // This is, in my opinion, completely wrong.
-                                       //
-                                       if (RootContext.Version != LanguageVersion.ISO_1 && r.IsValueType){
-                                               if (!TypeManager.IsPrimitiveType (r) && !TypeManager.IsEnumType (r)) {
-                                                       if (MemberLookup (ec.ContainerType, r, oper_names [(int) Operator.Equality], MemberTypes.Method, AllBindingFlags, loc) == null &&
-                                                               MemberLookup (ec.ContainerType, r, oper_names [(int) Operator.Inequality], MemberTypes.Method, AllBindingFlags, loc) == null) {
-                                                               Error_OperatorCannotBeApplied ();
-                                                               return null;
-                                                       }
-                                               }
+                       temp.Add (new PredefinedOperator (bool_type,
+                               Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
 
-                                               Warning_Constant_Result (loc, oper == Operator.Inequality, r);
-                                               return new BoolConstant (oper == Operator.Inequality, loc);
-                                       }
-                               }
+                       temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
+                       temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
+                       temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
+                       temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
 
-                               //
-                               // 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;
-                               }
+                       standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
+               }
 
-                               // IntPtr equality
-                               if (l == TypeManager.intptr_type && r == TypeManager.intptr_type) {
-                                       Type = TypeManager.bool_type;
-                                       return this;
+               //
+               // Rules used during binary numeric promotion
+               //
+               static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
+               {
+                       Expression temp;
+                       Type etype;
+
+                       Constant c = prim_expr as Constant;
+                       if (c != null) {
+                               temp = c.ConvertImplicitly (type);
+                               if (temp != null) {
+                                       prim_expr = temp;
+                                       return true;
                                }
+                       }
 
-#if GMCS_SOURCE                                                                                                
-                               //
-                               // Delegate equality
-                               //
-                               MethodGroupExpr mg = null;
-                               Type delegate_type = null;
-                               if (left.eclass == ExprClass.MethodGroup) {
-                                       if (!TypeManager.IsDelegateType(r)) {
-                                               Error_OperatorCannotBeApplied(Location, OperName(oper),
-                                                       left.ExprClassName, right.ExprClassName);
-                                               return null;
-                                       }
-                                       mg = (MethodGroupExpr)left;
-                                       delegate_type = r;
-                               } else if (right.eclass == ExprClass.MethodGroup) {
-                                       if (!TypeManager.IsDelegateType(l)) {
-                                               Error_OperatorCannotBeApplied(Location, OperName(oper),
-                                                       left.ExprClassName, right.ExprClassName);
-                                               return null;
+                       if (type == TypeManager.uint32_type) {
+                               etype = prim_expr.Type;
+                               if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
+                                       type = TypeManager.int64_type;
+
+                                       if (type != second_expr.Type) {
+                                               c = second_expr as Constant;
+                                               if (c != null)
+                                                       temp = c.ConvertImplicitly (type);
+                                               else
+                                                       temp = Convert.ImplicitNumericConversion (second_expr, type);
+                                               if (temp == null)
+                                                       return false;
+                                               second_expr = temp;
                                        }
-                                       mg = (MethodGroupExpr)right;
-                                       delegate_type = l;
                                }
+                       } else if (type == TypeManager.uint64_type) {
+                               //
+                               // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
+                               //
+                               if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
+                                       type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
+                                       return false;
+                       }
 
-                               if (mg != null) {
-                                       Expression e = ImplicitDelegateCreation.Create (ec, mg, delegate_type, loc);
-                                       if (e == null)
-                                               return null;
+                       temp = Convert.ImplicitNumericConversion (prim_expr, type);
+                       if (temp == null)
+                               return false;
 
-                                       // Find operator method
-                                       string op = oper_names[(int)oper];
-                                       MemberInfo[] mi = TypeManager.MemberLookup(ec.ContainerType, null,
-                                               TypeManager.delegate_type, MemberTypes.Method, AllBindingFlags, op, null);
+                       prim_expr = temp;
+                       return true;
+               }
 
-                                       ArrayList args = new ArrayList(2);
-                                       args.Add(new Argument(e, Argument.AType.Expression));
-                                       if (delegate_type == l)
-                                               args.Insert(0, new Argument(left, Argument.AType.Expression));
-                                       else
-                                               args.Add(new Argument(right, Argument.AType.Expression));
+               //
+               // 7.2.6.2 Binary numeric promotions
+               //
+               public bool DoBinaryOperatorPromotion (EmitContext ec)
+               {
+                       Type ltype = left.Type;
+                       Type rtype = right.Type;
+                       Expression temp;
 
-                                       return new BinaryMethod (TypeManager.bool_type, (MethodInfo)mi [0], args);
-                               }
-#endif                         
-                               if (l == TypeManager.anonymous_method_type || r == TypeManager.anonymous_method_type) {
-                                       Error_OperatorCannotBeApplied(Location, OperName(oper),
-                                               left.ExprClassName, right.ExprClassName);
-                                       return null;
-                               }                               
-                       }
+                       foreach (Type t in ConstantFold.binary_promotions) {
+                               if (t == ltype)
+                                       return t == rtype || DoNumericPromotion (ref right, ref left, t);
 
+                               if (t == rtype)
+                                       return t == ltype || DoNumericPromotion (ref left, ref right, t);
+                       }
 
-                       //
-                       // Do not perform operator overload resolution when both sides are
-                       // built-in types
-                       //
-                       MethodGroupExpr 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) as MethodGroupExpr;
-                               if (r != l){
-                                       right_operators = MemberLookup (
-                                               ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
-                                       union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
-                               } else
-                                       union = left_operators;
+                       Type int32 = TypeManager.int32_type;
+                       if (ltype != int32) {
+                               Constant c = left as Constant;
+                               if (c != null)
+                                       temp = c.ConvertImplicitly (int32);
+                               else
+                                       temp = Convert.ImplicitNumericConversion (left, int32);
 
-                               if (union != null) {
-                                       ArrayList args = new ArrayList (2);
-                                       args.Add (new Argument (left, Argument.AType.Expression));
-                                       args.Add (new Argument (right, Argument.AType.Expression));
+                               if (temp == null)
+                                       return false;
+                               left = temp;
+                       }
 
-                                       union = union.OverloadResolve (ec, ref args, true, Location.Null);
+                       if (rtype != int32) {
+                               Constant c = right as Constant;
+                               if (c != null)
+                                       temp = c.ConvertImplicitly (int32);
+                               else
+                                       temp = Convert.ImplicitNumericConversion (right, int32);
 
-                                       if (union != null) {
-                                               MethodInfo mi = (MethodInfo) union;
-                                               return new BinaryMethod (mi.ReturnType, mi, args);
-                                       }
-                               }
+                               if (temp == null)
+                                       return false;
+                               right = temp;
                        }
 
-                       //
-                       // String concatenation
-                       // 
-                       // string operator + (string x, string y);
-                       // string operator + (string x, object y);
-                       // string operator + (object x, string y);
-                       //
-                       if (oper == Operator.Addition && !TypeManager.IsDelegateType (l)) {
-                               // 
-                               // Either left or right expression is implicitly convertible to string
-                               //
-                               if (OverloadResolve_PredefinedString (ec, oper)) {
-                                       if (r == TypeManager.void_type || l == TypeManager.void_type) {
-                                               Error_OperatorCannotBeApplied ();
-                                               return null;
-                                       }
+                       return true;
+               }
 
-                                       //
-                                       // Constants folding for strings and nulls
-                                       //
-                                       if (left.Type == TypeManager.string_type && right.Type == TypeManager.string_type &&
-                                               left is Constant && right is Constant) {
-                                               string lvalue = (string)((Constant) left).GetValue ();
-                                               string rvalue = (string)((Constant) right).GetValue ();
-                                               return new StringConstant (lvalue + rvalue, left.Location);
-                                       }
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       if (left == null)
+                               return null;
 
-                                       // 
-                                       // Append to existing string concatenation
-                                       //
-                                       if (left is StringConcat) {
-                                               ((StringConcat) left).Append (ec, right);
-                                               return left;
-                                       }
+                       if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
+                               left = ((ParenthesizedExpression) left).Expr;
+                               left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
+                               if (left == null)
+                                       return null;
 
-                                       //
-                                       // Otherwise, start a new concat expression using converted expression
-                                       //
-                                       return new StringConcat (ec, loc, left, right).Resolve (ec);
+                               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);
 
-                               //
-                               // Transform a + ( - b) into a - b
-                               //
-                               if (right is Unary){
-                                       Unary right_unary = (Unary) right;
+                       if (left == null)
+                               return null;
 
-                                       if (right_unary.Oper == Unary.Operator.UnaryNegation){
-                                               return new Binary (Operator.Subtraction, left, right_unary.Expr).Resolve (ec);
-                                       }
-                               }
-                       }
+                       Constant lc = left as Constant;
 
-                       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;
-                                       }
+                       if (lc != null && lc.Type == TypeManager.bool_type &&
+                               ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
+                                (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
 
-                                       type = TypeManager.bool_type;
-                                       return this;
-                               }
+                               // FIXME: resolve right expression as unreachable
+                               // right.Resolve (ec);
 
-                               if (l.IsPointer || r.IsPointer) {
-                                       if (l.IsPointer && r.IsPointer) {
-                                               type = TypeManager.bool_type;
-                                               return this;
-                                       }
+                               Report.Warning (429, 4, loc, "Unreachable expression code detected");
+                               return left;
+                       }
 
-                                       if (l.IsPointer && r == TypeManager.null_type) {
-                                               right = new EmptyConstantCast (NullPointer.Null, l);
-                                               type = TypeManager.bool_type;
-                                               return this;
-                                       }
+                       right = right.Resolve (ec);
+                       if (right == null)
+                               return null;
 
-                                       if (r.IsPointer && l == TypeManager.null_type) {
-                                               left = new EmptyConstantCast (NullPointer.Null, r);
-                                               type = TypeManager.bool_type;
-                                               return this;
-                                       }
-                               }
+                       eclass = ExprClass.Value;
+                       Constant rc = right as Constant;
 
-#if GMCS_SOURCE
-                               if (l.IsGenericParameter && r.IsGenericParameter) {
-                                       GenericConstraints l_gc, r_gc;
+                       // 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 (ec, lc, rc, loc);
+                               if (lc == null)
+                                       return null;
+
+                               right = rc = EnumLiftUp (ec, rc, lc, loc);
+                               if (rc == null)
+                                       return null;
+                       }
 
-                                       l_gc = TypeManager.GetTypeParameterConstraints (l);
-                                       r_gc = TypeManager.GetTypeParameterConstraints (r);
+                       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;
+                       } else {
+                               if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) &&
+                                       ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue))) {
 
-                                       if ((l_gc == null) || (r_gc == null) ||
-                                           !(l_gc.HasReferenceTypeConstraint || l_gc.HasClassConstraint) ||
-                                           !(r_gc.HasReferenceTypeConstraint || r_gc.HasClassConstraint)) {
-                                               Error_OperatorCannotBeApplied ();
+                                       if ((ResolveOperator (ec)) == null) {
+                                               Error_OperatorCannotBeApplied (left, right);
                                                return null;
                                        }
 
+                                       if (rc != null) {
+                                               right = left;
+                                               lc = rc;
+                                       }
+
+                                       // The result is a constant with side-effect
+                                       return new SideEffectConstant (lc, right, loc);
                                }
-#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;
+                       // Comparison warnings
+                       if ((oper & Operator.ComparisonMask) != 0) {
+                               if (left.Equals (right)) {
+                                       Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
+                               }
+                               CheckUselessComparison (lc, right.Type);
+                               CheckUselessComparison (rc, left.Type);
+                       }
 
-                                       if (l == r)
-                                               return this;
-                                       
-                                       //
-                                       // Also, a standard conversion must exist from either one
-                                       //
-                                       // NOTE: An interface is converted to the object before the
-                                       // standard conversion is applied. It's not clear from the
-                                       // standard but it looks like it works like that.
-                                       //
-                                       if (l.IsInterface)
-                                               l = TypeManager.object_type;
-                                       if (r.IsInterface)
-                                               r = TypeManager.object_type;                                    
-                                       
-                                       bool left_to_right =
-                                               Convert.ImplicitStandardConversionExists (left, r);
-                                       bool right_to_left = !left_to_right &&
-                                               Convert.ImplicitStandardConversionExists (right, l);
+                       if (RootContext.Version >= LanguageVersion.ISO_2 &&
+                               (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type) ||
+                               (left is NullLiteral && right.Type.IsValueType) || (right is NullLiteral && left.Type.IsValueType)))
+                               return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
 
-                                       if (!left_to_right && !right_to_left) {
-                                               Error_OperatorCannotBeApplied ();
-                                               return null;
-                                       }
+                       return DoResolveCore (ec, left, right);
+               }
 
-                                       if (left_to_right && left_operators != null &&
-                                           Report.WarningLevel >= 2) {
-                                               ArrayList args = new ArrayList (2);
-                                               args.Add (new Argument (left, Argument.AType.Expression));
-                                               args.Add (new Argument (left, Argument.AType.Expression));
-                                               if (left_operators.OverloadResolve (ec, ref args, true, Location.Null) != null)
-                                                       Warning_UnintendedReferenceComparison (loc, "right", l);
-                                       }
+               protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
+               {
+                       Expression expr = ResolveOperator (ec);
+                       if (expr == null)
+                               Error_OperatorCannotBeApplied (left_orig, right_orig);
 
-                                       if (right_to_left && right_operators != null &&
-                                           Report.WarningLevel >= 2) {
-                                               ArrayList args = new ArrayList (2);
-                                               args.Add (new Argument (right, Argument.AType.Expression));
-                                               args.Add (new Argument (right, Argument.AType.Expression));
-                                               if (right_operators.OverloadResolve (ec, ref args, true, Location.Null) != null)
-                                                       Warning_UnintendedReferenceComparison (loc, "left", r);
-                                       }
+                       if (left == null || right == null)
+                               throw new InternalErrorException ("Invalid conversion");
 
-                                       //
-                                       // We are going to have to convert to an object to compare
-                                       //
-                                       if (l != TypeManager.object_type)
-                                               left = EmptyCast.Create (left, TypeManager.object_type);
-                                       if (r != TypeManager.object_type)
-                                               right = EmptyCast.Create (right, TypeManager.object_type);
+                       if (oper == Operator.BitwiseOr)
+                               CheckBitwiseOrOnSignExtended ();
 
-                                       return this;
+                       return expr;
+               }
+
+               //
+               // D operator + (D x, D y)
+               // D operator - (D x, D y)
+               //
+               Expression ResolveOperatorDelegateBinary (EmitContext ec, Type l, Type r)
+               {
+                       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;
                                }
+                       } else {
+                               if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral))
+                                       return null;
                        }
 
-                       // 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;
+                       MethodInfo method;
+                       ArrayList args = new ArrayList (2);
 
-                                               if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral)) {
-                                                       Error_OperatorCannotBeApplied ();
-                                                       return null;
-                                               }
+                       args = new ArrayList (2);
+                       args.Add (new Argument (left, Argument.AType.Expression));
+                       args.Add (new Argument (right, Argument.AType.Expression));
 
-                                               return new BinaryDelegate (l, method, args);
-                                       }
+                       if (oper == Operator.Addition) {
+                               if (TypeManager.delegate_combine_delegate_delegate == null) {
+                                       TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
+                                               TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
                                }
 
-                               //
-                               // 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);
+                               method = TypeManager.delegate_combine_delegate_delegate;
+                       } else {
+                               if (TypeManager.delegate_remove_delegate_delegate == null) {
+                                       TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
+                                               TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
                                }
+
+                               method = TypeManager.delegate_remove_delegate_delegate;
                        }
-                       
+
+                       return new BinaryDelegate (l, method, args);
+               }
+
+               //
+               // Enumeration operators
+               //
+               Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
+               {
                        //
-                       // Enumeration operators
+                       // bool operator == (E x, E y);
+                       // bool operator != (E x, E y);
+                       // bool operator < (E x, E y);
+                       // bool operator > (E x, E y);
+                       // bool operator <= (E x, E y);
+                       // bool operator >= (E x, E y);
                        //
-                       bool lie = TypeManager.IsEnumType (l);
-                       bool rie = TypeManager.IsEnumType (r);
-                       if (lie || rie){
-                               Expression temp;
+                       // E operator & (E x, E y);
+                       // E operator | (E x, E y);
+                       // E operator ^ (E x, E y);
+                       //
+                       // U operator - (E e, E f)
+                       // E operator - (E e, U x)
+                       //
+                       // E operator + (U x, E e)
+                       // E operator + (E e, U x)
+                       //
+                       if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
+                               (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
+                               return null;
 
-                               // 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;
-                                       }
+                       Expression ltemp = left;
+                       Expression rtemp = right;
+                       Type underlying_type;
 
-                                       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 (TypeManager.IsEqual (ltype, rtype)) {
+                               underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
 
-                               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 ();
+                               if (left is Constant)
+                                       left = ((Constant) left).ConvertExplicitly (false, underlying_type);
+                               else
+                                       left = EmptyCast.Create (left, underlying_type);
+
+                               if (right is Constant)
+                                       right = ((Constant) right).ConvertExplicitly (false, underlying_type);
+                               else
+                                       right = EmptyCast.Create (right, underlying_type);
+                       } else if (lenum) {
+                               if (oper != Operator.Subtraction && oper != Operator.Addition) {
+                                       Constant c = right as Constant;
+                                       if (c == null || !c.IsDefaultValue)
                                                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 ();
+                               underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
+                               if (left is Constant)
+                                       left = ((Constant) left).ConvertExplicitly (false, underlying_type);
+                               else
+                                       left = EmptyCast.Create (left, underlying_type);
+                       } else if (renum) {
+                               if (oper != Operator.Addition) {
+                                       Constant c = left as Constant;
+                                       if (c == null || !c.IsDefaultValue)
                                                return null;
-                                       }
-                                       type = l;
-                                       return this;
                                }
-                               Error_OperatorCannotBeApplied ();
+
+                               underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
+                               if (right is Constant)
+                                       right = ((Constant) right).ConvertExplicitly (false, underlying_type);
+                               else
+                                       right = EmptyCast.Create (right, underlying_type);
+                       } else {
                                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;
-                               }
+                       //
+                       // C# specification uses explicit cast syntax which means binary promotion
+                       // should happen, however it seems that csc does not do that
+                       //
+                       if (!DoBinaryOperatorPromotion (ec)) {
+                               left = ltemp;
+                               right = rtemp;
+                               return null;
+                       }
 
-                               Expression left_operators_e = l == TypeManager.bool_type ?
-                                       left : Convert.ImplicitUserConversion (ec, left, TypeManager.bool_type, loc);
-                               Expression right_operators_e = r == TypeManager.bool_type ?
-                                       right : Convert.ImplicitUserConversion (ec, right, TypeManager.bool_type, loc);
+                       Type res_type = null;
+                       if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
+                               Type promoted_type = lenum ? left.Type : right.Type;
+                               enum_conversion = Convert.ExplicitNumericConversion (
+                                       new EmptyExpression (promoted_type), underlying_type);
 
-                               if (left_operators_e != null && right_operators_e != null) {
-                                       left = left_operators_e;
-                                       right = right_operators_e;
-                                       type = TypeManager.bool_type;
-                                       return this;
-                               }
+                               if (oper == Operator.Subtraction && renum && lenum)
+                                       res_type = underlying_type;
+                               else if (oper == Operator.Addition && renum)
+                                       res_type = rtype;
+                               else
+                                       res_type = ltype;
+                       }
+                       
+                       Expression expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
+                       if (!is_compound || expr == null)
+                               return expr;
 
-                               Expression e = new ConditionalLogicalOperator (
-                                       oper == Operator.LogicalAnd, left, right, l, loc);
-                               return e.Resolve (ec);
-                       } 
+                       //
+                       // TODO: Need to corectly implemented Coumpound Assigment for all operators
+                       // Section: 7.16.2
+                       //
+                       if (Convert.ImplicitConversionExists (ec, left, rtype))
+                               return expr;
+
+                       if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
+                               return null;
 
-                       Expression orig_left = left;
-                       Expression orig_right = right;
+                       expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
+                       return expr;
+               }
 
+               //
+               // 7.9.6 Reference type equality operators
+               //
+               Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
+               {
                        //
-                       // operator & (bool x, bool y)
-                       // operator | (bool x, bool y)
-                       // operator ^ (bool x, bool y)
+                       // operator != (object a, object b)
+                       // operator == (object a, object b)
                        //
-                       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 ();
+                       // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
+
+                       if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
+                               return null;
+
+                       type = TypeManager.bool_type;
+                       GenericConstraints constraints;
+
+                       bool lgen = TypeManager.IsGenericParameter (l);
+
+                       if (TypeManager.IsEqual (l, r)) {
+                               if (lgen) {
+                                       //
+                                       // Only allow to compare same reference type parameter
+                                       //
+                                       constraints = TypeManager.GetTypeParameterConstraints (l);
+                                       if (constraints != null && constraints.IsReferenceType)
+                                               return this;
+
+                                       return null;
+                               }
+
+                               if (l == TypeManager.anonymous_method_type)
+                                       return null;
+
+                               if (TypeManager.IsValueType (l))
                                        return null;
-                               }
+
                                return this;
                        }
-                       
+
+                       bool rgen = TypeManager.IsGenericParameter (r);
+
                        //
-                       // Pointer comparison
+                       // a, Both operands are reference-type values or the value null
+                       // b, One operand is a value of type T where T is a type-parameter and
+                       // the other operand is the value null. Furthermore T does not have the
+                       // value type constrain
                        //
-                       if (l.IsPointer && r.IsPointer){
-                               if (oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
-                                   oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
-                                       type = TypeManager.bool_type;
+                       if (left is NullLiteral || right is NullLiteral) {
+                               if (lgen) {
+                                       constraints = TypeManager.GetTypeParameterConstraints (l);
+                                       if (constraints != null && constraints.HasValueTypeConstraint)
+                                               return null;
+
+                                       left = new BoxedCast (left, TypeManager.object_type);
                                        return this;
                                }
-                       }
 
-                       if (OverloadResolve_PredefinedIntegral (ec)) {
-                               if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
-                                       Error_OperatorAmbiguous (loc, oper, l, r);
-                                       return null;
+                               if (rgen) {
+                                       constraints = TypeManager.GetTypeParameterConstraints (r);
+                                       if (constraints != null && constraints.HasValueTypeConstraint)
+                                               return null;
+
+                                       right = new BoxedCast (right, TypeManager.object_type);
+                                       return this;
                                }
-                       } 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);
+                       }
+
+                       //
+                       // An interface is converted to the object before the
+                       // standard conversion is applied. It's not clear from the
+                       // standard but it looks like it works like that.
+                       //
+                       if (lgen) {
+                               constraints = TypeManager.GetTypeParameterConstraints (l);
+                               if (constraints == null || constraints.IsReferenceType)
                                        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);
+                       } else if (l.IsInterface) {
+                               l = TypeManager.object_type;
+                       } else if (l.IsValueType) {
+                               return null;
+                       }
+
+                       if (rgen) {
+                               constraints = TypeManager.GetTypeParameterConstraints (r);
+                               if (constraints == null || constraints.IsReferenceType)
                                        return null;
-                               }
-                       } else if (!OverloadResolve_PredefinedString (ec, oper)) {
-                               Error_OperatorCannotBeApplied ();
+                       } else if (r.IsInterface) {
+                               r = TypeManager.object_type;
+                       } else if (r.IsValueType) {
                                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;
+                       const string ref_comparison = "Possible unintended reference comparison. " +
+                               "Consider casting the {0} side of the expression to `string' to compare the values";
+
+                       //
+                       // A standard implicit conversion exists from the type of either
+                       // operand to the type of the other operand
+                       //
+                       if (Convert.ImplicitReferenceConversionExists (left, r)) {
+                               if (l == TypeManager.string_type)
+                                       Report.Warning (253, 2, loc, ref_comparison, "right");
+
+                               return this;
+                       }
 
-                       if (l == TypeManager.decimal_type || l == TypeManager.string_type || r == TypeManager.string_type) {
-                               Type lookup = l;
+                       if (Convert.ImplicitReferenceConversionExists (right, 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));
-                               ops = ops.OverloadResolve (ec, ref args, true, Location.Null);
-                               return new BinaryMethod (type, (MethodInfo)ops, args);
+                                       Report.Warning (252, 2, loc, ref_comparison, "left");
+
+                               return this;
                        }
 
-                       return this;
+                       return null;
                }
 
-               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;
+               Expression ResolveOperatorPointer (EmitContext ec, Type l, Type r)
+               {
+                       //
+                       // bool operator == (void* x, void* y);
+                       // bool operator != (void* x, void* y);
+                       // bool operator < (void* x, void* y);
+                       // bool operator > (void* x, void* y);
+                       // bool operator <= (void* x, void* y);
+                       // bool operator >= (void* x, void* y);
+                       //
+                       if ((oper & Operator.ComparisonMask) != 0) {
+                               Expression temp;
+                               if (!l.IsPointer) {
+                                       temp = Convert.ImplicitConversion (ec, left, r, left.Location);
+                                       if (temp == null)
+                                               return null;
+                                       left = temp;
+                               }
 
-                               case Operator.Addition:
-                               case Operator.Subtraction:
-                                       return left;
+                               if (!r.IsPointer) {
+                                       temp = Convert.ImplicitConversion (ec, right, l, right.Location);
+                                       if (temp == null)
+                                               return null;
+                                       right = temp;
+                               }
 
-                               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;
+                               type = TypeManager.bool_type;
+                               return this;
                        }
-                       Error_OperatorCannotBeApplied ();
-                       return null;
+
+                       if (pointer_operators == null)
+                               CreatePointerOperatorsTable ();
+
+                       return ResolveOperatorPredefined (ec, pointer_operators, false, null);
                }
 
-               public override Expression DoResolve (EmitContext ec)
+               //
+               // Build-in operators method overloading
+               //
+               protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
                {
-                       if (left == null)
-                               return null;
+                       PredefinedOperator best_operator = null;
+                       Type l = left.Type;
+                       Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
 
-                       if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
-                               left = ((ParenthesizedExpression) left).Expr;
-                               left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
-                               if (left == null)
-                                       return null;
+                       foreach (PredefinedOperator po in operators) {
+                               if ((po.OperatorsMask & oper_mask) == 0)
+                                       continue;
 
-                               if (left.eclass == ExprClass.Type) {
-                                       Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
-                                       return null;
+                               if (primitives_only) {
+                                       if (!po.IsPrimitiveApplicable (l))
+                                               continue;
+                               } else {
+                                       if (!po.IsApplicable (ec, left, right))
+                                               continue;
                                }
-                       } else
-                               left = left.Resolve (ec);
 
-                       if (left == null)
-                               return null;
+                               if (best_operator == null) {
+                                       best_operator = po;
+                                       if (primitives_only)
+                                               break;
 
-                       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))) {
+                                       continue;
+                               }
 
-                               // TODO: make a sense to resolve unreachable expression as we do for statement
-                               Report.Warning (429, 4, loc, "Unreachable expression code detected");
-                               return left;
+                               best_operator = po.ResolveBetterOperator (ec, left, right, best_operator);
+
+                               if (best_operator == null) {
+                                       Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
+                                               OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
+
+                                       best_operator = po;
+                                       break;
+                               }
                        }
 
-                       right = right.Resolve (ec);
-                       if (right == null)
+                       if (best_operator == null)
                                return null;
 
-                       eclass = ExprClass.Value;
-                       Constant rc = right as Constant;
+                       Expression expr = best_operator.ConvertResult (ec, this);
+                       if (enum_type == null)
+                               return expr;
 
-                       // 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;
+                       //
+                       // HACK: required by enum_conversion
+                       //
+                       expr.Type = enum_type;
+                       return EmptyCast.Create (expr, enum_type);
+               }
 
-                               right = rc = EnumLiftUp (rc, lc);
-                               if (rc == null)
-                                       return null;
-                       }
+               //
+               // Performs user-operator overloading
+               //
+               protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
+               {
+                       Operator user_oper;
+                       if (oper == Operator.LogicalAnd)
+                               user_oper = Operator.BitwiseAnd;
+                       else if (oper == Operator.LogicalOr)
+                               user_oper = Operator.BitwiseOr;
+                       else
+                               user_oper = oper;
 
-                       if (oper == Operator.BitwiseAnd) {
-                               if (rc != null && rc.IsZeroInteger) {
-                                       return lc is EnumConstant ?
-                                               new EnumConstant (rc, lc.Type):
-                                               rc;
-                               }
+                       string op = GetOperatorMetadataName (user_oper);
 
-                               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;
-                       }
+                       MethodGroupExpr union;
+                       MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
+                       if (!TypeManager.IsEqual (r, l)) {
+                               MethodGroupExpr right_operators = MemberLookup (
+                                       ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
+                               union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
+                       } else
+                               union = left_operators;
 
-                       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 (union == null)
+                               return null;
 
-#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
+                       ArrayList args = new ArrayList (2);
+                       Argument larg = new Argument (left);
+                       args.Add (larg);
+                       Argument rarg = new Argument (right);
+                       args.Add (rarg);
 
-                       // 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, "A comparison made to same variable. Did you mean to compare something else?");
+                       union = union.OverloadResolve (ec, ref args, true, loc);
+                       if (union == null)
+                               return null;
+
+                       Expression oper_expr;
+
+                       // TODO: CreateExpressionTree is allocated every time
+                       if (user_oper != oper) {
+                               oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
+                                       oper == Operator.LogicalAnd, loc).Resolve (ec);
+                       } else {
+                               oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
+
+                               //
+                               // This is used to check if a test 'x == null' can be optimized to a reference equals,
+                               // and not invoke user operator
+                               //
+                               if ((oper & Operator.EqualityMask) != 0) {
+                                       if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
+                                               (right is NullLiteral && IsBuildInEqualityOperator (l))) {
+                                               type = TypeManager.bool_type;
+                                               if (left is NullLiteral || right is NullLiteral)
+                                                       oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
+                                       } else if (union.DeclaringType == TypeManager.delegate_type && l != r) {
+                                               //
+                                               // Two System.Delegate(s) are never equal
+                                               //
+                                               return null;
+                                       }
                                }
-                               CheckUselessComparison (lc, right.Type);
-                               CheckUselessComparison (rc, left.Type);
                        }
 
-                       return ResolveOperator (ec);
+                       left = larg.Expr;
+                       right = rarg.Expr;
+                       return oper_expr;
                }
 
                public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
@@ -2651,6 +2950,12 @@ namespace Mono.CSharp {
                                type == TypeManager.uint32_type && value >= 0x100000000;
                }
 
+               static bool IsBuildInEqualityOperator (Type t)
+               {
+                       return t == TypeManager.object_type || t == TypeManager.string_type ||
+                               t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
+               }
+
                private static bool IsTypeIntegral (Type type)
                {
                        return type == TypeManager.uint64_type ||
@@ -2710,20 +3015,12 @@ namespace Mono.CSharp {
                                }
                                
                                if (((Constant) right).IsZeroInteger) {
-                                       left.Emit (ec);
-                                       if (my_on_true)
-                                               ig.Emit (OpCodes.Brtrue, target);
-                                       else
-                                               ig.Emit (OpCodes.Brfalse, target);
-                                       
+                                       left.EmitBranchable (ec, target, my_on_true);
                                        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);
-                                       
+                               }
+                               if (right.Type == TypeManager.bool_type) {
+                                       // right is a boolean, and it's not 'false' => it is 'true'
+                                       left.EmitBranchable (ec, target, !my_on_true);
                                        return;
                                }
 
@@ -2844,58 +3141,62 @@ namespace Mono.CSharp {
                                                ig.Emit (OpCodes.Blt, target);
                                break;
                        default:
-                               Console.WriteLine (oper);
-                               throw new Exception ("what is THAT");
+                               throw new InternalErrorException (oper.ToString ());
                        }
                }
                
                public override void Emit (EmitContext ec)
+               {
+                       EmitOperator (ec, left.Type);
+               }
+
+               protected virtual void EmitOperator (EmitContext ec, Type l)
                {
                        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 ();
+                       if ((oper & Operator.LogicalMask) != 0) {
+                               Label load_result = ig.DefineLabel ();
                                Label end = ig.DefineLabel ();
 
-                               left.EmitBranchable (ec, load_one, true);
+                               bool is_or = oper == Operator.LogicalOr;
+                               left.EmitBranchable (ec, load_result, is_or);
                                right.Emit (ec);
-                               ig.Emit (OpCodes.Br, end);
+                               ig.Emit (OpCodes.Br_S, end);
                                
-                               ig.MarkLabel (load_one);
-                               ig.Emit (OpCodes.Ldc_I4_1);
+                               ig.MarkLabel (load_result);
+                               ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
                                ig.MarkLabel (end);
                                return;
                        }
 
                        left.Emit (ec);
+
+                       //
+                       // Optimize zero-based operations
+                       //
+                       // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
+                       //
+                       if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
+                               Constant rc = right as Constant;
+                               if (rc != null && rc.IsDefaultValue) {
+                                       return;
+                               }
+                       }
+
                        right.Emit (ec);
 
-                       bool is_unsigned = IsUnsigned (left.Type);
+                       OpCode opcode;
                        
                        switch (oper){
                        case Operator.Multiply:
                                if (ec.CheckState){
                                        if (l == TypeManager.int32_type || l == TypeManager.int64_type)
                                                opcode = OpCodes.Mul_Ovf;
-                                       else if (is_unsigned)
+                                       else if (!IsFloat (l))
                                                opcode = OpCodes.Mul_Ovf_Un;
                                        else
                                                opcode = OpCodes.Mul;
@@ -2905,14 +3206,14 @@ namespace Mono.CSharp {
                                break;
                                
                        case Operator.Division:
-                               if (is_unsigned)
+                               if (IsUnsigned (l))
                                        opcode = OpCodes.Div_Un;
                                else
                                        opcode = OpCodes.Div;
                                break;
                                
                        case Operator.Modulus:
-                               if (is_unsigned)
+                               if (IsUnsigned (l))
                                        opcode = OpCodes.Rem_Un;
                                else
                                        opcode = OpCodes.Rem;
@@ -2922,7 +3223,7 @@ namespace Mono.CSharp {
                                if (ec.CheckState){
                                        if (l == TypeManager.int32_type || l == TypeManager.int64_type)
                                                opcode = OpCodes.Add_Ovf;
-                                       else if (is_unsigned)
+                                       else if (!IsFloat (l))
                                                opcode = OpCodes.Add_Ovf_Un;
                                        else
                                                opcode = OpCodes.Add;
@@ -2934,7 +3235,7 @@ namespace Mono.CSharp {
                                if (ec.CheckState){
                                        if (l == TypeManager.int32_type || l == TypeManager.int64_type)
                                                opcode = OpCodes.Sub_Ovf;
-                                       else if (is_unsigned)
+                                       else if (!IsFloat (l))
                                                opcode = OpCodes.Sub_Ovf_Un;
                                        else
                                                opcode = OpCodes.Sub;
@@ -2943,7 +3244,7 @@ namespace Mono.CSharp {
                                break;
 
                        case Operator.RightShift:
-                               if (is_unsigned)
+                               if (IsUnsigned (l))
                                        opcode = OpCodes.Shr_Un;
                                else
                                        opcode = OpCodes.Shr;
@@ -2965,23 +3266,21 @@ namespace Mono.CSharp {
                                break;
 
                        case Operator.LessThan:
-                               if (is_unsigned)
+                               if (IsUnsigned (l))
                                        opcode = OpCodes.Clt_Un;
                                else
                                        opcode = OpCodes.Clt;
                                break;
 
                        case Operator.GreaterThan:
-                               if (is_unsigned)
+                               if (IsUnsigned (l))
                                        opcode = OpCodes.Cgt_Un;
                                else
                                        opcode = OpCodes.Cgt;
                                break;
 
                        case Operator.LessThanOrEqual:
-                               Type lt = left.Type;
-                               
-                               if (is_unsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
+                               if (IsUnsigned (l) || IsFloat (l))
                                        ig.Emit (OpCodes.Cgt_Un);
                                else
                                        ig.Emit (OpCodes.Cgt);
@@ -2991,9 +3290,7 @@ namespace Mono.CSharp {
                                break;
 
                        case Operator.GreaterThanOrEqual:
-                               Type le = left.Type;
-                               
-                               if (is_unsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
+                               if (IsUnsigned (l) || IsFloat (l))
                                        ig.Emit (OpCodes.Clt_Un);
                                else
                                        ig.Emit (OpCodes.Clt);
@@ -3016,11 +3313,28 @@ namespace Mono.CSharp {
                                break;
 
                        default:
-                               throw new Exception ("This should not happen: Operator = "
-                                                    + oper.ToString ());
+                               throw new InternalErrorException (oper.ToString ());
                        }
 
                        ig.Emit (opcode);
+
+                       //
+                       // Nullable enum could require underlying type cast and we cannot simply wrap binary
+                       // expression because that would wrap lifted binary operation
+                       //
+                       if (enum_conversion != null)
+                               enum_conversion.Emit (ec);
+               }
+
+               public override void EmitSideEffect (EmitContext ec)
+               {
+                       if ((oper & Operator.LogicalMask) != 0 ||
+                           (ec.CheckState && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
+                               base.EmitSideEffect (ec);
+                       } else {
+                               left.EmitSideEffect (ec);
+                               right.EmitSideEffect (ec);
+                       }
                }
 
                protected override void CloneTo (CloneContext clonectx, Expression t)
@@ -3030,13 +3344,20 @@ namespace Mono.CSharp {
                        target.left = left.Clone (clonectx);
                        target.right = right.Clone (clonectx);
                }
-
+               
                public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       return CreateExpressionTree (ec, null);
+               }
+
+               Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)                
                {
                        string method_name;
+                       bool lift_arg = false;
+                       
                        switch (oper) {
                        case Operator.Addition:
-                               if (ec.CheckState)
+                               if (method == null && ec.CheckState && !IsFloat (type))
                                        method_name = "AddChecked";
                                else
                                        method_name = "Add";
@@ -3044,17 +3365,67 @@ namespace Mono.CSharp {
                        case Operator.BitwiseAnd:
                                method_name = "And";
                                break;
-                       case Operator.LogicalAnd:
-                               method_name = "AndAlso";
-                               break;
-                               
                        case Operator.BitwiseOr:
                                method_name = "Or";
                                break;
-
+                       case Operator.Division:
+                               method_name = "Divide";
+                               break;
+                       case Operator.Equality:
+                               method_name = "Equal";
+                               lift_arg = true;
+                               break;
+                       case Operator.ExclusiveOr:
+                               method_name = "ExclusiveOr";
+                               break;                          
+                       case Operator.GreaterThan:
+                               method_name = "GreaterThan";
+                               lift_arg = true;
+                               break;
+                       case Operator.GreaterThanOrEqual:
+                               method_name = "GreaterThanOrEqual";
+                               lift_arg = true;
+                               break;
+                       case Operator.Inequality:
+                               method_name = "NotEqual";
+                               lift_arg = true;
+                               break;
+                       case Operator.LeftShift:
+                               method_name = "LeftShift";
+                               break;
+                       case Operator.LessThan:
+                               method_name = "LessThan";
+                               lift_arg = true;
+                               break;
+                       case Operator.LessThanOrEqual:
+                               method_name = "LessThanOrEqual";
+                               lift_arg = true;
+                               break;
+                       case Operator.LogicalAnd:
+                               method_name = "AndAlso";
+                               break;
                        case Operator.LogicalOr:
                                method_name = "OrElse";
                                break;
+                       case Operator.Modulus:
+                               method_name = "Modulo";
+                               break;
+                       case Operator.Multiply:
+                               if (method == null && ec.CheckState && !IsFloat (type))
+                                       method_name = "MultiplyChecked";
+                               else
+                                       method_name = "Multiply";
+                               break;
+                       case Operator.RightShift:
+                               method_name = "RightShift";
+                               break;
+                       case Operator.Subtraction:
+                               if (method == null && ec.CheckState && !IsFloat (type))
+                                       method_name = "SubtractChecked";
+                               else
+                                       method_name = "Subtract";
+                               break;
+
                        default:
                                throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
                        }
@@ -3062,6 +3433,13 @@ namespace Mono.CSharp {
                        ArrayList args = new ArrayList (2);
                        args.Add (new Argument (left.CreateExpressionTree (ec)));
                        args.Add (new Argument (right.CreateExpressionTree (ec)));
+                       if (method != null) {
+                               if (lift_arg)
+                                       args.Add (new Argument (new BoolConstant (false, loc)));
+                               
+                               args.Add (new Argument (method.CreateExpressionTree (ec)));
+                       }
+                       
                        return CreateExpressionFactoryCall (method_name, args);
                }
        }
@@ -3117,7 +3495,45 @@ namespace Mono.CSharp {
                        Append (ec, left);
                        Append (ec, right);
                }
-               
+
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       Argument arg = (Argument) arguments [0];
+                       return CreateExpressionAddCall (ec, arg, arg.Expr.CreateExpressionTree (ec), 1);
+               }
+
+               //
+               // Creates nested calls tree from an array of arguments used for IL emit
+               //
+               Expression CreateExpressionAddCall (EmitContext ec, Argument left, Expression left_etree, int pos)
+               {
+                       ArrayList concat_args = new ArrayList (2);
+                       ArrayList add_args = new ArrayList (3);
+
+                       concat_args.Add (left);
+                       add_args.Add (new Argument (left_etree));
+
+                       concat_args.Add (arguments [pos]);
+                       add_args.Add (new Argument (((Argument) arguments [pos]).Expr.CreateExpressionTree (ec)));
+
+                       MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
+                       if (method == null)
+                               return null;
+
+                       method = method.OverloadResolve (ec, ref concat_args, false, loc);
+                       if (method == null)
+                               return null;
+
+                       add_args.Add (new Argument (method.CreateExpressionTree (ec)));
+
+                       Expression expr = CreateExpressionFactoryCall ("Add", add_args);
+                       if (++pos == arguments.Count)
+                               return expr;
+
+                       left = new Argument (new EmptyExpression (method.Type));
+                       return CreateExpressionAddCall (ec, left, expr, pos);
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        return this;
@@ -3144,37 +3560,23 @@ namespace Mono.CSharp {
                                // Multiple (3+) concatenation are resolved as multiple StringConcat instances
                                //
                                StringConcat concat_oper = operand as StringConcat;
-                               if (concat_oper != null) {
-                                       arguments.AddRange (concat_oper.arguments);
-                                       return;
-                               }
-                       }
-                       
-                       //
-                       // Conversion to object
-                       //
-                       if (operand.Type != TypeManager.string_type) {
-                               Expression expr = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
-                               if (expr == null) {
-                                       Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
+                               if (concat_oper != null) {
+                                       arguments.AddRange (concat_oper.arguments);
                                        return;
                                }
-                               operand = expr;
                        }
-                       
+
                        arguments.Add (new Argument (operand));
                }
 
-               Expression CreateConcatInvocation ()
+               Expression CreateConcatMemberExpression ()
                {
-                       return new Invocation (
-                               new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc),
-                               arguments, true);
+                       return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
                }
 
                public override void Emit (EmitContext ec)
                {
-                       Expression concat = CreateConcatInvocation ();
+                       Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
                        concat = concat.Resolve (ec);
                        if (concat != null)
                                concat.Emit (ec);
@@ -3227,92 +3629,60 @@ namespace Mono.CSharp {
        
        //
        // User-defined conditional logical operator
-       public class ConditionalLogicalOperator : Expression {
-               Expression left, right;
-               bool is_and;
+       //
+       public class ConditionalLogicalOperator : UserOperatorCall {
+               readonly bool is_and;
+               Expression oper;
 
-               public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
+               public ConditionalLogicalOperator (MethodGroupExpr oper_method, ArrayList arguments,
+                       ExpressionTreeExpression expr_tree, bool is_and, Location loc)
+                       : base (oper_method, arguments, expr_tree, 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)
                {
-                       MethodGroupExpr operator_group;
-
-                       operator_group = MethodLookup (ec.ContainerType, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc) as MethodGroupExpr;
-                       if (operator_group == null) {
-                               Error19 ();
-                               return null;
-                       }
-
-                       left_temp = new LocalTemporary (type);
-
-                       ArrayList arguments = new ArrayList (2);
-                       arguments.Add (new Argument (left_temp, Argument.AType.Expression));
-                       arguments.Add (new Argument (right, Argument.AType.Expression));
-                       operator_group = operator_group.OverloadResolve (ec, ref arguments, false, loc);
-                       if (operator_group == null) {
-                               Error19 ();
-                               return null;
-                       }
-
-                       MethodInfo method = (MethodInfo)operator_group;
-                       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));
+                       MethodInfo method = (MethodInfo)mg;
+                       type = TypeManager.TypeToCoreType (method.ReturnType);
+                       ParameterData pd = TypeManager.GetParameterData (method);
+                       if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
+                               Report.Error (217, loc,
+                                       "A user-defined operator `{0}' must have parameters and return values of the same type in order to be applicable as a short circuit operator",
+                                       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 ();
+                       Expression left_dup = new EmptyExpression (type);
+                       Expression op_true = GetOperatorTrue (ec, left_dup, loc);
+                       Expression op_false = GetOperatorFalse (ec, left_dup, loc);
+                       if (op_true == null || op_false == null) {
+                               Report.Error (218, loc,
+                                       "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
+                                       TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
                                return null;
                        }
 
+                       oper = is_and ? op_false : op_true;
+                       eclass = ExprClass.Value;
                        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);
+                       //
+                       // Emit and duplicate left argument
+                       //
+                       ((Argument)arguments [0]).Expr.Emit (ec);
+                       ig.Emit (OpCodes.Dup);
+                       arguments.RemoveAt (0);
 
-                       (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);
+                       oper.EmitBranchable (ec, end_target, true);
+                       base.Emit (ec);
                        ig.MarkLabel (end_target);
-
-                       // We release 'left_temp' here since 'op' may refer to it too
-                       left_temp.Release (ec);
                }
        }
 
@@ -3332,6 +3702,12 @@ namespace Mono.CSharp {
                        is_add = is_addition;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       Error_PointerInsideExpressionTree ();
+                       return null;
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        eclass = ExprClass.Variable;
@@ -3444,6 +3820,15 @@ namespace Mono.CSharp {
                        }
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       ArrayList args = new ArrayList (3);
+                       args.Add (new Argument (expr.CreateExpressionTree (ec)));
+                       args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
+                       args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
+                       return CreateExpressionFactoryCall ("Condition", args);
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        expr = expr.Resolve (ec);
@@ -3451,11 +3836,6 @@ namespace Mono.CSharp {
                        if (expr == null)
                                return null;
 
-#if GMCS_SOURCE
-                       if (TypeManager.IsNullableValueType (expr.Type))
-                               return new Nullable.LiftedConditional (expr, true_expr, false_expr, loc).Resolve (ec);
-#endif
-                       
                        if (expr.Type != TypeManager.bool_type){
                                expr = Expression.ResolveBoolean (
                                        ec, expr, loc);
@@ -3542,6 +3922,14 @@ namespace Mono.CSharp {
 
                        expr.EmitBranchable (ec, false_target, false);
                        true_expr.Emit (ec);
+
+                       if (type.IsInterface) {
+                               LocalBuilder temp = ec.GetTemporaryLocal (type);
+                               ig.Emit (OpCodes.Stloc, temp);
+                               ig.Emit (OpCodes.Ldloc, temp);
+                               ec.FreeTemporaryLocal (temp, type);
+                       }
+
                        ig.Emit (OpCodes.Br, end_target);
                        ig.MarkLabel (false_target);
                        false_expr.Emit (ec);
@@ -3575,6 +3963,11 @@ namespace Mono.CSharp {
                        Emit (ec, false);
                }
 
+               public override void EmitSideEffect (EmitContext ec)
+               {
+                       // do nothing
+               }
+
                //
                // This method is used by parameters that are references, that are
                // being passed as references:  we only want to pass the pointer (that
@@ -3634,8 +4027,13 @@ namespace Mono.CSharp {
                        source.Emit (ec);
 
                        // HACK: variable is already emitted when source is an initializer 
-                       if (source is NewInitialize)
+                       if (source is NewInitialize) {
+                               if (leave_copy) {
+                                       Variable.EmitInstance (ec);
+                                       Variable.Emit (ec);
+                               }
                                return;
+                       }
 
                        if (leave_copy) {
                                ig.Emit (OpCodes.Dup);
@@ -3720,6 +4118,13 @@ namespace Mono.CSharp {
                        }
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       ArrayList arg = new ArrayList (1);
+                       arg.Add (new Argument (this));
+                       return CreateExpressionFactoryCall ("Constant", arg);
+               }
+
                protected Expression DoResolveBase (EmitContext ec)
                {
                        type = local_info.VariableType;
@@ -3778,7 +4183,8 @@ namespace Mono.CSharp {
                        if (type == null) {
                                VarExpr ve = local_info.Type as VarExpr;
                                if (ve != null) {
-                                       ve.DoResolveLValue (ec, right_side);
+                                       if (!ve.InferType (ec, right_side))
+                                               return null;
                                        type = local_info.VariableType = ve.Type;
                                }
                        }
@@ -4117,6 +4523,9 @@ namespace Mono.CSharp {
 
                public bool Resolve (EmitContext ec, Location loc)
                {
+                       if (Expr == null)
+                               return false;
+
                        using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
                                // Verify that the argument is readable
                                if (ArgType != AType.Out)
@@ -4165,7 +4574,7 @@ namespace Mono.CSharp {
        /// </summary>
        public class Invocation : ExpressionStatement {
                protected ArrayList Arguments;
-               Expression expr;
+               protected Expression expr;
                protected MethodGroupExpr mg;
                bool arguments_resolved;
                
@@ -4182,7 +4591,8 @@ namespace Mono.CSharp {
                                this.expr = expr;
                        
                        Arguments = arguments;
-                       loc = expr.Location;
+                       if (expr != null)
+                               loc = expr.Location;
                }
 
                public Invocation (Expression expr, ArrayList arguments, bool arguments_resolved)
@@ -4191,36 +4601,32 @@ namespace Mono.CSharp {
                        this.arguments_resolved = arguments_resolved;
                }
 
-               public static string FullMethodDesc (MethodBase mb)
+               public override Expression CreateExpressionTree (EmitContext ec)
                {
-                       if (mb == null)
-                               return "";
+                       ArrayList args;
 
-                       StringBuilder sb;
-                       if (mb is MethodInfo) {
-                               sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
-                               sb.Append (" ");
+                       //
+                       // Special conversion for nested expression trees
+                       //
+                       if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
+                               args = new ArrayList (1);
+                               args.Add (new Argument (this));
+                               return CreateExpressionFactoryCall ("Quote", args);
                        }
-                       else
-                               sb = new StringBuilder ();
-
-                       sb.Append (TypeManager.CSharpSignature (mb));
-                       return sb.ToString ();
-               }
 
-               public override Expression CreateExpressionTree (EmitContext ec)
-               {
-                       ArrayList args = new ArrayList (Arguments.Count + 3);
+                       args = new ArrayList (Arguments == null ? 2 : Arguments.Count + 2);
                        if (mg.IsInstance)
                                args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
                        else
-                               args.Add (new Argument (new NullConstant (loc).CreateExpressionTree (ec)));
+                               args.Add (new Argument (new NullLiteral (loc)));
 
                        args.Add (new Argument (mg.CreateExpressionTree (ec)));
-                       foreach (Argument a in Arguments) {
-                               Expression e = a.Expr.CreateExpressionTree (ec);
-                               if (e != null)
-                                       args.Add (new Argument (e));
+                       if (Arguments != null) {
+                               foreach (Argument a in Arguments) {
+                                       Expression e = a.Expr.CreateExpressionTree (ec);
+                                       if (e != null)
+                                               args.Add (new Argument (e));
+                               }
                        }
 
                        return CreateExpressionFactoryCall ("Call", args);
@@ -4244,9 +4650,21 @@ namespace Mono.CSharp {
                                        return (new DelegateInvocation (
                                                expr_resolved, Arguments, loc)).Resolve (ec);
                                }
+
+                               MemberExpr me = expr_resolved as MemberExpr;
+                               if (me == null) {
+                                       expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
+                                       return null;
+                               }
                                
-                               expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
-                               return null;
+                               mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name, loc);
+                               if (mg == null) {
+                                       Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
+                                               expr_resolved.GetSignatureForError ());
+                                       return null;
+                               }
+
+                               ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
                        }
 
                        //
@@ -4455,25 +4873,6 @@ namespace Mono.CSharp {
 
                        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
@@ -4840,7 +5239,7 @@ namespace Mono.CSharp {
                        if (t == TypeManager.decimal_type)
                                return new DecimalConstant (0, Location.Null);
                        if (TypeManager.IsEnumType (t))
-                               return new EnumConstant (Constantify (TypeManager.EnumToUnderlying (t)), t);
+                               return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
 
                        return null;
                }
@@ -4867,6 +5266,28 @@ namespace Mono.CSharp {
                        Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
                        return cast.Resolve (ec);
                }
+
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       ArrayList args = Arguments == null ?
+                               new ArrayList (1) : new ArrayList (Arguments.Count + 1);
+
+                       if (method == null) {
+                               args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
+                       } else {
+                               args.Add (new Argument (method.CreateExpressionTree (ec)));
+                               if (Arguments != null) {
+                                       Expression expr;
+                                       foreach (Argument a in Arguments) {
+                                               expr = a.Expr.CreateExpressionTree (ec);
+                                               if (expr != null)
+                                                       args.Add (new Argument (expr));
+                                       }
+                               }
+                       }
+
+                       return CreateExpressionFactoryCall ("New", args);
+               }
                
                public override Expression DoResolve (EmitContext ec)
                {
@@ -4936,6 +5357,14 @@ namespace Mono.CSharp {
                                        return null;
                                }
 
+                               if (TypeManager.activator_create_instance == null) {
+                                       Type activator_type = TypeManager.CoreLookupType ("System", "Activator", Kind.Class, true);
+                                       if (activator_type != null) {
+                                               TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
+                                                       activator_type, "CreateInstance", loc, Type.EmptyTypes);
+                                       }
+                               }
+
                                is_type_parameter = true;
                                eclass = ExprClass.Value;
                                return this;
@@ -5191,7 +5620,7 @@ namespace Mono.CSharp {
        ///   specified but where initialization data is mandatory.
        /// </remarks>
        public class ArrayCreation : Expression {
-               Expression requested_base_type;
+               FullNamedExpression requested_base_type;
                ArrayList initializers;
 
                //
@@ -5214,7 +5643,7 @@ namespace Mono.CSharp {
                int const_initializers_count;
                bool only_constant_initializers;
                
-               public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
+               public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
                {
                        this.requested_base_type = requested_base_type;
                        this.initializers = initializers;
@@ -5229,7 +5658,7 @@ namespace Mono.CSharp {
                        }
                }
 
-               public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
+               public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
                {
                        this.requested_base_type = requested_base_type;
                        this.initializers = initializers;
@@ -5244,19 +5673,6 @@ namespace Mono.CSharp {
                        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 `]'");
@@ -5347,15 +5763,26 @@ namespace Mono.CSharp {
 
                        return true;
                }
-               
+
                public override Expression CreateExpressionTree (EmitContext ec)
                {
+                       ArrayList args;
+
                        if (dimensions != 1) {
-                               Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
-                               return null;
+                               if (initializers != null) {
+                                       Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
+                                       return null;
+                               }
+
+                               args = new ArrayList (arguments.Count + 1);
+                               args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
+                               foreach (Argument a in arguments)
+                                       args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
+
+                               return CreateExpressionFactoryCall ("NewArrayBounds", args);
                        }
 
-                       ArrayList args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
+                       args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
                        args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
                        if (array_data != null) {
                                foreach (Expression e in array_data)
@@ -5388,12 +5815,22 @@ namespace Mono.CSharp {
 
                }
 
+               Expression first_emit;
+               LocalTemporary first_emit_temp;
+
                protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
                {
                        element = element.Resolve (ec);
                        if (element == null)
                                return null;
 
+                       if (element is CompoundAssign.Helper) {
+                               if (first_emit != null)
+                                       throw new InternalErrorException ("Can only handle one mutator at a time");
+                               first_emit = element;
+                               element = first_emit_temp = new LocalTemporary (element.Type);
+                       }
+
                        return Convert.ImplicitConversionRequired (
                                ec, element, array_element_type, loc);
                }
@@ -5525,8 +5962,8 @@ namespace Mono.CSharp {
                        byte [] element;
                        int count = array_data.Count;
 
-                       if (array_element_type.IsEnum)
-                               array_element_type = TypeManager.EnumToUnderlying (array_element_type);
+                       if (TypeManager.IsEnumType (array_element_type))
+                               array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
                        
                        factor = GetTypeSize (array_element_type);
                        if (factor == 0)
@@ -5673,6 +6110,15 @@ namespace Mono.CSharp {
                //
                void EmitStaticInitializers (EmitContext ec)
                {
+                       // FIXME: This should go to Resolve !
+                       if (TypeManager.void_initializearray_array_fieldhandle == null) {
+                               TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
+                                       TypeManager.runtime_helpers_type, "InitializeArray", loc,
+                                       TypeManager.array_type, TypeManager.runtime_field_handle_type);
+                               if (TypeManager.void_initializearray_array_fieldhandle == null)
+                                       return;
+                       }
+
                        //
                        // First, the static data
                        //
@@ -5781,6 +6227,11 @@ namespace Mono.CSharp {
                {
                        ILGenerator ig = ec.ig;
 
+                       if (first_emit != null) {
+                               first_emit.Emit (ec);
+                               first_emit_temp.Store (ec);
+                       }
+
                        foreach (Argument a in arguments)
                                a.Emit (ec);
 
@@ -5804,7 +6255,10 @@ namespace Mono.CSharp {
                                        EmitDynamicInitializers (ec, false);
                        } else {
                                EmitDynamicInitializers (ec, true);
-                       }                               
+                       }
+
+                       if (first_emit_temp != null)
+                               first_emit_temp.Release (ec);
                }
 
                public override bool GetAttributableValue (Type value_type, out object value)
@@ -5849,7 +6303,7 @@ namespace Mono.CSharp {
                        ArrayCreation target = (ArrayCreation) t;
 
                        if (requested_base_type != null)
-                               target.requested_base_type = requested_base_type.Clone (clonectx);
+                               target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
 
                        if (arguments != null){
                                target.arguments = new ArrayList (arguments.Count);
@@ -5859,8 +6313,16 @@ namespace Mono.CSharp {
 
                        if (initializers != null){
                                target.initializers = new ArrayList (initializers.Count);
-                               foreach (Expression initializer in initializers)
-                                       target.initializers.Add (initializer.Clone (clonectx));
+                               foreach (object initializer in initializers)
+                                       if (initializer is ArrayList) {
+                                               ArrayList this_al = (ArrayList)initializer;
+                                               ArrayList al = new ArrayList (this_al.Count);
+                                               target.initializers.Add (al);
+                                               foreach (Expression e in this_al)
+                                                       al.Add (e.Clone (clonectx));
+                                       } else {
+                                               target.initializers.Add (((Expression)initializer).Clone (clonectx));
+                                       }
                        }
                }
        }
@@ -6173,6 +6635,11 @@ namespace Mono.CSharp {
                        this.loc = loc;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       throw new NotSupportedException ("ET");
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        eclass = ExprClass.Variable;
@@ -6261,29 +6728,6 @@ namespace Mono.CSharp {
                }
        }
 
-       //
-       // 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>
@@ -6297,8 +6741,19 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       ArrayList args = new ArrayList (2);
+                       args.Add (new Argument (this));
+                       args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
+                       return CreateExpressionFactoryCall ("Constant", args);
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
+                       if (eclass != ExprClass.Invalid)
+                               return this;
+
                        TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
                        if (texpr == null)
                                return null;
@@ -6316,6 +6771,17 @@ namespace Mono.CSharp {
                        }
 
                        type = TypeManager.type_type;
+
+                       return DoResolveBase ();
+               }
+
+               protected Expression DoResolveBase ()
+               {
+                       if (TypeManager.system_type_get_type_from_handle == null) {
+                               TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
+                                       TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_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;
@@ -6358,8 +6824,8 @@ namespace Mono.CSharp {
                protected override void CloneTo (CloneContext clonectx, Expression t)
                {
                        TypeOf target = (TypeOf) t;
-
-                       target.QueriedType = QueriedType.Clone (clonectx);
+                       if (QueriedType != null)
+                               target.QueriedType = QueriedType.Clone (clonectx);
                }
        }
 
@@ -6376,40 +6842,145 @@ namespace Mono.CSharp {
                {
                        type = TypeManager.type_type;
                        typearg = TypeManager.void_type;
-                       // See description in TypeOf.
-                       eclass = ExprClass.Value;
-                       return this;
+
+                       return DoResolveBase ();
+               }
+       }
+
+       class TypeOfMethodInfo : TypeOfMethod
+       {
+               public TypeOfMethodInfo (MethodBase method, Location loc)
+                       : base (method, loc)
+               {
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       type = typeof (MethodInfo);
+                       return base.DoResolve (ec);
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) method);
+                       base.Emit (ec);
+                       ec.ig.Emit (OpCodes.Castclass, type);
                }
        }
 
-       internal class TypeOfMethod : Expression
+       class TypeOfConstructorInfo : TypeOfMethod
        {
-               readonly MethodGroupExpr method;
-               static MethodInfo get_type_from_handle;
+               public TypeOfConstructorInfo (MethodBase method, Location loc)
+                       : base (method, loc)
+               {
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       type = typeof (ConstructorInfo);
+                       return base.DoResolve (ec);
+               }
 
-               static TypeOfMethod ()
+               public override void Emit (EmitContext ec)
                {
-                       get_type_from_handle = typeof (MethodBase).GetMethod ("GetMethodFromHandle",
-                               new Type [] { TypeManager.runtime_method_handle_type });
+                       ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
+                       base.Emit (ec);
+                       ec.ig.Emit (OpCodes.Castclass, type);
                }
+       }
+
+       abstract class TypeOfMethod : Expression
+       {
+               protected readonly MethodBase method;
 
-               public TypeOfMethod (MethodGroupExpr method)
+               protected TypeOfMethod (MethodBase method, Location loc)
                {
                        this.method = method;
-                       loc = method.Location;
+                       this.loc = loc;
+               }
+
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       ArrayList args = new ArrayList (2);
+                       args.Add (new Argument (this));
+                       args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
+                       return CreateExpressionFactoryCall ("Constant", args);
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
+                       MethodInfo mi = is_generic ?
+                               TypeManager.methodbase_get_type_from_handle_generic :
+                               TypeManager.methodbase_get_type_from_handle;
+
+                       if (mi == null) {
+                               Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
+                               Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
+
+                               if (t == null || handle_type == null)
+                                       return null;
+
+                               mi = TypeManager.GetPredefinedMethod (t, "GetMethodFromHandle", loc,
+                                       is_generic ?
+                                       new Type[] { handle_type, TypeManager.runtime_handle_type } :
+                                       new Type[] { handle_type } );
+
+                               if (is_generic)
+                                       TypeManager.methodbase_get_type_from_handle_generic = mi;
+                               else
+                                       TypeManager.methodbase_get_type_from_handle = mi;
+                       }
+
+                       eclass = ExprClass.Value;
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
+                       MethodInfo mi;
+                       if (is_generic) {
+                               mi = TypeManager.methodbase_get_type_from_handle_generic;
+                               ec.ig.Emit (OpCodes.Ldtoken, method.DeclaringType);
+                       } else {
+                               mi = TypeManager.methodbase_get_type_from_handle;
+                       }
+
+                       ec.ig.Emit (OpCodes.Call, mi);
+               }
+       }
+
+       internal class TypeOfField : Expression
+       {
+               readonly FieldInfo field;
+
+               public TypeOfField (FieldInfo field, Location loc)
+               {
+                       this.field = field;
+                       this.loc = loc;
                }
 
                public override Expression DoResolve (EmitContext ec)
                {
-                       type = typeof (MethodBase);
+                       if (TypeManager.fieldinfo_get_field_from_handle == null) {
+                               Type t = TypeManager.CoreLookupType ("System.Reflection", "FieldInfo", Kind.Class, true);
+                               Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeFieldHandle", Kind.Class, true);
+
+                               if (t != null && handle_type != null)
+                                       TypeManager.fieldinfo_get_field_from_handle = TypeManager.GetPredefinedMethod (t,
+                                               "GetFieldFromHandle", loc, handle_type);
+                       }
+
+                       type = typeof (FieldInfo);
                        eclass = ExprClass.Value;
                        return this;
                }
 
                public override void Emit (EmitContext ec)
                {
-                       ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo)method);
-                       ec.ig.Emit (OpCodes.Call, get_type_from_handle);
+                       ec.ig.Emit (OpCodes.Ldtoken, field);
+                       ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
                }
        }
 
@@ -6426,22 +6997,21 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       Error_PointerInsideExpressionTree ();
+                       return null;
+               }
+
                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);
+                       if (texpr == null)
                                return null;
-                       }
-#endif
 
                        type_queried = texpr.Type;
-                       if (type_queried.IsEnum)
-                               type_queried = TypeManager.EnumToUnderlying (type_queried);
+                       if (TypeManager.IsEnumType (type_queried))
+                               type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
 
                        if (type_queried == TypeManager.void_type) {
                                Expression.Error_VoidInvalidInTheContext (loc);
@@ -6453,14 +7023,14 @@ namespace Mono.CSharp {
                                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));
+                       if (!TypeManager.VerifyUnManaged (type_queried, loc)){
                                return null;
                        }
 
-                       if (!TypeManager.VerifyUnManaged (type_queried, loc)){
-                               return null;
+                       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));
                        }
                        
                        type = TypeManager.int32_type;
@@ -6486,83 +7056,73 @@ namespace Mono.CSharp {
        /// <summary>
        ///   Implements the qualified-alias-member (::) expression.
        /// </summary>
-       public class QualifiedAliasMember : Expression
+       public class QualifiedAliasMember : MemberAccess
        {
-               string alias, identifier;
+               readonly string alias;
+
+               public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
+                       : base (null, identifier, targs, l)
+               {
+                       this.alias = alias;
+               }
 
                public QualifiedAliasMember (string alias, string identifier, Location l)
+                       : base (null, identifier, 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);
+                       if (alias == "global") {
+                               expr = RootNamespace.Global;
+                               return base.ResolveAsTypeStep (ec, silent);
+                       }
 
                        int errors = Report.Errors;
-                       FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
-                       if (fne == null) {
+                       expr = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
+                       if (expr == 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)
+                       FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
+                       if (fne == 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);
+                       if (expr.eclass == ExprClass.Type) {
+                               if (!silent) {
+                                       Report.Error (431, loc,
+                                               "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
+                               }
                                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;
+                       return fne;
                }
 
-               public override void Emit (EmitContext ec)
+               public override Expression DoResolve (EmitContext ec)
                {
-                       throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
+                       return ResolveAsTypeStep (ec, false);
                }
 
-
-               public override string ToString ()
+               protected override void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
                {
-                       return alias + "::" + identifier;
+                       Report.Error (687, loc,
+                               "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
+                               GetSignatureForError ());
                }
 
                public override string GetSignatureForError ()
                {
-                       return ToString ();
+                       string name = Name;
+                       if (targs != null) {
+                               name = TypeManager.RemoveGenericArity (Name) + "<" +
+                                       targs.GetSignatureForError () + ">";
+                       }
+
+                       return alias + "::" + name;
                }
 
                protected override void CloneTo (CloneContext clonectx, Expression t)
@@ -6574,31 +7134,25 @@ namespace Mono.CSharp {
        /// <summary>
        ///   Implements the member access expression
        /// </summary>
-       public class MemberAccess : Expression {
-               public readonly string Identifier;
-               Expression expr;
-               readonly TypeArguments args;
+       public class MemberAccess : ATypeNameExpression {
+               protected Expression expr;
 
                public MemberAccess (Expression expr, string id)
-                       : this (expr, id, expr.Location)
+                       : base (id, expr.Location)
                {
+                       this.expr = expr;
                }
 
                public MemberAccess (Expression expr, string identifier, Location loc)
+                       : base (identifier, loc)
                {
                        this.expr = expr;
-                       Identifier = identifier;
-                       this.loc = loc;
                }
 
                public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
-                       : this (expr, identifier, loc)
+                       : base (identifier, args, loc)
                {
-                       this.args = args;
-               }
-
-               protected string LookupIdentifier {
-                       get { return MemberName.MakeName (Identifier, args); }
+                       this.expr = expr;
                }
 
                // TODO: this method has very poor performace for Enum fields and
@@ -6623,28 +7177,27 @@ namespace Mono.CSharp {
                        if (expr_resolved == null)
                                return null;
 
+                       string LookupIdentifier = MemberName.MakeName (Name, targs);
+
                        if (expr_resolved is Namespace) {
                                Namespace ns = (Namespace) expr_resolved;
                                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);
+                               if ((retval != null) && (targs != null))
+                                       retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (ec, false);
 #endif
 
                                if (retval == null)
-                                       ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
+                                       ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Name);
                                return retval;
                        }
 
                        Type expr_type = expr_resolved.Type;
-                       if (expr_type.IsPointer || expr_type == TypeManager.void_type || expr_resolved is NullLiteral){
+                       if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
+                               expr_resolved is NullLiteral || expr_type == TypeManager.anonymous_method_type) {
                                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 = expr_resolved as Constant;
                        if (c != null && c.GetValue () == null) {
@@ -6652,16 +7205,16 @@ namespace Mono.CSharp {
                                        "System.NullReferenceException");
                        }
 
-                       if (args != null) {
-                               if (!args.Resolve (ec))
+                       if (targs != null) {
+                               if (!targs.Resolve (ec))
                                        return null;
                        }
 
                        Expression member_lookup;
                        member_lookup = MemberLookup (
-                               ec.ContainerType, expr_type, expr_type, Identifier, loc);
+                               ec.ContainerType, expr_type, expr_type, Name, loc);
 #if GMCS_SOURCE
-                       if ((member_lookup == null) && (args != null)) {
+                       if ((member_lookup == null) && (targs != null)) {
                                member_lookup = MemberLookup (
                                        ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
                        }
@@ -6675,12 +7228,12 @@ namespace Mono.CSharp {
                                if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
                                        expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
                                        expr_eclass == ExprClass.EventAccess) {
-                                       ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Identifier);
+                                       ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Name, loc);
                                        if (ex_method_lookup != null) {
                                                ex_method_lookup.ExtensionExpression = expr_resolved;
 
-                                               if (args != null) {
-                                                       ex_method_lookup.SetTypeArguments (args);
+                                               if (targs != null) {
+                                                       ex_method_lookup.SetTypeArguments (targs);
                                                }
 
                                                return ex_method_lookup.DoResolve (ec);
@@ -6689,7 +7242,7 @@ namespace Mono.CSharp {
 
                                expr = expr_resolved;
                                Error_MemberLookupFailed (
-                                       ec.ContainerType, expr_type, expr_type, Identifier, null,
+                                       ec.ContainerType, expr_type, expr_type, Name, null,
                                        AllMemberTypes, AllBindingFlags);
                                return null;
                        }
@@ -6699,7 +7252,7 @@ namespace Mono.CSharp {
                                if (!(expr_resolved is TypeExpr) && 
                                    (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
                                        Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
-                                               Identifier, member_lookup.GetSignatureForError ());
+                                               Name, member_lookup.GetSignatureForError ());
                                        return null;
                                }
 
@@ -6733,8 +7286,8 @@ namespace Mono.CSharp {
                        if (me == null)
                                return null;
 
-                       if (args != null) {
-                               me.SetTypeArguments (args);
+                       if (targs != null) {
+                               me.SetTypeArguments (targs);
                        }
 
                        if (original != null && !TypeManager.IsValueType (expr_type)) {
@@ -6776,12 +7329,14 @@ namespace Mono.CSharp {
                        if (new_expr == null)
                                return null;
 
+                       string LookupIdentifier = MemberName.MakeName (Name, targs);
+
                        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);
+                               if ((retval != null) && (targs != null))
+                                       retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (rc, false);
 #endif
                                if (!silent && retval == null)
                                        ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
@@ -6807,30 +7362,7 @@ namespace Mono.CSharp {
                                if (silent)
                                        return null;
 
-                               member_lookup = MemberLookup (
-                                       rc.DeclContainer.TypeBuilder, expr_type, expr_type, SimpleName.RemoveGenericArity (LookupIdentifier),
-                                       MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
-
-                               if (member_lookup != null) {
-                                       tnew_expr = member_lookup.ResolveAsTypeTerminal (rc, false);
-                                       if (tnew_expr == null)
-                                               return null;
-
-                                       Namespace.Error_TypeArgumentsCannotBeUsed (tnew_expr.Type, loc);
-                                       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);
-                               }
+                               Error_IdentifierNotFound (rc, new_expr, LookupIdentifier);
                                return null;
                        }
 
@@ -6839,7 +7371,7 @@ namespace Mono.CSharp {
                                return null;
 
 #if GMCS_SOURCE
-                       TypeArguments the_args = args;
+                       TypeArguments the_args = targs;
                        Type declaring_type = texpr.Type.DeclaringType;
                        if (TypeManager.HasGenericArguments (declaring_type)) {
                                while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
@@ -6850,8 +7382,8 @@ namespace Mono.CSharp {
                                foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
                                        new_args.Add (new TypeExpression (decl, loc));
 
-                               if (args != null)
-                                       new_args.Add (args);
+                               if (targs != null)
+                                       new_args.Add (targs);
 
                                the_args = new_args;
                        }
@@ -6865,9 +7397,32 @@ namespace Mono.CSharp {
                        return texpr;
                }
 
-               public override void Emit (EmitContext ec)
+               protected virtual void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
                {
-                       throw new Exception ("Should not happen");
+                       Expression member_lookup = MemberLookup (
+                               rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
+                               MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
+
+                       if (member_lookup != null) {
+                               expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
+                               if (expr_type == null)
+                                       return;
+
+                               Namespace.Error_TypeArgumentsCannotBeUsed (expr_type.Type, loc);
+                               return;
+                       }
+
+                       member_lookup = MemberLookup (
+                               rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, identifier,
+                                       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}'",
+                                                 Name, expr_type.GetSignatureForError ());
+                       } else {
+                               // TODO: Report.SymbolRelatedToPreviousError
+                               member_lookup.Error_UnexpectedKind (null, "type", loc);
+                       }
                }
 
                protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
@@ -6884,14 +7439,9 @@ namespace Mono.CSharp {
                        base.Error_TypeDoesNotContainDefinition (type, name);
                }
 
-               public override string ToString ()
-               {
-                       return expr + "." + MemberName.MakeName (Identifier, args);
-               }
-
                public override string GetSignatureForError ()
                {
-                       return expr.GetSignatureForError () + "." + Identifier;
+                       return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
                }
 
                protected override void CloneTo (CloneContext clonectx, Expression t)
@@ -6914,6 +7464,12 @@ namespace Mono.CSharp {
                        Expr = e;
                        loc = l;
                }
+               
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
+                               return Expr.CreateExpressionTree (ec);
+               }
 
                public override Expression DoResolve (EmitContext ec)
                {
@@ -6963,6 +7519,12 @@ namespace Mono.CSharp {
                        Expr = e;
                        loc = l;
                }
+               
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
+                               return Expr.CreateExpressionTree (ec);
+               }
 
                public override Expression DoResolve (EmitContext ec)
                {
@@ -7150,7 +7712,6 @@ namespace Mono.CSharp {
                ElementAccess ea;
 
                LocalTemporary temp;
-               LocalTemporary prepared_value;
 
                bool prepared;
                
@@ -7185,12 +7746,18 @@ namespace Mono.CSharp {
 #endif
 
                        Type t = ea.Expr.Type;
-                       if (t.GetArrayRank () != ea.Arguments.Count) {
+                       int rank = ea.Arguments.Count;
+                       if (t.GetArrayRank () != rank) {
                                Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
                                          ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
                                return null;
                        }
 
+                       if (rank != 1 && TypeManager.int_getlength_int == null) {
+                               TypeManager.int_getlength_int = TypeManager.GetPredefinedMethod (
+                                       TypeManager.array_type, "GetLength", loc, TypeManager.int32_type);
+                       }
+
                        type = TypeManager.GetElementType (t);
                        if (type.IsPointer && !ec.InUnsafe) {
                                UnsafeError (ea.Location);
@@ -7241,7 +7808,7 @@ namespace Mono.CSharp {
                        else if (type == TypeManager.intptr_type)
                                ig.Emit (OpCodes.Ldelem_I);
                        else if (TypeManager.IsEnumType (type)){
-                               EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type), rank);
+                               EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
                        } else if (type.IsValueType){
                                ig.Emit (OpCodes.Ldelema, type);
                                ig.Emit (OpCodes.Ldobj, type);
@@ -7270,7 +7837,7 @@ namespace Mono.CSharp {
                        has_type_arg = false; is_stobj = false;
                        t = TypeManager.TypeToCoreType (t);
                        if (TypeManager.IsEnumType (t))
-                               t = TypeManager.EnumToUnderlying (t);
+                               t = TypeManager.GetEnumUnderlyingType (t);
                        if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
                            t == TypeManager.bool_type)
                                return OpCodes.Stelem_I1;
@@ -7353,36 +7920,13 @@ namespace Mono.CSharp {
                //
                // 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.
-               //
-               // prepare_for_load is used in compound assignments to cache original index
-               // values ( label[idx++] += s )
-               //
-               LocalTemporary [] LoadArrayAndArguments (EmitContext ec, bool prepare_for_load)
+               void LoadArrayAndArguments (EmitContext ec)
                {
                        ea.Expr.Emit (ec);
 
-                       LocalTemporary[] indexes = null;
-                       if (prepare_for_load) {
-                               ec.ig.Emit (OpCodes.Dup);
-                               indexes = new LocalTemporary [ea.Arguments.Count];
-                       }
-
                        for (int i = 0; i < ea.Arguments.Count; ++i) {
                                ((Argument)ea.Arguments [i]).Emit (ec);
-                               if (!prepare_for_load)
-                                       continue;
-
-                               // Keep original array index value on the stack
-                               ec.ig.Emit (OpCodes.Dup);
-
-                               indexes [i] = new LocalTemporary (TypeManager.intptr_type);
-                               indexes [i].Store (ec);
                        }
-
-                       return indexes;
                }
 
                public void Emit (EmitContext ec, bool leave_copy)
@@ -7390,12 +7934,10 @@ namespace Mono.CSharp {
                        int rank = ea.Expr.Type.GetArrayRank ();
                        ILGenerator ig = ec.ig;
 
-                       if (prepared_value != null) {
-                               prepared_value.Emit (ec);
-                       } else if (prepared) {
+                       if (prepared) {
                                LoadFromPtr (ig, this.type);
                        } else {
-                               LoadArrayAndArguments (ec, false);
+                               LoadArrayAndArguments (ec);
                                EmitLoadOpcode (ig, type, rank);
                        }       
 
@@ -7416,24 +7958,13 @@ namespace Mono.CSharp {
                        int rank = ea.Expr.Type.GetArrayRank ();
                        ILGenerator ig = ec.ig;
                        Type t = source.Type;
-                       prepared = prepare_for_load && !(source is StringConcat);
+                       prepared = prepare_for_load;
 
                        if (prepared) {
                                AddressOf (ec, AddressOp.LoadStore);
                                ec.ig.Emit (OpCodes.Dup);
                        } else {
-                               LocalTemporary[] original_indexes_values = LoadArrayAndArguments (ec,
-                                       prepare_for_load && (source is StringConcat));
-
-                               if (original_indexes_values != null) {
-                                       prepared_value = new LocalTemporary (type);
-                                       EmitLoadOpcode (ig, type, rank);
-                                       prepared_value.Store (ec);
-                                       foreach (LocalTemporary lt in original_indexes_values) {
-                                               lt.Emit (ec);
-                                               lt.Release (ec);
-                                       }
-                               }
+                               LoadArrayAndArguments (ec);
                        }
 
                        if (rank == 1) {
@@ -7505,7 +8036,7 @@ namespace Mono.CSharp {
                        int rank = ea.Expr.Type.GetArrayRank ();
                        ILGenerator ig = ec.ig;
 
-                       LoadArrayAndArguments (ec, false);
+                       LoadArrayAndArguments (ec);
 
                        if (rank == 1){
                                ig.Emit (OpCodes.Ldelema, type);
@@ -7751,7 +8282,7 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       type = pi.PropertyType;
+                       type = TypeManager.TypeToCoreType (pi.PropertyType);
                        if (type.IsPointer && !ec.InUnsafe)
                                UnsafeError (loc);
 
@@ -8077,6 +8608,10 @@ namespace Mono.CSharp {
                        // nothing, as we only exist to not do anything.
                }
 
+               public override void EmitSideEffect (EmitContext ec)
+               {
+               }
+
                //
                // This is just because we might want to reuse this bad boy
                // instead of creating gazillions of EmptyExpressions.
@@ -8119,14 +8654,14 @@ namespace Mono.CSharp {
        }       
 
        public class UserCast : Expression {
-               MethodBase method;
+               MethodInfo method;
                Expression source;
                
                public UserCast (MethodInfo method, Expression source, Location l)
                {
                        this.method = method;
                        this.source = source;
-                       type = method.ReturnType;
+                       type = TypeManager.TypeToCoreType (method.ReturnType);
                        eclass = ExprClass.Value;
                        loc = l;
                }
@@ -8136,6 +8671,15 @@ namespace Mono.CSharp {
                                return source;
                        }
                }
+
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       ArrayList args = new ArrayList (2);
+                       args.Add (new Argument (source.CreateExpressionTree (ec)));
+                       args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
+                       args.Add (new Argument (new TypeOfMethodInfo (method, loc)));
+                       return CreateExpressionFactoryCall ("Convert", args);
+               }
                        
                public override Expression DoResolve (EmitContext ec)
                {
@@ -8147,15 +8691,8 @@ namespace Mono.CSharp {
 
                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);
-
+                       ec.ig.Emit (OpCodes.Call, method);
                }
        }
 
@@ -8166,15 +8703,15 @@ namespace Mono.CSharp {
        //   one bit at a time.
        // </summary>
        public class ComposedCast : TypeExpr {
-               Expression left;
+               FullNamedExpression left;
                string dim;
                
-               public ComposedCast (Expression left, string dim)
+               public ComposedCast (FullNamedExpression left, string dim)
                        : this (left, dim, left.Location)
                {
                }
 
-               public ComposedCast (Expression left, string dim, Location l)
+               public ComposedCast (FullNamedExpression left, string dim, Location l)
                {
                        this.left = left;
                        this.dim = dim;
@@ -8206,7 +8743,7 @@ namespace Mono.CSharp {
 
 #if GMCS_SOURCE
                        if ((dim.Length > 0) && (dim [0] == '?')) {
-                               TypeExpr nullable = new NullableType (left, loc);
+                               TypeExpr nullable = new Nullable.NullableType (left, loc);
                                if (dim.Length > 1)
                                        nullable = new ComposedCast (nullable, dim.Substring (1), loc);
                                return nullable.ResolveAsTypeTerminal (ec, false);
@@ -8239,14 +8776,6 @@ namespace Mono.CSharp {
                        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;
@@ -8256,7 +8785,7 @@ namespace Mono.CSharp {
                {
                        ComposedCast target = (ComposedCast) t;
 
-                       target.left = left.Clone (clonectx);
+                       target.left = (FullNamedExpression)left.Clone (clonectx);
                }
        }
 
@@ -8272,6 +8801,12 @@ namespace Mono.CSharp {
                        eclass = ExprClass.Value;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       Error_PointerInsideExpressionTree ();
+                       return null;
+               }
+
                public override void Emit(EmitContext ec)
                {
                        array.Emit (ec);
@@ -8314,34 +8849,24 @@ namespace Mono.CSharp {
        //
        // Encapsulates a conversion rules required for array indexes
        //
-       public class ArrayIndexCast : Expression
+       public class ArrayIndexCast : TypeCast
        {
-               Expression expr;
-
                public ArrayIndexCast (Expression expr)
+                       : base (expr, expr.Type)
                {
-                       this.expr = expr;
-                       this.loc = expr.Location;
                }
 
                public override Expression CreateExpressionTree (EmitContext ec)
                {
                        ArrayList args = new ArrayList (2);
-                       args.Add (new Argument (expr.CreateExpressionTree (ec)));
+                       args.Add (new Argument (child.CreateExpressionTree (ec)));
                        args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
                        return CreateExpressionFactoryCall ("ConvertChecked", args);
                }
 
-               public override Expression DoResolve (EmitContext ec)
-               {
-                       type = expr.Type;
-                       eclass = expr.eclass;
-                       return this;
-               }
-
                public override void Emit (EmitContext ec)
                {
-                       expr.Emit (ec);
+                       child.Emit (ec);
                                
                        if (type == TypeManager.int32_type)
                                return;
@@ -8357,39 +8882,6 @@ namespace Mono.CSharp {
                }
        }
 
-       //
-       // 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
        //
@@ -8405,6 +8897,11 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       throw new NotSupportedException ("ET");
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        count = count.Resolve (ec);
@@ -8468,60 +8965,76 @@ namespace Mono.CSharp {
        //
        // An object initializer expression
        //
-       public class ElementInitializer : Expression
+       public class ElementInitializer : Assign
        {
-               Expression initializer;
                public readonly string Name;
 
                public ElementInitializer (string name, Expression initializer, Location loc)
+                       : base (null, initializer, loc)
                {
                        this.Name = name;
-                       this.initializer = initializer;
-                       this.loc = loc;
                }
-
+               
                protected override void CloneTo (CloneContext clonectx, Expression t)
                {
-                       if (initializer == null)
-                               return;
-
                        ElementInitializer target = (ElementInitializer) t;
-                       target.initializer = initializer.Clone (clonectx);
+                       target.source = source.Clone (clonectx);
+               }
+
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       ArrayList args = new ArrayList (2);
+                       FieldExpr fe = target as FieldExpr;
+                       if (fe != null)
+                               args.Add (new Argument (fe.CreateTypeOfExpression ()));
+                       else
+                               args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
+
+                       args.Add (new Argument (source.CreateExpressionTree (ec)));
+                       return CreateExpressionFactoryCall (
+                               source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
+                               args);
                }
 
                public override Expression DoResolve (EmitContext ec)
                {
-                       if (initializer == null)
+                       if (source == null)
                                return EmptyExpressionStatement.Instance;
                        
-                       MemberExpr element_member = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
+                       MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
                                Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
 
-                       if (element_member == null)
+                       if (me == null)
                                return null;
 
-                       element_member.InstanceExpression = ec.CurrentInitializerVariable;
+                       target = me;
+                       me.InstanceExpression = ec.CurrentInitializerVariable;
 
-                       if (initializer is CollectionOrObjectInitializers) {
+                       if (source is CollectionOrObjectInitializers) {
                                Expression previous = ec.CurrentInitializerVariable;
-                               ec.CurrentInitializerVariable = element_member;
-                               initializer = initializer.Resolve (ec);
+                               ec.CurrentInitializerVariable = target;
+                               source = source.Resolve (ec);
                                ec.CurrentInitializerVariable = previous;
-                               return initializer;
+                               if (source == null)
+                                       return null;
+                                       
+                               eclass = source.eclass;
+                               type = source.Type;
+                               return this;
                        }
 
-                       Assign a = new Assign (element_member, initializer, loc);
-                       if (a.Resolve (ec) == null)
+                       Expression expr = base.DoResolve (ec);
+                       if (expr == null)
                                return null;
 
                        //
                        // Ignore field initializers with default value
                        //
-                       Constant c = a.Source as Constant;
-                       if (c != null && c.IsDefaultInitializer (a.Type) && a.Target.eclass == ExprClass.Variable)
+                       Constant c = source as Constant;
+                       if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
                                return EmptyExpressionStatement.Instance;
 
-                       return a;
+                       return expr;
                }
 
                protected override Expression Error_MemberLookupFailed (MemberInfo[] members)
@@ -8536,17 +9049,20 @@ namespace Mono.CSharp {
 
                        return null;
                }
-
-               public override void Emit (EmitContext ec)
+               
+               public override void EmitStatement (EmitContext ec)
                {
-                       throw new NotSupportedException ("Should not be reached");
+                       if (source is CollectionOrObjectInitializers)
+                               source.Emit (ec);
+                       else
+                               base.EmitStatement (ec);
                }
        }
        
        //
        // A collection initializer expression
        //
-       public class CollectionElementInitializer : Expression
+       public class CollectionElementInitializer : Invocation
        {
                public class ElementInitializerArgument : Argument
                {
@@ -8556,49 +9072,61 @@ namespace Mono.CSharp {
                        }
                }
 
-               ArrayList arguments;
-
                public CollectionElementInitializer (Expression argument)
+                       : base (null, new ArrayList (1), true)
                {
-                       arguments = new ArrayList (1);
-                       arguments.Add (argument);
+                       Arguments.Add (argument);
                        this.loc = argument.Location;
                }
 
                public CollectionElementInitializer (ArrayList arguments, Location loc)
+                       : base (null, arguments, true)
                {
-                       this.arguments = arguments;
                        this.loc = loc;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       ArrayList args = new ArrayList (2);
+                       args.Add (new Argument (mg.CreateExpressionTree (ec)));
+
+                       ArrayList expr_initializers = new ArrayList (Arguments.Count);
+                       foreach (Argument a in Arguments)
+                               expr_initializers.Add (a.Expr.CreateExpressionTree (ec));
+
+                       args.Add (new Argument (new ArrayCreation (
+                               CreateExpressionTypeExpression (loc), "[]", expr_initializers, loc)));
+                       return CreateExpressionFactoryCall ("ElementInit", args);
+               }
+
                protected override void CloneTo (CloneContext clonectx, Expression t)
                {
                        CollectionElementInitializer target = (CollectionElementInitializer) t;
-                       ArrayList t_arguments = target.arguments = new ArrayList (arguments.Count);
-                       foreach (Expression e in arguments)
-                               t_arguments.Add (e.Clone (clonectx));
+
+                       target.Arguments = new ArrayList (Arguments.Count);
+                       foreach (Expression e in Arguments)
+                               target.Arguments.Add (e.Clone (clonectx));
                }
 
                public override Expression DoResolve (EmitContext ec)
                {
-                       // TODO: We should call a constructor which takes element counts argument,
-                       // for know types like List<T>, Dictionary<T, U>
+                       if (eclass != ExprClass.Invalid)
+                               return this;
+
+                       // TODO: We could call a constructor which takes element count argument,
+                       // for known types like List<T>, Dictionary<T, U>
                        
-                       for (int i = 0; i < arguments.Count; ++i)
-                               arguments [i] = new ElementInitializerArgument ((Expression)arguments [i]);
+                       for (int i = 0; i < Arguments.Count; ++i) {
+                               Expression expr = ((Expression) Arguments [i]).Resolve (ec);
+                               if (expr == null)
+                                       return null;
 
-                       Expression add_method = new Invocation (
-                               new MemberAccess (ec.CurrentInitializerVariable, "Add", loc),
-                               arguments);
+                               Arguments [i] = new ElementInitializerArgument (expr);
+                       }
 
-                       add_method = add_method.Resolve (ec);
+                       base.expr = new MemberAccess (ec.CurrentInitializerVariable, "Add", loc);
 
-                       return add_method;
-               }
-               
-               public override void Emit (EmitContext ec)
-               {
-                       throw new NotSupportedException ("Should not be reached");
+                       return base.DoResolve (ec);
                }
        }
        
@@ -8624,6 +9152,12 @@ namespace Mono.CSharp {
                        }
                }
 
+               public bool IsCollectionInitializer {
+                       get {
+                               return type == typeof (CollectionOrObjectInitializers);
+                       }
+               }
+
                protected override void CloneTo (CloneContext clonectx, Expression target)
                {
                        CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
@@ -8632,9 +9166,24 @@ namespace Mono.CSharp {
                        foreach (Expression e in initializers)
                                t.initializers.Add (e.Clone (clonectx));
                }
+
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       ArrayList expr_initializers = new ArrayList (initializers.Count);
+                       foreach (Expression e in initializers) {
+                               Expression expr = e.CreateExpressionTree (ec);
+                               if (expr != null)
+                                       expr_initializers.Add (expr);
+                       }
+
+                       return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
+               }
                
                public override Expression DoResolve (EmitContext ec)
                {
+                       if (eclass != ExprClass.Invalid)
+                               return this;
+
                        bool is_elements_initialization = false;
                        ArrayList element_names = null;
                        for (int i = 0; i < initializers.Count; ++i) {
@@ -8679,10 +9228,10 @@ namespace Mono.CSharp {
                                if (e == EmptyExpressionStatement.Instance)
                                        initializers.RemoveAt (i--);
                                else
-                                       initializers [i] = e;                           
+                                       initializers [i] = e;
                        }
 
-                       type = typeof (CollectionOrObjectInitializers);
+                       type = is_elements_initialization ? typeof (ElementInitializer) : typeof (CollectionOrObjectInitializers);
                        eclass = ExprClass.Variable;
                        return this;
                }
@@ -8721,6 +9270,12 @@ namespace Mono.CSharp {
                                this.new_instance = newInstance;
                        }
 
+                       public override Expression CreateExpressionTree (EmitContext ec)
+                       {
+                               // Should not be reached
+                               throw new NotSupportedException ("ET");
+                       }
+
                        public override Expression DoResolve (EmitContext ec)
                        {
                                return this;
@@ -8762,8 +9317,22 @@ namespace Mono.CSharp {
                        target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       ArrayList args = new ArrayList (2);
+                       args.Add (new Argument (base.CreateExpressionTree (ec)));
+                       args.Add (new Argument (initializers.CreateExpressionTree (ec)));
+
+                       return CreateExpressionFactoryCall (
+                               initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
+                               args);
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
+                       if (eclass != ExprClass.Invalid)
+                               return this;
+                       
                        Expression e = base.DoResolve (ec);
                        if (type == null)
                                return null;
@@ -8941,6 +9510,11 @@ namespace Mono.CSharp {
                        t.initializer = initializer.Clone (clonectx);
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       throw new NotSupportedException ("ET");
+               }
+
                public override bool Equals (object o)
                {
                        AnonymousTypeParameter other = o as AnonymousTypeParameter;