2008-04-09 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / expression.cs
index 9b0a469610e105c6f8d761ef38184667fe6fa3fd..a346cc4581b0ee546be8e9ad7bba87d26f15b81d 100644 (file)
@@ -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).CreateExpressionTree (ec)));
+                       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,14 +64,11 @@ namespace Mono.CSharp {
 
                public override void Emit (EmitContext ec)
                {
-                       if (args != null) 
-                               Invocation.EmitArguments (ec, mi, 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;
@@ -66,23 +81,16 @@ namespace Mono.CSharp {
                                 return null;
 
                         args.Add (a);
-                       mg = mg.OverloadResolve (ec, args, false, loc);
+                       mg = mg.OverloadResolve (ec, ref args, false, loc);
 
                        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; }
                }
        }
 
@@ -121,21 +129,18 @@ namespace Mono.CSharp {
                }
        }
        
-       /// <summary>
-       ///   Unary expressions.  
-       /// </summary>
-       ///
-       /// <remarks>
-       ///   Unary implements unary expressions.   It derives from
-       ///   ExpressionStatement becuase the pre/post increment/decrement
-       ///   operators can be used in a statement context.
-       /// </remarks>
+       //
+       //   Unary implements unary expressions.
+       //
        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;
 
@@ -146,31 +151,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];
@@ -179,26 +159,9 @@ 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.
@@ -347,237 +310,135 @@ 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)
+               Expression ResolveOperator (EmitContext ec, Expression expr)
                {
-                       //
-                       // Step 1: Default operations on CLI native types.
-                       //
+                       if (predefined_operators == null)
+                               CreatePredefinedOperatorsTable ();
 
-                       // Attempt to use a constant folding operation.
-                       Constant cexpr = Expr as Constant;
-                       if (cexpr != null) {
-                               cexpr = TryReduceConstant (ec, cexpr);
-                               if (cexpr != null) {
-                                       return cexpr;
-                               }
-                       }
+                       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;
-                               }
-
-                               type = TypeManager.int32_type;
-                               Expr = Convert.ImplicitUserConversion(ec, Expr, type, loc);
-                               if (Expr != null)
-                                       return this;
-
-                               Error23 (expr_type);
-                               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);
+                       //
+                       // E operator ~(E x);
+                       //
+                       if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type)) {
+                               best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, TypeManager.GetEnumUnderlyingType (expr_type)));
+                               if (best_expr == null)
                                        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);
+                               Expr = EmptyCast.Create (best_expr, expr_type);
+                               type = Expr.Type;
                                return this;
+                       }
 
-                       case Operator.Indirection:
-                               if (!ec.InUnsafe){
-                                       UnsafeError (loc);
-                                       return null;
-                               }
-                               
-                               if (!expr_type.IsPointer){
-                                       Error (193, "The * or -> operator must be applied to a pointer");
-                                       return null;
-                               }
-                               
-                               //
-                               // We create an Indirection expression, because
-                               // it can implement the IMemoryLocation.
-                               // 
-                               return new Indirection (Expr, loc);
-                       
-                       case Operator.UnaryPlus:
-                               // 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);
-                               }
+                       return ResolveUserType (ec, expr);
+               }
 
-                               // 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;
-                               }
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       return CreateExpressionTree (ec, null);
+               }
 
-                               Expr = Convert.ImplicitUserConversion(ec, Expr, TypeManager.int32_type, loc);
-                               if (Expr != null) {
-                                        // Because we can completely ignore unary +
-                                       return Expr;
-                               }
+               Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr user_op)
+               {
+                       string method_name; 
+                       switch (Oper) {
+                       case Operator.UnaryNegation:
+                               method_name = "Negate";
+                               break;
+                       case Operator.LogicalNot:
+                               method_name = "Not";
+                               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)
                {
+                       eclass = ExprClass.Value;
+
                        if (Oper == Operator.AddressOf) {
                                Expr = Expr.DoResolveLValue (ec, new EmptyExpression ());
 
@@ -585,10 +446,11 @@ 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;
 
@@ -597,22 +459,38 @@ namespace Mono.CSharp {
                                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)
                {
                        ILGenerator ig = ec.ig;
-                       
+
                        switch (Oper) {
                        case Operator.UnaryPlus:
                                throw new Exception ("This should be caught by Resolve");
@@ -660,34 +538,186 @@ namespace Mono.CSharp {
                                base.EmitBranchable (ec, target, on_true);
                }
 
-               public override string ToString ()
+               public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
                {
-                       return "Unary (" + Oper + ", " + Expr + ")";
+                       Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
+                               oper, TypeManager.CSharpName (t));
                }
 
-               protected override void CloneTo (CloneContext clonectx, Expression t)
+               //
+               // Returns a stringified representation of the Operator
+               //
+               public static string OperName (Operator oper)
                {
-                       Unary target = (Unary) t;
+                       switch (oper) {
+                       case Operator.UnaryPlus:
+                               return "+";
+                       case Operator.UnaryNegation:
+                               return "-";
+                       case Operator.LogicalNot:
+                               return "!";
+                       case Operator.OnesComplement:
+                               return "~";
+                       case Operator.AddressOf:
+                               return "&";
+                       }
 
-                       target.Expr = Expr.Clone (clonectx);
+                       throw new NotImplementedException (oper.ToString ());
                }
-       }
 
-       //
-       // Unary operators are turned into Indirection expressions
-       // after semantic analysis (this is so we can take the address
-       // of an indirection).
-       //
-       public class Indirection : Expression, IMemoryLocation, IAssignMethod, IVariable {
-               Expression expr;
-               LocalTemporary temporary;
-               bool prepared;
-               
-               public Indirection (Expression expr, Location l)
+               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);
+                       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;
+               }
+
+               //
+               // Unary user type overload resolution
+               //
+               Expression ResolveUserType (EmitContext ec, Expression expr)
+               {
+                       //
+                       // Perform user-operator overload resolution
+                       //
+                       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) {
+                               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) {
+                                       Expr = ((Argument) args [0]).Expr;
+                                       return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
+                               }
+                       }
+
+                       Type[] predefined = predefined_operators [(int) Oper];
+                       Expression best_expr = null;
+                       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;
+               bool prepared;
+               
+               public Indirection (Expression expr, Location l)
                {
                        this.expr = expr;
-                       type = TypeManager.HasElementType (expr.Type) ? TypeManager.GetElementType (expr.Type) : expr.Type;
-                       eclass = ExprClass.Variable;
                        loc = l;
                }
                
@@ -745,9 +775,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;
                }
                
@@ -808,7 +849,7 @@ namespace Mono.CSharp {
                //
                // This is expensive for the simplest case.
                //
-               StaticCallExpr method;
+               UserOperatorCall method;
 
                public UnaryMutator (Mode m, Expression e, Location l)
                {
@@ -840,7 +881,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);
@@ -864,7 +905,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;
@@ -898,6 +939,11 @@ namespace Mono.CSharp {
                        return this;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       return new Assign (this, this).CreateExpressionTree (ec);
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        expr = expr.Resolve (ec);
@@ -1016,7 +1062,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;
                        }
@@ -1288,8 +1334,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;
                        
                        }
@@ -1320,8 +1366,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);
@@ -1454,6 +1499,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);
@@ -1467,20 +1520,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;
@@ -1507,18 +1557,242 @@ 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
+
+               protected class PredefinedOperator {
+                       protected readonly Type left;
+                       protected readonly Type right;
+                       public readonly Operator OperatorsMask;
+                       public Type ReturnType;
+
+                       public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
+                               : this (ltype, rtype, op_mask, ltype)
+                       {
+                       }
+
+                       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;
+                       }
+               }
+
+               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);
+                       }
+               }
+
+               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;
+                       }
+               }
+
+               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;
@@ -1527,29 +1801,32 @@ namespace Mono.CSharp {
 
                // 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 [(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";
+                       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)
@@ -1644,929 +1921,856 @@ 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;
-               }
+                       //
+                       // 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;
 
-               bool OverloadResolve_PredefinedFloating (EmitContext ec)
-               {
-                       return VerifyApplicable_Predefined (ec, TypeManager.float_type) ||
-                               VerifyApplicable_Predefined (ec, TypeManager.double_type) ||
-                               false;
-               }
+                                       primitives_only = true;
+                               }
+                       } else {
+                               // Pointers
+                               if (l.IsPointer || r.IsPointer)
+                                       return ResolveOperatorPointer (ec, l, r);
 
-               static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
-               {
-                       Error_OperatorCannotBeApplied (loc, name, TypeManager.CSharpName (l), TypeManager.CSharpName (r));
-               }
+                               // Enums
+                               bool lenum = TypeManager.IsEnumType (l);
+                               bool renum = TypeManager.IsEnumType (r);
+                               if (lenum || renum) {
+                                       expr = ResolveOperatorEnum (ec, lenum, renum, 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));
-               }
+                                       // TODO: Can this be ambiguous
+                                       if (expr != null)
+                                               return expr;
+                               }
 
-               static bool IsUnsigned (Type t)
-               {
-                       if (t.IsPointer)
-                               return IsUnsigned (t.GetElementType ());
-                       
-                       return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
-                               t == TypeManager.short_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;
+                               }
+                       }
+
+                       if (standard_operators == null)
+                               CreateStandardOperatorsTable ();
+
+                       return ResolveOperatorPredefined (ec, standard_operators, primitives_only);
                }
-                                       
-               Expression CheckShiftArguments (EmitContext ec)
+
+               Constant EnumLiftUp (Constant left, Constant right)
                {
-                       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 (left is EnumConstant)
+                                       return left;
+                               
+                               if (left.IsZeroInteger)
+                                       return new EnumConstant (left, right.Type);
+                               
+                               break;
+                               
+                       case Operator.Addition:
+                       case Operator.Subtraction:
+                               return left;
+                               
+                       case Operator.Multiply:
+                       case Operator.Division:
+                       case Operator.Modulus:
+                       case Operator.LeftShift:
+                       case Operator.RightShift:
+                               if (right is EnumConstant || left is EnumConstant)
+                                       break;
+                               return left;
                        }
-                       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;
+                       }
+
+                       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_UnintendedReferenceComparison (Location loc, string side, Type type)
+               static void CreatePointerOperatorsTable ()
                {
-                       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));
+                       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));
                }
 
-               static void Warning_Constant_Result (Location loc, bool result, Type type)
+               static void CreateStandardOperatorsTable ()
                {
-                       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 ();
+                       Type bool_type = TypeManager.bool_type;
+
+                       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));
+
+                       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));
+
+                       temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
+
+                       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));
+
+                       temp.Add (new PredefinedOperator (bool_type,
+                               Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
+
+                       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));
+
+                       standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
                }
-                       
-               Expression ResolveOperator (EmitContext ec)
-               {
-                       Type l = left.Type;
-                       Type r = right.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;
-                                       } 
+               //
+               // Rules used during binary numeric promotion
+               //
+               static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
+               {
+                       Expression temp;
+                       Type etype;
 
-                                       //
-                                       // 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){
-                                               Warning_Constant_Result (loc, oper == Operator.Inequality, l);
-                                               return new BoolLiteral (oper == Operator.Inequality, loc);
-                                       }
+                       Constant c = prim_expr as Constant;
+                       if (c != null) {
+                               temp = c.ConvertImplicitly (type);
+                               if (temp != null) {
+                                       prim_expr = temp;
+                                       return true;
                                }
+                       }
 
-                               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;
-                                       }
+                       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;
 
-                                       //
-                                       // 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){
-                                               Warning_Constant_Result (loc, oper == Operator.Inequality, r);
-                                               return new BoolLiteral (oper == Operator.Inequality, loc);
+                                       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;
                                        }
                                }
-
+                       } else if (type == TypeManager.uint64_type) {
                                //
-                               // Optimize out call to op_Equality in a few cases.
+                               // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
                                //
-                               if ((l == TypeManager.null_type && EqualsNullIsReferenceEquals (r)) ||
-                                   (r == TypeManager.null_type && EqualsNullIsReferenceEquals (l))) {
-                                       Type = TypeManager.bool_type;
-                                       return this;
-                               }
-
-                               // IntPtr equality
-                               if (l == TypeManager.intptr_type && r == TypeManager.intptr_type) {
-                                       Type = TypeManager.bool_type;
-                                       return this;
-                               }
+                               if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
+                                       type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
+                                       return false;
+                       }
 
-#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;
-                                       }
-                                       mg = (MethodGroupExpr)right;
-                                       delegate_type = l;
-                               }
+                       temp = Convert.ImplicitNumericConversion (prim_expr, type);
+                       if (temp == null)
+                               return false;
 
-                               if (mg != null) {
-                                       Expression e = ImplicitDelegateCreation.Create (ec, mg, delegate_type, loc);
-                                       if (e == null)
-                                               return null;
+                       prim_expr = temp;
+                       return true;
+               }
 
-                                       // Find operator method
-                                       string op = oper_names[(int)oper];
-                                       MemberInfo[] mi = TypeManager.MemberLookup(ec.ContainerType, null,
-                                               TypeManager.delegate_type, MemberTypes.Method, AllBindingFlags, op, null);
+               //
+               // 7.2.6.2 Binary numeric promotions
+               //
+               public bool DoBinaryOperatorPromotion (EmitContext ec)
+               {
+                       Type ltype = left.Type;
+                       Type rtype = right.Type;
+                       Expression temp;
 
-                                       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));
+                       foreach (Type t in ConstantFold.binary_promotions) {
+                               if (t == ltype)
+                                       return t == rtype || DoNumericPromotion (ref right, ref left, t);
 
-                                       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;
-                               }                               
+                               if (t == rtype)
+                                       return t == ltype || DoNumericPromotion (ref left, ref right, t);
                        }
 
+                       Type int32 = TypeManager.int32_type;
+                       if (ltype != int32) {
+                               Constant c = left as Constant;
+                               if (c != null)
+                                       temp = c.ImplicitConversionRequired (int32, loc);
+                               else
+                                       temp = Convert.ImplicitNumericConversion (left, int32);
 
-                       //
-                       // 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;
-
-                               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, args, true, Location.Null);
+                       if (rtype != int32) {
+                               Constant c = right as Constant;
+                               if (c != null)
+                                       temp = c.ImplicitConversionRequired (int32, loc);
+                               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 (lc, rc);
+                               if (lc == null)
+                                       return null;
 
-                                       l_gc = TypeManager.GetTypeParameterConstraints (l);
-                                       r_gc = TypeManager.GetTypeParameterConstraints (r);
+                               right = rc = EnumLiftUp (rc, lc);
+                               if (rc == null)
+                                       return null;
+                       }
+
+                       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;
+                                       }
+                                       
+                                       // TODO: there must be better way how to check that the expression
+                                       // does not have any mutator
+                                       if (right is MemberExpr)
+                                               return lc;
+
+                                       // 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 ((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, 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, 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;
-                                               }
-                                       }
+                       MethodInfo method;
+                       ArrayList args = new ArrayList (2);
 
-                                       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;
+                       args = new ArrayList (2);
+                       args.Add (new Argument (left, Argument.AType.Expression));
+                       args.Add (new Argument (right, Argument.AType.Expression));
 
-                                               if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral)) {
-                                                       Error_OperatorCannotBeApplied ();
-                                                       return null;
-                                               }
+                       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);
+                               }
 
-                                               return new BinaryDelegate (l, method, args);
-                                       }
+                               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
+               //
+               Binary ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
+               {
+                       Expression temp;
+
+                       if (lenum || renum) {
                                //
-                               // 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)
+                               // 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);
                                //
-                               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);
+                               if ((oper & Operator.ComparisonMask) != 0) {
+                                       type = TypeManager.bool_type;
+                               } else if ((oper & Operator.BitwiseMask) != 0) {
+                                       type = ltype;
                                }
-                       }
-                       
-                       //
-                       // Enumeration operators
-                       //
-                       bool lie = TypeManager.IsEnumType (l);
-                       bool rie = TypeManager.IsEnumType (r);
-                       if (lie || rie){
-                               Expression temp;
 
-                               // U operator - (E e, E f)
-                               if (lie && rie){
-                                       if (oper == Operator.Subtraction){
-                                               if (l == r){
-                                                       type = TypeManager.EnumToUnderlying (l);
-                                                       return this;
+                               if (type != null) {
+                                       if (!TypeManager.IsEqual (ltype, rtype)) {
+                                               if (!lenum) {
+                                                       temp = Convert.ImplicitConversion (ec, left, rtype, loc);
+                                                       if (temp == null)
+                                                               return null;
+                                                       left = temp;
+                                               } else {
+                                                       temp = Convert.ImplicitConversion (ec, right, ltype, loc);
+                                                       if (temp == null)
+                                                               return null;
+                                                       right = temp;
                                                }
-                                               Error_OperatorCannotBeApplied ();
-                                               return null;
                                        }
+
+                                       return this;
                                }
-                                       
+                       }
+
+                       Type underlying_type;
+                       if (lenum && !renum) {
                                //
-                               // operator + (E e, U x)
-                               // operator - (E e, U x)
+                               // 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 ();
+                               if (oper == Operator.Addition || oper == Operator.Subtraction) {
+                                       underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
+                                       temp = Convert.ImplicitConversion (ec, right, underlying_type, loc);
+                                       if (temp == null)
                                                return null;
-                                       }
 
-                                       type = enum_type;
+                                       right = temp;
+                                       type = ltype;
                                        return this;
                                }
-                               
-                               if (!rie){
-                                       temp = Convert.ImplicitConversion (ec, right, l, loc);
-                                       if (temp != null)
-                                               right = temp;
-                                       else {
-                                               Error_OperatorCannotBeApplied ();
-                                               return null;
-                                       }
-                               } if (!lie){
-                                       temp = Convert.ImplicitConversion (ec, left, r, loc);
-                                       if (temp != null){
-                                               left = temp;
-                                               l = r;
-                                       } else {
-                                               Error_OperatorCannotBeApplied ();
-                                               return null;
-                                       }
-                               }
 
-                               if (oper == Operator.Equality || oper == Operator.Inequality ||
-                                   oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
-                                   oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
-                                       if (left.Type != right.Type){
-                                               Error_OperatorCannotBeApplied ();
-                                               return null;
-                                       }
-                                       type = TypeManager.bool_type;
-                                       return this;
-                               }
+                               return null;
+                       }
 
-                               if (oper == Operator.BitwiseAnd ||
-                                   oper == Operator.BitwiseOr ||
-                                   oper == Operator.ExclusiveOr){
-                                       if (left.Type != right.Type){
-                                               Error_OperatorCannotBeApplied ();
+                       if (renum) {
+                               //
+                               // E operator + (U x, E e)
+                               //
+                               if (oper == Operator.Addition) {
+                                       underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
+                                       temp = Convert.ImplicitConversion (ec, left, underlying_type, loc);
+                                       if (temp == null)
                                                return null;
-                                       }
-                                       type = l;
+
+                                       left = temp;
+                                       type = rtype;
                                        return this;
                                }
-                               Error_OperatorCannotBeApplied ();
+                       }
+
+                       //
+                       // U operator - (E e, E f)
+                       //
+                       if (oper == Operator.Subtraction) {
+                               if (!TypeManager.IsEqual (ltype, rtype))
+                                       return null;
+
+                               type = TypeManager.GetEnumUnderlyingType (ltype);
+                               return this;
+                       }
+
+                       return null;
+               }
+
+               //
+               // 7.9.6 Reference type equality operators
+               //
+               Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
+               {
+                       //
+                       // operator != (object a, object b)
+                       // operator == (object a, object b)
+                       //
+
+                       // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
+
+                       if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
                                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;
-                               }
+                       type = TypeManager.bool_type;
+                       GenericConstraints constraints;
 
-                               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);
+                       bool lgen = TypeManager.IsGenericParameter (l);
 
-                               if (left_operators_e != null && right_operators_e != null) {
-                                       left = left_operators_e;
-                                       right = right_operators_e;
-                                       type = TypeManager.bool_type;
-                                       return this;
+                       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;
                                }
 
-                               Expression e = new ConditionalLogicalOperator (
-                                       oper == Operator.LogicalAnd, left, right, l, loc);
-                               return e.Resolve (ec);
-                       } 
+                               if (l == TypeManager.anonymous_method_type)
+                                       return null;
+
+                               if (TypeManager.IsValueType (l))
+                                       return null;
+
+                               return this;
+                       }
 
-                       Expression orig_left = left;
-                       Expression orig_right = right;
+                       bool rgen = TypeManager.IsGenericParameter (r);
 
                        //
-                       // operator & (bool x, bool y)
-                       // operator | (bool x, bool y)
-                       // operator ^ (bool x, bool y)
+                       // 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 (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);
+                       if (left is NullLiteral || right is NullLiteral) {
+                               if (lgen) {
+                                       constraints = TypeManager.GetTypeParameterConstraints (l);
+                                       if (constraints != null && constraints.HasValueTypeConstraint)
                                                return null;
-                                       }
 
-                                       if (oper == Operator.BitwiseOr && l != r && !(orig_right is Constant) && right is OpcodeCast &&
-                                               (r == TypeManager.sbyte_type || r == TypeManager.short_type ||
-                                                r == TypeManager.int32_type || r == TypeManager.int64_type)) {
-                                                       Report.Warning (675, 3, loc, "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
-                                                               TypeManager.CSharpName (r));
-                                       }
-                                       
-                               } else if (!VerifyApplicable_Predefined (ec, TypeManager.bool_type)) {
-                                       Error_OperatorCannotBeApplied ();
-                                       return null;
+                                       left = new BoxedCast (left, TypeManager.object_type);
+                                       return this;
                                }
-                               return this;
-                       }
-                       
-                       //
-                       // Pointer comparison
-                       //
-                       if (l.IsPointer && r.IsPointer){
-                               if (oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
-                                   oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
-                                       type = TypeManager.bool_type;
+
+                               if (rgen) {
+                                       constraints = TypeManager.GetTypeParameterConstraints (r);
+                                       if (constraints != null && constraints.HasValueTypeConstraint)
+                                               return null;
+
+                                       right = new BoxedCast (right, 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;
-                               }
-                       } 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;
+                       }
+
+                       if (rgen) {
+                               constraints = TypeManager.GetTypeParameterConstraints (r);
+                               if (constraints == null || constraints.IsReferenceType)
                                        return null;
-                               }
-                       } else if (!OverloadResolve_PredefinedString (ec, oper)) {
-                               Error_OperatorCannotBeApplied ();
-                               return null;
+                       } else if (r.IsInterface) {
+                               r = TypeManager.object_type;
                        }
 
-                       if (oper == Operator.Equality ||
-                           oper == Operator.Inequality ||
-                           oper == Operator.LessThanOrEqual ||
-                           oper == Operator.LessThan ||
-                           oper == Operator.GreaterThanOrEqual ||
-                           oper == Operator.GreaterThan)
-                               type = TypeManager.bool_type;
+                       const string ref_comparison = "Possible unintended reference comparison. " +
+                               "Consider casting the {0} side of the expression to `string' to compare the values";
 
-                       l = left.Type;
-                       r = right.Type;
+                       //
+                       // 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, 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);
                }
 
-               public override Expression DoResolve (EmitContext ec)
+               //
+               // Build-in operators method overloading
+               //
+               protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only)
                {
-                       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;
+                       return best_operator.ConvertResult (ec, this);
+               }
 
-                       // 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;
+               //
+               // 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;
 
-                               right = rc = EnumLiftUp (rc, lc);
-                               if (rc == null)
-                                       return null;
-                       }
+                       string op = GetOperatorMetadataName (user_oper);
 
-                       if (oper == Operator.BitwiseAnd) {
-                               if (rc != null && rc.IsZeroInteger) {
-                                       return lc is EnumConstant ?
-                                               new EnumConstant (rc, lc.Type):
-                                               rc;
-                               }
+                       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 (lc != null && lc.IsZeroInteger) {
-                                       return rc is EnumConstant ?
-                                               new EnumConstant (lc, rc.Type):
-                                               lc;
-                               }
-                       }
-                       else if (oper == Operator.BitwiseOr) {
-                               if (lc is EnumConstant &&
-                                   rc != null && rc.IsZeroInteger)
-                                       return lc;
-                               if (rc is EnumConstant &&
-                                   lc != null && lc.IsZeroInteger)
-                                       return rc;
-                       } else if (oper == Operator.LogicalAnd) {
-                               if (rc != null && rc.IsDefaultValue && rc.Type == TypeManager.bool_type)
-                                       return rc;
-                               if (lc != null && lc.IsDefaultValue && lc.Type == TypeManager.bool_type)
-                                       return lc;
-                       }
+                       if (union == null)
+                               return null;
 
-                       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;
-                       }
+                       ArrayList args = new ArrayList (2);
+                       Argument larg = new Argument (left);
+                       args.Add (larg);
+                       Argument rarg = new Argument (right);
+                       args.Add (rarg);
 
-#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
+                       union = union.OverloadResolve (ec, ref args, true, loc);
+                       if (union == null)
+                               return null;
 
-                       // 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?");
+                       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)
@@ -2639,6 +2843,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 ||
@@ -2832,75 +3042,80 @@ 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);
+               }
+
+               protected void EmitOperator (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
-                       Type l = left.Type;
-                       OpCode opcode;
 
                        //
                        // Handle short-circuit operators differently
                        // than the rest
                        //
-                       if (oper == Operator.LogicalAnd) {
-                               Label load_zero = ig.DefineLabel ();
-                               Label end = ig.DefineLabel ();
-                                                               
-                               left.EmitBranchable (ec, load_zero, false);
-                               right.Emit (ec);
-                               ig.Emit (OpCodes.Br, end);
-                               
-                               ig.MarkLabel (load_zero);
-                               ig.Emit (OpCodes.Ldc_I4_0);
-                               ig.MarkLabel (end);
-                               return;
-                       } else if (oper == Operator.LogicalOr) {
-                               Label load_one = ig.DefineLabel ();
+                       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);
+                       Type l = 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;
                                } else
                                        opcode = OpCodes.Mul;
-
+                               
                                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;
@@ -2910,7 +3125,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;
@@ -2922,7 +3137,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;
@@ -2931,7 +3146,7 @@ namespace Mono.CSharp {
                                break;
 
                        case Operator.RightShift:
-                               if (is_unsigned)
+                               if (IsUnsigned (l))
                                        opcode = OpCodes.Shr_Un;
                                else
                                        opcode = OpCodes.Shr;
@@ -2953,23 +3168,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);
@@ -2977,46 +3190,141 @@ namespace Mono.CSharp {
                                
                                opcode = OpCodes.Ceq;
                                break;
-
-                       case Operator.GreaterThanOrEqual:
-                               Type le = left.Type;
-                               
-                               if (is_unsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
-                                       ig.Emit (OpCodes.Clt_Un);
-                               else
-                                       ig.Emit (OpCodes.Clt);
-                               
-                               ig.Emit (OpCodes.Ldc_I4_0);
-                               
-                               opcode = OpCodes.Ceq;
+
+                       case Operator.GreaterThanOrEqual:
+                               if (IsUnsigned (l) || IsFloat (l))
+                                       ig.Emit (OpCodes.Clt_Un);
+                               else
+                                       ig.Emit (OpCodes.Clt);
+                               
+                               ig.Emit (OpCodes.Ldc_I4_0);
+                               
+                               opcode = OpCodes.Ceq;
+                               break;
+
+                       case Operator.BitwiseOr:
+                               opcode = OpCodes.Or;
+                               break;
+
+                       case Operator.BitwiseAnd:
+                               opcode = OpCodes.And;
+                               break;
+
+                       case Operator.ExclusiveOr:
+                               opcode = OpCodes.Xor;
+                               break;
+
+                       default:
+                               throw new InternalErrorException (oper.ToString ());
+                       }
+
+                       ig.Emit (opcode);
+               }
+
+               protected override void CloneTo (CloneContext clonectx, Expression t)
+               {
+                       Binary target = (Binary) t;
+
+                       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 (method == null && ec.CheckState && !IsFloat (left.Type))
+                                       method_name = "AddChecked";
+                               else
+                                       method_name = "Add";
+                               break;
+                       case Operator.BitwiseAnd:
+                               method_name = "And";
+                               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.BitwiseOr:
-                               opcode = OpCodes.Or;
+                       case Operator.LogicalOr:
+                               method_name = "OrElse";
                                break;
-
-                       case Operator.BitwiseAnd:
-                               opcode = OpCodes.And;
+                       case Operator.Modulus:
+                               method_name = "Modulo";
                                break;
-
-                       case Operator.ExclusiveOr:
-                               opcode = OpCodes.Xor;
+                       case Operator.Multiply:
+                               if (method == null && ec.CheckState && !IsFloat (left.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 (left.Type))
+                                       method_name = "SubtractChecked";
+                               else
+                                       method_name = "Subtract";
                                break;
 
                        default:
-                               throw new Exception ("This should not happen: Operator = "
-                                                    + oper.ToString ());
+                               throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
                        }
 
-                       ig.Emit (opcode);
-               }
-
-               protected override void CloneTo (CloneContext clonectx, Expression t)
-               {
-                       Binary target = (Binary) t;
-
-                       target.left = left.Clone (clonectx);
-                       target.right = right.Clone (clonectx);
+                       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);
                }
        }
 
@@ -3045,8 +3353,7 @@ namespace Mono.CSharp {
                {
                        ILGenerator ig = ec.ig;
                        
-                       if (Arguments != null) 
-                               Invocation.EmitArguments (ec, method, Arguments, false, null);
+                       Invocation.EmitArguments (ec, Arguments, false, null);
                        
                        if (method is MethodInfo)
                                ig.Emit (OpCodes.Call, (MethodInfo) method);
@@ -3060,30 +3367,59 @@ namespace Mono.CSharp {
        // b, c, d... may be strings or objects.
        //
        public class StringConcat : Expression {
-               ArrayList operands;
-               bool invalid = false;
-               bool emit_conv_done = false;
-               //
-               // Are we also concating objects?
-               //
-               bool is_strings_only = true;
+               ArrayList arguments;
                
                public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
                {
                        this.loc = loc;
                        type = TypeManager.string_type;
                        eclass = ExprClass.Value;
-               
-                       operands = new ArrayList (2);
+
+                       arguments = new ArrayList (2);
                        Append (ec, left);
                        Append (ec, right);
                }
-               
-               public override Expression DoResolve (EmitContext ec)
+
+               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)
                {
-                       if (invalid)
+                       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;
                }
                
@@ -3094,119 +3430,40 @@ namespace Mono.CSharp {
                        //
                        StringConstant sc = operand as StringConstant;
                        if (sc != null) {
-// TODO: it will be better to do this silently as an optimalization
-// int i = 0;
-// string s = "" + i;
-// because this code has poor performace
-//                             if (sc.Value.Length == 0)
-//                                     Report.Warning (-300, 3, Location, "Appending an empty string has no effect. Did you intend to append a space string?");
-
-                               if (operands.Count != 0) {
-                                       StringConstant last_operand = operands [operands.Count - 1] as StringConstant;
-                                       if (last_operand != null) {
-                                               operands [operands.Count - 1] = new StringConstant (last_operand.Value + ((StringConstant) operand).Value, last_operand.Location);
+                               if (arguments.Count != 0) {
+                                       Argument last_argument = (Argument) arguments [arguments.Count - 1];
+                                       StringConstant last_expr_constant = last_argument.Expr as StringConstant;
+                                       if (last_expr_constant != null) {
+                                               last_argument.Expr = new StringConstant (
+                                                       last_expr_constant.Value + sc.Value, sc.Location);
                                                return;
                                        }
                                }
-                       }
-                       
-
-                       //
-                       // Multiple (3+) concatenation are resolved as multiple StringConcat instances
-                       //
-                       StringConcat concat_oper = operand as StringConcat;
-                       if (concat_oper != null) {
-                               operands.AddRange (concat_oper.operands);
-                               return;
-                       }                       
-                       
-                       //
-                       // Conversion to object
-                       //
-                       if (operand.Type != TypeManager.string_type) {
-                               Expression no = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
-                               
-                               if (no == null) {
-                                       Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
-                                       invalid = true;
+                       } else {
+                               //
+                               // 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;
                                }
-                               operand = no;
                        }
-                       
-                       operands.Add (operand);
+
+                       arguments.Add (new Argument (operand));
+               }
+
+               Expression CreateConcatMemberExpression ()
+               {
+                       return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
                }
 
                public override void Emit (EmitContext ec)
                {
-                       MethodInfo concat_method = null;
-                       
-                       //
-                       // Do conversion to arguments; check for strings only
-                       //
-                       
-                       // This can get called multiple times, so we have to deal with that.
-                       if (!emit_conv_done) {
-                               emit_conv_done = true;
-                               for (int i = 0; i < operands.Count; i ++) {
-                                       Expression e = (Expression) operands [i];
-                                       is_strings_only &= e.Type == TypeManager.string_type;
-                               }
-                               
-                               for (int i = 0; i < operands.Count; i ++) {
-                                       Expression e = (Expression) operands [i];
-                                       
-                                       if (! is_strings_only && e.Type == TypeManager.string_type) {
-                                               // need to make sure this is an object, because the EmitParams
-                                               // method might look at the type of this expression, see it is a
-                                               // string and emit a string [] when we want an object [];
-                                               
-                                               e = EmptyCast.Create (e, TypeManager.object_type);
-                                       }
-                                       operands [i] = new Argument (e, Argument.AType.Expression);
-                               }
-                       }
-                       
-                       //
-                       // Find the right method
-                       //
-                       switch (operands.Count) {
-                       case 1:
-                               //
-                               // This should not be possible, because simple constant folding
-                               // is taken care of in the Binary code.
-                               //
-                               throw new Exception ("how did you get here?");
-                       
-                       case 2:
-                               concat_method = is_strings_only ? 
-                                       TypeManager.string_concat_string_string :
-                                       TypeManager.string_concat_object_object ;
-                               break;
-                       case 3:
-                               concat_method = is_strings_only ? 
-                                       TypeManager.string_concat_string_string_string :
-                                       TypeManager.string_concat_object_object_object ;
-                               break;
-                       case 4:
-                               //
-                               // There is not a 4 param overlaod for object (the one that there is
-                               // is actually a varargs methods, and is only in corlib because it was
-                               // introduced there before.).
-                               //
-                               if (!is_strings_only)
-                                       goto default;
-                               
-                               concat_method = TypeManager.string_concat_string_string_string_string;
-                               break;
-                       default:
-                               concat_method = is_strings_only ? 
-                                       TypeManager.string_concat_string_dot_dot_dot :
-                                       TypeManager.string_concat_object_dot_dot_dot ;
-                               break;
-                       }
-                       
-                       Invocation.EmitArguments (ec, concat_method, operands, false, null);
-                       ec.ig.Emit (OpCodes.Call, concat_method);
+                       Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
+                       concat = concat.Resolve (ec);
+                       if (concat != null)
+                               concat.Emit (ec);
                }
        }
 
@@ -3234,7 +3491,7 @@ namespace Mono.CSharp {
                {
                        ILGenerator ig = ec.ig;
                        
-                       Invocation.EmitArguments (ec, method, args, false, null);
+                       Invocation.EmitArguments (ec, args, false, null);
                        
                        ig.Emit (OpCodes.Call, (MethodInfo) method);
                        ig.Emit (OpCodes.Castclass, type);
@@ -3256,92 +3513,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, 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);
                }
        }
 
@@ -3473,6 +3698,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);
@@ -3480,11 +3714,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);
@@ -3571,6 +3800,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);
@@ -3749,6 +3986,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;
@@ -4007,6 +4251,11 @@ namespace Mono.CSharp {
                        return Name == pr.Name && referenced == pr.referenced;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       return Parameter.ExpressionTreeVariableReference ();
+               }
+
                //
                // Notice that for ref/out parameters, the type exposed is not the
                // same type exposed externally.
@@ -4116,15 +4365,13 @@ namespace Mono.CSharp {
                        }
                }
 
-               public static string FullDesc (Argument a)
+               public string GetSignatureForError ()
                {
-                       if (a.ArgType == AType.ArgList)
-                               return "__arglist";
+                       if (Expr.eclass == ExprClass.MethodGroup)
+                               return Expr.ExprClassName;
 
-                       return (a.ArgType == AType.Ref ? "ref " :
-                               (a.ArgType == AType.Out ? "out " : "")) +
-                               TypeManager.CSharpName (a.Expr.Type);
-               }
+                       return Expr.GetSignatureForError ();
+               }               
 
                public bool ResolveMethodGroup (EmitContext ec)
                {
@@ -4180,19 +4427,6 @@ namespace Mono.CSharp {
                                ml.AddressOf (ec, mode);
                }
 
-               public void EmitArrayArgument (EmitContext ec)
-               {
-                       Type argtype = Expr.Type;
-                       Expr.Emit (ec);
-                               
-                       if (argtype == TypeManager.uint32_type)
-                               ec.ig.Emit (OpCodes.Conv_U);
-                       else if (argtype == TypeManager.int64_type)
-                               ec.ig.Emit (OpCodes.Conv_Ovf_I);
-                       else if (argtype == TypeManager.uint64_type)
-                               ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
-               }
-
                public Argument Clone (CloneContext clonectx)
                {
                        return new Argument (Expr.Clone (clonectx), ArgType);
@@ -4204,8 +4438,9 @@ namespace Mono.CSharp {
        /// </summary>
        public class Invocation : ExpressionStatement {
                protected ArrayList Arguments;
-               Expression expr;
+               protected Expression expr;
                protected MethodGroupExpr mg;
+               bool arguments_resolved;
                
                //
                // arguments is an ArrayList, but we do not want to typecast,
@@ -4220,24 +4455,43 @@ 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)
+                       : this (expr, arguments)
+               {
+                       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);
                        }
+
+                       args = new ArrayList (Arguments.Count + 3);
+                       if (mg.IsInstance)
+                               args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
                        else
-                               sb = new StringBuilder ();
+                               args.Add (new Argument (new NullLiteral (loc).CreateExpressionTree (ec)));
+
+                       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));
+                       }
 
-                       sb.Append (TypeManager.CSharpSignature (mb));
-                       return sb.ToString ();
+                       return CreateExpressionFactoryCall ("Call", args);
                }
 
                public override Expression DoResolve (EmitContext ec)
@@ -4258,16 +4512,27 @@ 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;
                        }
 
                        //
                        // Next, evaluate all the expressions in the argument list
                        //
-                       if (Arguments != null)
-                       {
+                       if (Arguments != null && !arguments_resolved) {
                                for (int i = 0; i < Arguments.Count; ++i)
                                {
                                        if (!((Argument)Arguments[i]).Resolve(ec, loc))
@@ -4324,22 +4589,8 @@ namespace Mono.CSharp {
                                return null;
                        }
                        
-                       if (mg.InstanceExpression != null){
-                               mg.InstanceExpression.CheckMarshalByRefAccess ();
-
-                               //
-                               // This is used to check that no methods are called in struct
-                               // constructors before all the fields on the struct have been
-                               // initialized.
-                               //
-                               if (!method.IsStatic){
-                                       This mgthis = mg.InstanceExpression as This;
-                                       if (mgthis != null){
-                                               if (!mgthis.CheckThisUsage (ec))
-                                                       return  null;
-                                       }
-                               }
-                       }
+                       if (mg.InstanceExpression != null)
+                               mg.InstanceExpression.CheckMarshalByRefAccess (ec);
 
                        eclass = ExprClass.Value;
                        return this;
@@ -4347,7 +4598,7 @@ namespace Mono.CSharp {
 
                protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
                {
-                       return mg.OverloadResolve (ec, Arguments, false, loc);
+                       return mg.OverloadResolve (ec, ref Arguments, false, loc);
                }
 
                bool IsSpecialMethodInvocation (MethodBase method)
@@ -4362,38 +4613,6 @@ namespace Mono.CSharp {
                        return true;
                }
 
-               // <summary>
-               //   Emits the list of arguments as an array
-               // </summary>
-               static void EmitParams (EmitContext ec, ArrayList arguments, int idx, int count)
-               {
-                       ILGenerator ig = ec.ig;
-                       Type t = null;
-                       for (int j = 0; j < count; j++){
-                               Argument a = (Argument) arguments [j + idx];
-                               if (j == 0) {
-                                       t = a.Expr.Type;
-                                       IntConstant.EmitInt (ig, count);
-                                       ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
-                               }
-                               
-                               ig.Emit (OpCodes.Dup);
-                               IntConstant.EmitInt (ig, j);
-
-                               bool is_stobj, has_type_arg;
-                               OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
-                               if (is_stobj)
-                                       ig.Emit (OpCodes.Ldelema, t);
-
-                               a.Emit (ec);
-
-                               if (has_type_arg)
-                                       ig.Emit (op, t);
-                               else
-                                       ig.Emit (op);
-                       }
-               }
-               
                /// <summary>
                ///   Emits a list of resolved Arguments that are in the arguments
                ///   ArrayList.
@@ -4408,10 +4627,12 @@ namespace Mono.CSharp {
                ///   which will be duplicated before any other args. Only EmitCall
                ///   should be using this interface.
                /// </summary>
-               public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
+               public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
                {
-                       ParameterData pd = mb == null ? null : TypeManager.GetParameterData (mb);
-                       int top = pd.Count;
+                       if (arguments == null)
+                               return;
+
+                       int top = arguments.Count;
                        LocalTemporary [] temps = null;
                        
                        if (dup_args && top != 0)
@@ -4419,42 +4640,7 @@ namespace Mono.CSharp {
 
                        int argument_index = 0;
                        Argument a;
-                       for (int i = 0; i < top; i++){
-                               if (pd != null){
-                                       if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
-                                               Type p_type = pd.ParameterType (i);
-                                               int params_args_count = arguments == null ?
-                                                       0 : arguments.Count - top + 1;
-
-                                               // Fill not provided argument
-                                               if (params_args_count <= 0) {
-                                                       ILGenerator ig = ec.ig;
-                                                       IntConstant.EmitInt (ig, 0);
-                                                       ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (p_type));
-                                               } else {
-                                                       //
-                                                       // Special case if we are passing the same data as the
-                                                       // params argument, we do not need to recreate an array.
-                                                       //
-                                                       a = (Argument) arguments [argument_index];
-                                                       if (params_args_count == 1 && p_type == a.Type) {
-                                                               ++argument_index;
-                                                               a.Emit (ec);
-                                                       } else {
-                                                               EmitParams (ec, arguments, i, params_args_count);
-                                                               argument_index += params_args_count;
-                                                       }
-                                               }
-
-                                               if (dup_args) {
-                                                       ec.ig.Emit (OpCodes.Dup);
-                                                       temps [i] = new LocalTemporary (p_type);
-                                                       temps [i].Store (ec);
-                                               }
-                                               continue;
-                                       }
-                               }
-
+                       for (int i = 0; i < top; i++) {
                                a = (Argument) arguments [argument_index++];
                                a.Emit (ec);
                                if (dup_args) {
@@ -4549,25 +4735,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
@@ -4654,7 +4821,7 @@ namespace Mono.CSharp {
                        }
 
                        if (!omit_args)
-                               EmitArguments (ec, method, Arguments, dup_args, this_arg);
+                               EmitArguments (ec, Arguments, dup_args, this_arg);
 
 #if GMCS_SOURCE
                        if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
@@ -4934,7 +5101,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;
                }
@@ -4961,6 +5128,24 @@ 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);
+
+                       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)
                {
@@ -5030,6 +5215,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;
@@ -5084,7 +5277,7 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       method = method.OverloadResolve (ec, Arguments, false, loc);
+                       method = method.OverloadResolve (ec, ref Arguments, false, loc);
                        if (method == null)
                                return null;
 
@@ -5353,7 +5546,12 @@ namespace Mono.CSharp {
 
                void Error_IncorrectArrayInitializer ()
                {
-                       Error (178, "Invalid rank specifier: expected `,' or `]'");
+                       Error (178, "Invalid rank specifier: expected `,' or `]'");
+               }
+
+               protected override void Error_NegativeArrayIndex (Location loc)
+               {
+                       Report.Error (248, loc, "Cannot create an array with a negative size");
                }
                
                bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
@@ -5436,6 +5634,23 @@ namespace Mono.CSharp {
 
                        return true;
                }
+
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       if (dimensions != 1) {
+                               Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
+                               return null;
+                       }
+
+                       ArrayList 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)
+                                       args.Add (new Argument (e.CreateExpressionTree (ec)));
+                       }
+
+                       return CreateExpressionFactoryCall ("NewArrayInit", args);
+               }               
                
                public void UpdateIndices ()
                {
@@ -5561,13 +5776,9 @@ namespace Mono.CSharp {
 
                        foreach (Argument a in arguments){
                                if (!a.Resolve (ec, loc))
-                                       return null;
-
-                               Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
-                               if (real_arg == null)
-                                       return null;
+                                       continue;
 
-                               a.Expr = real_arg;
+                               a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
                        }
                                                        
                        eclass = ExprClass.Value;
@@ -5601,8 +5812,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)
@@ -5749,6 +5960,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
                        //
@@ -5853,17 +6073,13 @@ namespace Mono.CSharp {
                        }
                }
 
-               void EmitArrayArguments (EmitContext ec)
-               {
-                       foreach (Argument a in arguments)
-                               a.EmitArrayArgument (ec);
-               }
-               
                public override void Emit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
-                       
-                       EmitArrayArguments (ec);
+
+                       foreach (Argument a in arguments)
+                               a.Emit (ec);
+
                        if (arguments.Count == 1)
                                ig.Emit (OpCodes.Newarr, array_element_type);
                        else {
@@ -5939,8 +6155,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));
+                                       }
                        }
                }
        }
@@ -6132,17 +6356,22 @@ namespace Mono.CSharp {
                //
                // Called from Invocation to check if the invocation is correct
                //
-               public bool CheckThisUsage (EmitContext ec)
+               public override void CheckMarshalByRefAccess (EmitContext ec)
                {
                        if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
                            !variable_info.IsAssigned (ec)) {
                                Error (188, "The `this' object cannot be used before all of its " +
                                       "fields are assigned to");
                                variable_info.SetAssigned (ec);
-                               return false;
                        }
+               }
 
-                       return true;
+               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)
@@ -6155,7 +6384,7 @@ namespace Mono.CSharp {
                                Error (27, "Keyword `this' is not available in the current context");
                                return null;
                        }
-
+                       
                        return this;
                }
 
@@ -6300,6 +6529,12 @@ namespace Mono.CSharp {
                                return retval;
                        }
                }
+               
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
+                       return null;
+               }
 
                public override Expression DoResolve (EmitContext ec)
                {
@@ -6385,6 +6620,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;
@@ -6445,10 +6691,102 @@ namespace Mono.CSharp {
                {
                        type = TypeManager.type_type;
                        typearg = TypeManager.void_type;
-                       // See description in TypeOf.
+
+                       return DoResolveBase ();
+               }
+       }
+
+       internal class TypeOfMethod : Expression
+       {
+               readonly MethodBase method;
+
+               public TypeOfMethod (MethodBase method, Location loc)
+               {
+                       this.method = method;
+                       this.loc = loc;
+               }
+
+               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;
+                       }
+
+                       type = typeof (MethodBase);
+                       eclass = ExprClass.Value;
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       if (method is MethodInfo)
+                               ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo)method);
+                       else
+                               ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
+
+                       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)
+               {
+                       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, field);
+                       ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
+               }
        }
 
        /// <summary>
@@ -6478,8 +6816,8 @@ namespace Mono.CSharp {
 #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);
@@ -6530,9 +6868,6 @@ namespace Mono.CSharp {
 
                public QualifiedAliasMember (string alias, string identifier, Location l)
                {
-                       if (RootContext.Version == LanguageVersion.ISO_1)
-                               Report.FeatureIsNotAvailable (l, "namespace alias qualifier");
-
                        this.alias = alias;
                        this.identifier = identifier;
                        loc = l;
@@ -6678,14 +7013,11 @@ namespace Mono.CSharp {
                        }
 
                        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) {
@@ -6693,8 +7025,10 @@ namespace Mono.CSharp {
                                        "System.NullReferenceException");
                        }
 
-                       if (args != null)
-                               args.Resolve (ec);
+                       if (args != null) {
+                               if (!args.Resolve (ec))
+                                       return null;
+                       }
 
                        Expression member_lookup;
                        member_lookup = MemberLookup (
@@ -6706,15 +7040,24 @@ namespace Mono.CSharp {
                        }
 #endif
                        if (member_lookup == null) {
-                               ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Identifier);
-                               if (ex_method_lookup != null) {
-                                       ex_method_lookup.ExtensionExpression = expr_resolved;
+                               ExprClass expr_eclass = expr_resolved.eclass;
 
-                                       if (args != null) {
-                                               ex_method_lookup.SetTypeArguments (args);
-                                       }
+                               //
+                               // Extension methods are not allowed on all expression types
+                               //
+                               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, loc);
+                                       if (ex_method_lookup != null) {
+                                               ex_method_lookup.ExtensionExpression = expr_resolved;
+
+                                               if (args != null) {
+                                                       ex_method_lookup.SetTypeArguments (args);
+                                               }
 
-                                       return ex_method_lookup.DoResolve (ec);
+                                               return ex_method_lookup.DoResolve (ec);
+                                       }
                                }
 
                                expr = expr_resolved;
@@ -6837,17 +7180,30 @@ namespace Mono.CSharp {
                                if (silent)
                                        return null;
 
-                               member_lookup = MemberLookup(
-                                   rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
-                                       MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
+                               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) {
+                               if (member_lookup == null) {
                                        Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
-                                                     Identifier, new_expr.GetSignatureForError ());
+                                                         Identifier, new_expr.GetSignatureForError ());
                                } else {
-                               // TODO: Report.SymbolRelatedToPreviousError
-                                   member_lookup.Error_UnexpectedKind (null, "type", loc);
-                               }
+                                       // TODO: Report.SymbolRelatedToPreviousError
+                                       member_lookup.Error_UnexpectedKind (null, "type", loc);
+                               }
                                return null;
                        }
 
@@ -6857,11 +7213,14 @@ namespace Mono.CSharp {
 
 #if GMCS_SOURCE
                        TypeArguments the_args = args;
-                       if (TypeManager.HasGenericArguments (texpr.Type.DeclaringType)) {
-                               Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
-
+                       Type declaring_type = texpr.Type.DeclaringType;
+                       if (TypeManager.HasGenericArguments (declaring_type)) {
+                               while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
+                                       expr_type = expr_type.BaseType;
+                               }
+                               
                                TypeArguments new_args = new TypeArguments (loc);
-                               foreach (Type decl in decl_args)
+                               foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
                                        new_args.Add (new TypeExpression (decl, loc));
 
                                if (args != null)
@@ -6928,6 +7287,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)
                {
@@ -6977,6 +7342,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)
                {
@@ -7054,6 +7425,16 @@ namespace Mono.CSharp {
                        return Expr != null;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       ArrayList args = new ArrayList (Arguments.Count + 1);
+                       args.Add (new Argument (Expr.CreateExpressionTree (ec)));
+                       foreach (Argument a in Arguments)
+                               args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
+
+                       return CreateExpressionFactoryCall ("ArrayIndex", args);
+               }
+
                Expression MakePointerAccess (EmitContext ec, Type t)
                {
                        if (t == TypeManager.void_ptr_type){
@@ -7165,6 +7546,11 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       return ea.CreateExpressionTree (ec);
+               }
+
                public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
                {
                        return DoResolve (ec);
@@ -7184,41 +7570,26 @@ 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;
                        }
 
-                        type = TypeManager.GetElementType (t);
-                        if (type.IsPointer && !ec.InUnsafe){
+                       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);
                                return null;
                        }
 
-                       foreach (Argument a in ea.Arguments){
-                               Type argtype = a.Type;
-
-                               if (argtype == TypeManager.int32_type ||
-                                   argtype == TypeManager.uint32_type ||
-                                   argtype == TypeManager.int64_type ||
-                                   argtype == TypeManager.uint64_type) {
-                                       Constant c = a.Expr as Constant;
-                                       if (c != null && c.IsNegative) {
-                                               Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)");
-                                       }
-                                       continue;
-                               }
-
-                               //
-                               // Mhm.  This is strage, because the Argument.Type is not the same as
-                               // Argument.Expr.Type: the value changes depending on the ref/out setting.
-                               //
-                               // Wonder if I will run into trouble for this.
-                               //
-                               a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
-                               if (a.Expr == null)
-                                       return null;
+                       foreach (Argument a in ea.Arguments) {
+                               a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
                        }
                        
                        eclass = ExprClass.Variable;
@@ -7261,7 +7632,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);
@@ -7275,6 +7646,11 @@ namespace Mono.CSharp {
                                ig.Emit (OpCodes.Ldelem_Ref);
                }
 
+               protected override void Error_NegativeArrayIndex (Location loc)
+               {
+                       Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
+               }
+
                /// <summary>
                ///    Returns the right opcode to store an object of Type `t'
                ///    from an array of T.  
@@ -7285,7 +7661,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;
@@ -7386,7 +7762,7 @@ namespace Mono.CSharp {
                        }
 
                        for (int i = 0; i < ea.Arguments.Count; ++i) {
-                               ((Argument)ea.Arguments [i]).EmitArrayArgument (ec);
+                               ((Argument)ea.Arguments [i]).Emit (ec);
                                if (!prepare_for_load)
                                        continue;
 
@@ -7753,7 +8129,7 @@ namespace Mono.CSharp {
                        }
 
                        MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
-                       mg = mg.OverloadResolve (ec, arguments, false, loc);
+                       mg = mg.OverloadResolve (ec, ref arguments, false, loc);
                        if (mg == null)
                                return null;
 
@@ -7766,7 +8142,7 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       type = pi.PropertyType;
+                       type = TypeManager.TypeToCoreType (pi.PropertyType);
                        if (type.IsPointer && !ec.InUnsafe)
                                UnsafeError (loc);
 
@@ -7815,7 +8191,7 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       instance_expr.CheckMarshalByRefAccess ();
+                       instance_expr.CheckMarshalByRefAccess (ec);
                        eclass = ExprClass.IndexerAccess;
                        return this;
                }
@@ -8134,14 +8510,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;
                }
@@ -8151,6 +8527,16 @@ 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 Cast (new TypeExpression (typeof (MethodInfo), loc),
+                               new TypeOfMethod (method, loc))));
+                       return CreateExpressionFactoryCall ("Convert", args);
+               }
                        
                public override Expression DoResolve (EmitContext ec)
                {
@@ -8162,15 +8548,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);
                }
        }
 
@@ -8221,7 +8600,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);
@@ -8326,6 +8705,52 @@ namespace Mono.CSharp {
                }
        }
 
+       //
+       // Encapsulates a conversion rules required for array indexes
+       //
+       public class ArrayIndexCast : Expression
+       {
+               Expression expr;
+
+               public ArrayIndexCast (Expression expr)
+               {
+                       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 (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);
+                               
+                       if (type == TypeManager.int32_type)
+                               return;
+
+                       if (type == TypeManager.uint32_type)
+                               ec.ig.Emit (OpCodes.Conv_U);
+                       else if (type == TypeManager.int64_type)
+                               ec.ig.Emit (OpCodes.Conv_Ovf_I);
+                       else if (type == TypeManager.uint64_type)
+                               ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
+                       else
+                               throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
+               }
+       }
+
        //
        // Used by the fixed statement
        //
@@ -8350,6 +8775,12 @@ namespace Mono.CSharp {
 
                public override void Emit (EmitContext ec)
                {
+                       if (TypeManager.int_get_offset_to_string_data == null) {
+                               // TODO: Move to resolve !!
+                               TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedMethod (
+                                       TypeManager.runtime_helpers_type, "get_OffsetToStringData", loc, Type.EmptyTypes);
+                       }
+
                        ILGenerator ig = ec.ig;
 
                        ig.Emit (OpCodes.Ldloc, b);
@@ -8437,60 +8868,70 @@ 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)
+               public override Expression CreateExpressionTree (EmitContext ec)
                {
-                       if (initializer == null)
-                               return;
+                       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 ()));
 
-                       ElementInitializer target = (ElementInitializer) t;
-                       target.initializer = initializer.Clone (clonectx);
+                       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)
@@ -8505,17 +8946,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
                {
@@ -8525,49 +8969,52 @@ 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;
                }
 
-               protected override void CloneTo (CloneContext clonectx, Expression t)
+               public override Expression CreateExpressionTree (EmitContext ec)
                {
-                       CollectionElementInitializer target = (CollectionElementInitializer) t;
-                       ArrayList t_arguments = target.arguments = new ArrayList (arguments.Count);
-                       foreach (Expression e in arguments)
-                               t_arguments.Add (e.Clone (clonectx));
+                       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);
                }
 
                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);
                }
        }
        
@@ -8593,6 +9040,12 @@ namespace Mono.CSharp {
                        }
                }
 
+               public bool IsCollectionInitializer {
+                       get {
+                               return type == typeof (CollectionOrObjectInitializers);
+                       }
+               }
+
                protected override void CloneTo (CloneContext clonectx, Expression target)
                {
                        CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
@@ -8601,9 +9054,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) {
@@ -8648,10 +9116,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;
                }
@@ -8690,6 +9158,12 @@ namespace Mono.CSharp {
                                this.new_instance = newInstance;
                        }
 
+                       public override Expression CreateExpressionTree (EmitContext ec)
+                       {
+                               // Should not be reached
+                               throw new NotSupportedException ();
+                       }
+
                        public override Expression DoResolve (EmitContext ec)
                        {
                                return this;
@@ -8731,8 +9205,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;