2008-04-01 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / expression.cs
index 23b0605febbeb3df9645ecd43d09ef8155c63575..5e4e71a56f94dca8f05fca5d76e2a563f0e3da19 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)
+               readonly ArrayList arguments;
+               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,12 +64,11 @@ namespace Mono.CSharp {
 
                public override void Emit (EmitContext ec)
                {
-                       Invocation.EmitArguments (ec, args, false, null);
-                       ec.ig.Emit (OpCodes.Call, mi);
-                       return;
+                       mg.EmitCall (ec, arguments);
                }
-               
-               static public StaticCallExpr MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
+
+               [Obsolete ("It may not be compatible with expression trees")]
+               static public UserOperatorCall MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
                                                         Expression e, Location loc)
                {
                        ArrayList args;
@@ -69,18 +86,11 @@ namespace Mono.CSharp {
                        if (mg == null)
                                return null;
 
-                       return new StaticCallExpr ((MethodInfo) mg, args, loc);
+                       return new UserOperatorCall (mg, args, null, loc);
                }
 
-               public override void EmitStatement (EmitContext ec)
-               {
-                       Emit (ec);
-                       if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
-                               ec.ig.Emit (OpCodes.Pop);
-               }
-               
-               public MethodInfo Method {
-                       get { return mi; }
+               public MethodGroupExpr Method {
+                       get { return mg; }
                }
        }
 
@@ -370,17 +380,18 @@ namespace Mono.CSharp {
                        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);
+                       MethodGroupExpr user_op = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc) 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, loc);
 
-                               if (e == null){
+                               if (user_op == null) {
                                        Error23 (expr_type);
                                        return null;
                                }
-                               
-                               return e;
+
+                               return new UserOperatorCall (user_op, args, CreateExpressionTree, loc);
                        }
 
                        switch (Oper){
@@ -568,6 +579,32 @@ namespace Mono.CSharp {
                        return null;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       return CreateExpressionTree (ec, null);
+               }
+
+               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 ());
+                       }
+
+                       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);
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        if (Oper == Operator.AddressOf) {
@@ -604,7 +641,7 @@ namespace Mono.CSharp {
                public override void Emit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
-                       
+
                        switch (Oper) {
                        case Operator.UnaryPlus:
                                throw new Exception ("This should be caught by Resolve");
@@ -800,7 +837,7 @@ namespace Mono.CSharp {
                //
                // This is expensive for the simplest case.
                //
-               StaticCallExpr method;
+               UserOperatorCall method;
 
                public UnaryMutator (Mode m, Expression e, Location l)
                {
@@ -832,7 +869,7 @@ namespace Mono.CSharp {
                                (t == TypeManager.int64_type) ||
                                (t == TypeManager.uint64_type) ||
                                (t == TypeManager.char_type) ||
-                               (t.IsSubclassOf (TypeManager.enum_type)) ||
+                               (TypeManager.IsSubclassOf (t, TypeManager.enum_type)) ||
                                (t == TypeManager.float_type) ||
                                (t == TypeManager.double_type) ||
                                (t.IsPointer && t != TypeManager.void_ptr_type);
@@ -856,7 +893,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;
@@ -1008,7 +1045,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;
                        }
@@ -1280,8 +1317,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;
                        
                        }
@@ -1446,6 +1483,14 @@ namespace Mono.CSharp {
                        this.loc = loc;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       ArrayList args = new ArrayList (2);
+                       args.Add (new Argument (this));
+                       args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
+                       return CreateExpressionFactoryCall ("Constant", args);
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
@@ -1459,20 +1504,17 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       if (TypeManager.IsGenericParameter (type))
-                       {
+                       if (TypeManager.IsGenericParameter (type)) {
                                GenericConstraints constraints = TypeManager.GetTypeParameterConstraints(type);
                                if (constraints != null && constraints.IsReferenceType)
-                                       return new NullDefault (new NullLiteral (Location), type);
-                       }
-                       else
-                       {
-                               Constant c = New.Constantify(type);
+                                       return new EmptyConstantCast (new NullLiteral (Location), type);
+                       } else {
+                               Constant c = New.Constantify (type);
                                if (c != null)
-                                       return new NullDefault (c, type);
+                                       return new EmptyConstantCast (c, type);
 
                                if (!TypeManager.IsValueType (type))
-                                       return new NullDefault (new NullLiteral (Location), type);
+                                       return new EmptyConstantCast (new NullLiteral (Location), type);
                        }
                        eclass = ExprClass.Variable;
                        return this;
@@ -1499,18 +1541,247 @@ 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, bool lnull, bool rnull)
+                       {
+                               if (lnull)
+                                       return Convert.ImplicitConversionExists (ec, rexpr, right);
+                               if (rnull)
+                                       return Convert.ImplicitConversionExists (ec, lexpr, left);
+
+                               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, bool lnull, bool rnull)
+                       {
+                               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;
@@ -1519,29 +1790,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)
@@ -1636,949 +1910,860 @@ namespace Mono.CSharp {
                        return s;
                }
 
-               public override string ToString ()
-               {
-                       return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
-                               right.ToString () + ")";
-               }
-               
-               Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
+               static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
                {
-                       if (expr.Type == target_type)
-                               return expr;
-
-                       return Convert.ImplicitConversion (ec, expr, target_type, loc);
+                       Error_OperatorCannotBeApplied (loc, name, TypeManager.CSharpName (l), TypeManager.CSharpName (r));
                }
 
-               void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
+               public static void Error_OperatorCannotBeApplied (Location loc, string name, string left, string right)
                {
-                       Report.Error (
-                               34, loc, "Operator `" + OperName (oper) 
-                               + "' is ambiguous on operands of type `"
-                               + TypeManager.CSharpName (l) + "' "
-                               + "and `" + TypeManager.CSharpName (r)
-                               + "'");
+                       Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
+                               name, left, right);
                }
-
-               bool IsConvertible (EmitContext ec, Expression le, Expression re, Type t)
+               
+               protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
                {
-                       return Convert.ImplicitConversionExists (ec, le, t) && Convert.ImplicitConversionExists (ec, re, t);
+                       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);
+
+                       if (right.eclass == ExprClass.MethodGroup)
+                               r = left.ExprClassName;
+                       else
+                               r = TypeManager.CSharpName (right.Type);
+
+                       Error_OperatorCannotBeApplied (Location, OperName (oper), l, r);
                }
 
-               bool VerifyApplicable_Predefined (EmitContext ec, Type t)
+               public static string GetOperatorMetadataName (Operator op)
                {
-                       if (!IsConvertible (ec, left, right, t))
-                               return false;
-                       left = ForceConversion (ec, left, t);
-                       right = ForceConversion (ec, right, t);
-                       type = t;
-                       return true;
+                       return oper_names [(int)(op & Operator.ValuesOnlyMask)];
                }
 
-               bool IsApplicable_String (EmitContext ec, Expression le, Expression re, Operator oper)
+               static bool IsUnsigned (Type t)
                {
-                       bool l = Convert.ImplicitConversionExists (ec, le, TypeManager.string_type);
-                       bool r = Convert.ImplicitConversionExists (ec, re, TypeManager.string_type);
+                       while (t.IsPointer)
+                               t = TypeManager.GetElementType (t);
 
-                       if (oper == Operator.Equality || oper == Operator.Inequality)
-                               return l && r;
-                       if (oper == Operator.Addition)
-                               return l || r;
-                       return false;
+                       return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
+                               t == TypeManager.ushort_type || t == TypeManager.byte_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;
-               }
-                                       
-               Expression CheckShiftArguments (EmitContext ec)
-               {
-                       Expression new_left = Make32or64 (ec, left);
-                       Expression new_right = ForceConversion (ec, right, TypeManager.int32_type);
-                       if (new_left == null || new_right == null) {
-                               Error_OperatorCannotBeApplied ();
-                               return null;
+                               // 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;
+                               }
                        }
-                       type = new_left.Type;
-                       int shiftmask = (type == TypeManager.int32_type || type == TypeManager.uint32_type) ? 31 : 63;
-                       left = new_left;
-                       right = new Binary (Binary.Operator.BitwiseAnd, new_right, new IntConstant (shiftmask, loc)).DoResolve (ec);
-                       return this;
-               }
 
-               //
-               // This is used to check if a test 'x == null' can be optimized to a reference equals,
-               // i.e., not invoke op_Equality.
-               //
-               static bool EqualsNullIsReferenceEquals (Type t)
-               {
-                       return t == TypeManager.object_type || t == TypeManager.string_type ||
-                               t == TypeManager.delegate_type || t.IsSubclassOf (TypeManager.delegate_type);
-               }
+                       if (standard_operators == null)
+                               CreateStandardOperatorsTable ();
 
-               static void Warning_UnintendedReferenceComparison (Location loc, string side, Type type)
-               {
-                       Report.Warning ((side == "left" ? 252 : 253), 2, loc,
-                               "Possible unintended reference comparison; to get a value comparison, " +
-                               "cast the {0} hand side to type `{1}'.", side, TypeManager.CSharpName (type));
+                       return ResolveOperatorPredefined (ec, standard_operators, primitives_only);
                }
 
-               static void Warning_Constant_Result (Location loc, bool result, Type type)
-               {
-                       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"); 
-               }
-                       
-               Expression ResolveOperator (EmitContext ec)
+               Constant EnumLiftUp (Constant left, Constant right)
                {
-                       Type l = left.Type;
-                       Type r = right.Type;
+                       switch (oper) {
+                       case Operator.BitwiseOr:
+                       case Operator.BitwiseAnd:
+                       case Operator.ExclusiveOr:
+                       case Operator.Equality:
+                       case Operator.Inequality:
+                       case Operator.LessThan:
+                       case Operator.LessThanOrEqual:
+                       case Operator.GreaterThan:
+                       case Operator.GreaterThanOrEqual:
+                               if (left is EnumConstant)
+                                       return left;
+                               
+                               if (left.IsZeroInteger)
+                                       return new EnumConstant (left, right.Type);
+                               
+                               break;
+                               
+                       case Operator.Addition:
+                       case Operator.Subtraction:
+                               return left;
+                               
+                       case Operator.Multiply:
+                       case Operator.Division:
+                       case Operator.Modulus:
+                       case Operator.LeftShift:
+                       case Operator.RightShift:
+                               if (right is EnumConstant || left is EnumConstant)
+                                       break;
+                               return left;
+                       }
+                       Error_OperatorCannotBeApplied (this.left, this.right);
+                       return null;
+               }
 
-                       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;
-                                       } 
+               //
+               // The `|' operator used on types which were extended is dangerous
+               //
+               void CheckBitwiseOrOnSignExtended ()
+               {
+                       OpcodeCast lcast = left as OpcodeCast;
+                       if (lcast != null) {
+                               if (IsUnsigned (lcast.UnderlyingType))
+                                       lcast = null;
+                       }
 
-                                       //
-                                       // 7.9.9 Equality operators and null
-                                       //
-                                       // CSC 2 has this behavior, it allows structs to be compared
-                                       // with the null literal *outside* of a generics context and
-                                       // inlines that as true or false.
-                                       //
-                                       // This is, in my opinion, completely wrong.
-                                       //
-                                       if (RootContext.Version != LanguageVersion.ISO_1 && l.IsValueType) {
-                                               if (!TypeManager.IsPrimitiveType (l) && !TypeManager.IsEnumType (l)) {
-                                                       if (MemberLookup (ec.ContainerType, l, oper_names [(int)Operator.Equality], MemberTypes.Method, AllBindingFlags, loc) == null &&
-                                                               MemberLookup (ec.ContainerType, l, oper_names [(int)Operator.Inequality], MemberTypes.Method, AllBindingFlags, loc) == null) {
-                                                               Error_OperatorCannotBeApplied ();
-                                                               return null;
-                                                       }
-                                               }
+                       OpcodeCast rcast = right as OpcodeCast;
+                       if (rcast != null) {
+                               if (IsUnsigned (rcast.UnderlyingType))
+                                       rcast = null;
+                       }
 
-                                               Warning_Constant_Result (loc, oper == Operator.Inequality, l);
-                                               return new BoolConstant (oper == Operator.Inequality, loc);
-                                       }
-                               }
+                       if (lcast == null && rcast == null)
+                               return;
 
-                               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;
-                                       }
+                       // FIXME: consider constants
 
-                                       //
-                                       // 7.9.9 Equality operators and null
-                                       //
-                                       // CSC 2 has this behavior, it allows structs to be compared
-                                       // with the null literal *outside* of a generics context and
-                                       // inlines that as true or false.
-                                       //
-                                       // This is, in my opinion, completely wrong.
-                                       //
-                                       if (RootContext.Version != LanguageVersion.ISO_1 && r.IsValueType){
-                                               if (!TypeManager.IsPrimitiveType (r) && !TypeManager.IsEnumType (r)) {
-                                                       if (MemberLookup (ec.ContainerType, r, oper_names [(int) Operator.Equality], MemberTypes.Method, AllBindingFlags, loc) == null &&
-                                                               MemberLookup (ec.ContainerType, r, oper_names [(int) Operator.Inequality], MemberTypes.Method, AllBindingFlags, loc) == null) {
-                                                               Error_OperatorCannotBeApplied ();
-                                                               return null;
-                                                       }
-                                               }
+                       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));
+               }
 
-                                               Warning_Constant_Result (loc, oper == Operator.Inequality, r);
-                                               return new BoolConstant (oper == Operator.Inequality, loc);
-                                       }
-                               }
+               static void CreatePointerOperatorsTable ()
+               {
+                       ArrayList temp = new ArrayList ();
 
-                               //
-                               // Optimize out call to op_Equality in a few cases.
-                               //
-                               if ((l == TypeManager.null_type && EqualsNullIsReferenceEquals (r)) ||
-                                   (r == TypeManager.null_type && EqualsNullIsReferenceEquals (l))) {
-                                       Type = TypeManager.bool_type;
-                                       return this;
-                               }
+                       //
+                       // 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));
 
-                               // IntPtr equality
-                               if (l == TypeManager.intptr_type && r == TypeManager.intptr_type) {
-                                       Type = TypeManager.bool_type;
-                                       return this;
-                               }
+                       //
+                       // 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));
 
-#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;
-                               }
+                       //
+                       // long operator - (T* x, T *y)
+                       //
+                       temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
 
-                               if (mg != null) {
-                                       Expression e = ImplicitDelegateCreation.Create (ec, mg, delegate_type, loc);
-                                       if (e == null)
-                                               return null;
+                       pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
+               }
 
-                                       // Find operator method
-                                       string op = oper_names[(int)oper];
-                                       MemberInfo[] mi = TypeManager.MemberLookup(ec.ContainerType, null,
-                                               TypeManager.delegate_type, MemberTypes.Method, AllBindingFlags, op, null);
+               static void CreateStandardOperatorsTable ()
+               {
+                       ArrayList temp = new ArrayList ();
+                       Type bool_type = TypeManager.bool_type;
 
-                                       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));
+                       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));
+               }
+
+               //
+               // Rules used during binary numeric promotion
+               //
+               static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
+               {
+                       Expression temp;
+                       Type etype;
 
-                                       return new BinaryMethod (TypeManager.bool_type, (MethodInfo)mi [0], args);
+                       Constant c = prim_expr as Constant;
+                       if (c != null) {
+                               temp = c.ConvertImplicitly (type);
+                               if (temp != null) {
+                                       prim_expr = temp;
+                                       return true;
                                }
-#endif                         
-                               if (l == TypeManager.anonymous_method_type || r == TypeManager.anonymous_method_type) {
-                                       Error_OperatorCannotBeApplied(Location, OperName(oper),
-                                               left.ExprClassName, right.ExprClassName);
-                                       return null;
-                               }                               
                        }
 
+                       if (type == TypeManager.uint32_type) {
+                               etype = prim_expr.Type;
+                               if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
+                                       type = TypeManager.int64_type;
 
-                       //
-                       // 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))) {
+                                       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) {
                                //
-                               // Step 1: Perform Operator Overload location
+                               // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
                                //
-                               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 (type == TypeManager.int32_type || type == TypeManager.int64_type ||
+                                       type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
+                                       return false;
+                       }
 
-                               if (union != null) {
-                                       ArrayList args = new ArrayList (2);
-                                       args.Add (new Argument (left, Argument.AType.Expression));
-                                       args.Add (new Argument (right, Argument.AType.Expression));
+                       temp = Convert.ImplicitNumericConversion (prim_expr, type);
+                       if (temp == null)
+                               return false;
 
-                                       union = union.OverloadResolve (ec, ref args, true, Location.Null);
+                       prim_expr = temp;
+                       return true;
+               }
 
-                                       if (union != null) {
-                                               MethodInfo mi = (MethodInfo) union;
-                                               return new BinaryMethod (mi.ReturnType, mi, args);
-                                       }
-                               }
-                       }
+               //
+               // 7.2.6.2 Binary numeric promotions
+               //
+               public bool DoBinaryOperatorPromotion (EmitContext ec)
+               {
+                       Type ltype = left.Type;
+                       Type rtype = right.Type;
+                       Expression 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;
-                                       }
+                       foreach (Type t in ConstantFold.binary_promotions) {
+                               if (t == ltype)
+                                       return t == rtype || DoNumericPromotion (ref right, ref left, t);
 
-                                       //
-                                       // 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);
-                                       }
+                               if (t == rtype)
+                                       return t == ltype || DoNumericPromotion (ref left, ref right, t);
+                       }
 
-                                       // 
-                                       // Append to existing string concatenation
-                                       //
-                                       if (left is StringConcat) {
-                                               ((StringConcat) left).Append (ec, right);
-                                               return left;
-                                       }
+                       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);
 
-                                       //
-                                       // Otherwise, start a new concat expression using converted expression
-                                       //
-                                       return new StringConcat (ec, loc, left, right).Resolve (ec);
-                               }
+                               if (temp == null)
+                                       return false;
+                               left = temp;
+                       }
 
-                               //
-                               // Transform a + ( - b) into a - b
-                               //
-                               if (right is Unary){
-                                       Unary right_unary = (Unary) right;
+                       if (rtype != int32) {
+                               Constant c = right as Constant;
+                               if (c != null)
+                                       temp = c.ImplicitConversionRequired (int32, loc);
+                               else
+                                       temp = Convert.ImplicitNumericConversion (right, int32);
 
-                                       if (right_unary.Oper == Unary.Operator.UnaryNegation){
-                                               return new Binary (Operator.Subtraction, left, right_unary.Expr).Resolve (ec);
-                                       }
-                               }
+                               if (temp == null)
+                                       return false;
+                               right = temp;
                        }
 
-                       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;
-                                       }
+                       return true;
+               }
 
-                                       type = TypeManager.bool_type;
-                                       return this;
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       if (left == null)
+                               return null;
+
+                       if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
+                               left = ((ParenthesizedExpression) left).Expr;
+                               left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
+                               if (left == null)
+                                       return null;
+
+                               if (left.eclass == ExprClass.Type) {
+                                       Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
+                                       return null;
                                }
+                       } else
+                               left = left.Resolve (ec);
 
-                               if (l.IsPointer || r.IsPointer) {
-                                       if (l.IsPointer && r.IsPointer) {
-                                               type = TypeManager.bool_type;
-                                               return this;
-                                       }
+                       if (left == null)
+                               return null;
 
-                                       if (l.IsPointer && r == TypeManager.null_type) {
-                                               right = new EmptyConstantCast (NullPointer.Null, l);
-                                               type = TypeManager.bool_type;
-                                               return this;
-                                       }
+                       Constant lc = left as Constant;
 
-                                       if (r.IsPointer && l == TypeManager.null_type) {
-                                               left = new EmptyConstantCast (NullPointer.Null, r);
-                                               type = TypeManager.bool_type;
-                                               return this;
-                                       }
-                               }
+                       if (lc != null && lc.Type == TypeManager.bool_type &&
+                               ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
+                                (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
 
-#if GMCS_SOURCE
-                               if (l.IsGenericParameter && r.IsGenericParameter) {
-                                       GenericConstraints l_gc, r_gc;
+                               // FIXME: resolve right expression as unreachable
+                               // right.Resolve (ec);
 
-                                       l_gc = TypeManager.GetTypeParameterConstraints (l);
-                                       r_gc = TypeManager.GetTypeParameterConstraints (r);
+                               Report.Warning (429, 4, loc, "Unreachable expression code detected");
+                               return left;
+                       }
 
-                                       if ((l_gc == null) || (r_gc == null) ||
-                                           !(l_gc.HasReferenceTypeConstraint || l_gc.HasClassConstraint) ||
-                                           !(r_gc.HasReferenceTypeConstraint || r_gc.HasClassConstraint)) {
-                                               Error_OperatorCannotBeApplied ();
-                                               return null;
-                                       }
+                       right = right.Resolve (ec);
+                       if (right == null)
+                               return null;
 
-                               }
-#endif
+                       eclass = ExprClass.Value;
+                       Constant rc = right as Constant;
 
-                               //
-                               // 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;
+                       // 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;
 
-                                       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);
+                               right = rc = EnumLiftUp (rc, lc);
+                               if (rc == null)
+                                       return null;
+                       }
 
-                                       if (!left_to_right && !right_to_left) {
-                                               Error_OperatorCannotBeApplied ();
-                                               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 (left_to_right && left_operators != null &&
-                                           Report.WarningLevel >= 2) {
-                                               ArrayList args = new ArrayList (2);
-                                               args.Add (new Argument (left, Argument.AType.Expression));
-                                               args.Add (new Argument (left, Argument.AType.Expression));
-                                               if (left_operators.OverloadResolve (ec, ref args, true, Location.Null) != null)
-                                                       Warning_UnintendedReferenceComparison (loc, "right", l);
+                                       if ((ResolveOperator (ec)) == null) {
+                                               Error_OperatorCannotBeApplied (left, right);
+                                               return null;
                                        }
 
-                                       if (right_to_left && right_operators != null &&
-                                           Report.WarningLevel >= 2) {
-                                               ArrayList args = new ArrayList (2);
-                                               args.Add (new Argument (right, Argument.AType.Expression));
-                                               args.Add (new Argument (right, Argument.AType.Expression));
-                                               if (right_operators.OverloadResolve (ec, ref args, true, Location.Null) != null)
-                                                       Warning_UnintendedReferenceComparison (loc, "left", r);
+                                       if (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;
 
-                                       //
-                                       // 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);
+                                       // The result is a constant with side-effect
+                                       return new SideEffectConstant (lc, right, loc);
+                               }
+                       }
 
-                                       return this;
+                       // 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);
                        }
 
-                       // Only perform numeric promotions on:
-                       // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
-                       //
-                       if (oper == Operator.Addition || oper == Operator.Subtraction) {
-                               if (TypeManager.IsDelegateType (l)){
-                                       if (((right.eclass == ExprClass.MethodGroup) ||
-                                            (r == TypeManager.anonymous_method_type))){
-                                               if ((RootContext.Version != LanguageVersion.ISO_1)){
-                                                       Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
-                                                       if (tmp == null)
-                                                               return null;
-                                                       right = tmp;
-                                                       r = right.Type;
-                                               }
-                                       }
+                       if ((TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type) ||
+                               (left is NullLiteral && right.Type.IsValueType) || (right is NullLiteral && left.Type.IsValueType)) &&
+                               !(this is Nullable.LiftedBinaryOperator))
+                               return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
 
-                                       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;
+                       return DoResolveCore (ec, left, right);
+               }
 
-                                               if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral)) {
-                                                       Error_OperatorCannotBeApplied ();
-                                                       return null;
-                                               }
+               protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
+               {
+                       Expression expr = ResolveOperator (ec);
+                       if (expr == null)
+                               Error_OperatorCannotBeApplied (left_orig, right_orig);
 
-                                               return new BinaryDelegate (l, method, args);
-                                       }
-                               }
+                       if (left == null || right == null)
+                               throw new InternalErrorException ("Invalid conversion");
 
-                               //
-                               // Pointer arithmetic:
-                               //
-                               // T* operator + (T* x, int y);
-                               // T* operator + (T* x, uint y);
-                               // T* operator + (T* x, long y);
-                               // T* operator + (T* x, ulong y);
-                               //
-                               // T* operator + (int y,   T* x);
-                               // T* operator + (uint y,  T *x);
-                               // T* operator + (long y,  T *x);
-                               // T* operator + (ulong y, T *x);
-                               //
-                               // T* operator - (T* x, int y);
-                               // T* operator - (T* x, uint y);
-                               // T* operator - (T* x, long y);
-                               // T* operator - (T* x, ulong y);
-                               //
-                               // long operator - (T* x, T *y)
-                               //
-                               if (l.IsPointer){
-                                       if (r.IsPointer && oper == Operator.Subtraction){
-                                               if (r == l)
-                                                       return new PointerArithmetic (
-                                                               false, left, right, TypeManager.int64_type,
-                                                               loc).Resolve (ec);
-                                       } else {
-                                               Expression t = Make32or64 (ec, right);
-                                               if (t != null)
-                                                       return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc).Resolve (ec);
-                                       }
-                               } else if (r.IsPointer && oper == Operator.Addition){
-                                       Expression t = Make32or64 (ec, left);
-                                       if (t != null)
-                                               return new PointerArithmetic (true, right, t, r, loc).Resolve (ec);
+                       if (oper == Operator.BitwiseOr)
+                               CheckBitwiseOrOnSignExtended ();
+
+                       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;
                        }
-                       
-                       //
-                       // Enumeration operators
-                       //
-                       bool lie = TypeManager.IsEnumType (l);
-                       bool rie = TypeManager.IsEnumType (r);
-                       if (lie || rie){
-                               Expression temp;
 
-                               // U operator - (E e, E f)
-                               if (lie && rie){
-                                       if (oper == Operator.Subtraction){
-                                               if (l == r){
-                                                       type = TypeManager.EnumToUnderlying (l);
-                                                       return this;
-                                               }
-                                               Error_OperatorCannotBeApplied ();
-                                               return null;
-                                       }
+                       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) {
+                               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);
                                }
-                                       
+
+                               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) {
                                //
-                               // operator + (E e, U x)
-                               // operator - (E e, U x)
+                               // 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 (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;
+                               if ((oper & Operator.ComparisonMask) != 0) {
+                                       type = TypeManager.bool_type;
+                               } else if ((oper & Operator.BitwiseMask) != 0) {
+                                       type = ltype;
+                               }
+
+                               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;
                                        }
 
-                                       type = enum_type;
                                        return this;
                                }
-                               
-                               if (!rie){
-                                       temp = Convert.ImplicitConversion (ec, right, l, loc);
-                                       if (temp != null)
-                                               right = temp;
-                                       else {
-                                               Error_OperatorCannotBeApplied ();
-                                               return null;
-                                       }
-                               } if (!lie){
-                                       temp = Convert.ImplicitConversion (ec, left, r, loc);
-                                       if (temp != null){
-                                               left = temp;
-                                               l = r;
-                                       } else {
-                                               Error_OperatorCannotBeApplied ();
-                                               return null;
-                                       }
-                               }
+                       }
 
-                               if (oper == Operator.Equality || oper == Operator.Inequality ||
-                                   oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
-                                   oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
-                                       if (left.Type != right.Type){
-                                               Error_OperatorCannotBeApplied ();
+                       Type underlying_type;
+                       if (lenum && !renum) {
+                               //
+                               // E operator + (E e, U x)
+                               // E operator - (E e, U x)
+                               //
+                               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 = TypeManager.bool_type;
-                                       return this;
-                               }
 
-                               if (oper == Operator.BitwiseAnd ||
-                                   oper == Operator.BitwiseOr ||
-                                   oper == Operator.ExclusiveOr){
-                                       if (left.Type != right.Type){
-                                               Error_OperatorCannotBeApplied ();
-                                               return null;
-                                       }
-                                       type = l;
+                                       right = temp;
+                                       type = ltype;
                                        return this;
                                }
-                               Error_OperatorCannotBeApplied ();
+
                                return null;
                        }
-                       
-                       if (oper == Operator.LeftShift || oper == Operator.RightShift)
-                               return CheckShiftArguments (ec);
-
-                       if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
-                               if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
-                                       type = TypeManager.bool_type;
-                                       return this;
-                               }
 
-                               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);
+                       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;
 
-                               if (left_operators_e != null && right_operators_e != null) {
-                                       left = left_operators_e;
-                                       right = right_operators_e;
-                                       type = TypeManager.bool_type;
+                                       left = temp;
+                                       type = rtype;
                                        return this;
                                }
+                       }
 
-                               Expression e = new ConditionalLogicalOperator (
-                                       oper == Operator.LogicalAnd, left, right, l, loc);
-                               return e.Resolve (ec);
-                       } 
+                       //
+                       // U operator - (E e, E f)
+                       //
+                       if (oper == Operator.Subtraction) {
+                               if (!TypeManager.IsEqual (ltype, rtype))
+                                       return null;
 
-                       Expression orig_left = left;
-                       Expression orig_right = right;
+                               type = TypeManager.GetEnumUnderlyingType (ltype);
+                               return this;
+                       }
 
+                       return null;
+               }
+
+               //
+               // 7.9.6 Reference type equality operators
+               //
+               Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
+               {
                        //
-                       // operator & (bool x, bool y)
-                       // operator | (bool x, bool y)
-                       // operator ^ (bool x, bool y)
+                       // operator != (object a, object b)
+                       // operator == (object a, object b)
                        //
-                       if (oper == Operator.BitwiseAnd ||
-                           oper == Operator.BitwiseOr ||
-                           oper == Operator.ExclusiveOr) {
-                               if (OverloadResolve_PredefinedIntegral (ec)) {
-                                       if (IsConvertible (ec, orig_left, orig_right, TypeManager.bool_type)) {
-                                               Error_OperatorAmbiguous (loc, oper, l, r);
-                                               return null;
-                                       }
 
-                                       if (oper == Operator.BitwiseOr && l != r && !(orig_right is Constant) && right is OpcodeCast &&
-                                               (r == TypeManager.sbyte_type || r == TypeManager.short_type ||
-                                                r == TypeManager.int32_type || r == TypeManager.int64_type)) {
-                                                       Report.Warning (675, 3, loc, "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
-                                                               TypeManager.CSharpName (r));
-                                       }
-                                       
-                               } else if (!VerifyApplicable_Predefined (ec, TypeManager.bool_type)) {
-                                       Error_OperatorCannotBeApplied ();
+                       // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
+
+                       if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
+                               return null;
+
+                       type = TypeManager.bool_type;
+                       GenericConstraints constraints;
+
+                       bool lgen = TypeManager.IsGenericParameter (l);
+
+                       if (TypeManager.IsEqual (l, r)) {
+                               if (lgen) {
+                                       //
+                                       // Only allow to compare same reference type parameter
+                                       //
+                                       constraints = TypeManager.GetTypeParameterConstraints (l);
+                                       if (constraints != null && constraints.IsReferenceType)
+                                               return this;
+
                                        return null;
                                }
+
+                               if (l == TypeManager.anonymous_method_type)
+                                       return null;
+
+                               if (TypeManager.IsValueType (l))
+                                       return null;
+
                                return this;
                        }
-                       
+
+                       bool rgen = TypeManager.IsGenericParameter (r);
+
                        //
-                       // Pointer comparison
+                       // a, Both operands are reference-type values or the value null
+                       // b, One operand is a value of type T where T is a type-parameter and
+                       // the other operand is the value null. Furthermore T does not have the
+                       // value type constrain
                        //
-                       if (l.IsPointer && r.IsPointer){
-                               if (oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
-                                   oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
-                                       type = TypeManager.bool_type;
+                       if (left is NullLiteral || right is NullLiteral) {
+                               if (lgen) {
+                                       constraints = TypeManager.GetTypeParameterConstraints (l);
+                                       if (constraints != null && constraints.HasValueTypeConstraint)
+                                               return null;
+
+                                       left = new BoxedCast (left, TypeManager.object_type);
                                        return this;
                                }
-                       }
 
-                       if (OverloadResolve_PredefinedIntegral (ec)) {
-                               if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
-                                       Error_OperatorAmbiguous (loc, oper, l, r);
-                                       return null;
+                               if (rgen) {
+                                       constraints = TypeManager.GetTypeParameterConstraints (r);
+                                       if (constraints != null && constraints.HasValueTypeConstraint)
+                                               return null;
+
+                                       right = new BoxedCast (right, TypeManager.object_type);
+                                       return this;
                                }
-                       } else if (OverloadResolve_PredefinedFloating (ec)) {
-                               if (IsConvertible (ec, orig_left, orig_right, TypeManager.decimal_type) ||
-                                   IsApplicable_String (ec, orig_left, orig_right, oper)) {
-                                       Error_OperatorAmbiguous (loc, oper, l, r);
+                       }
+
+                       //
+                       // An interface is converted to the object before the
+                       // standard conversion is applied. It's not clear from the
+                       // standard but it looks like it works like that.
+                       //
+                       if (lgen) {
+                               constraints = TypeManager.GetTypeParameterConstraints (l);
+                               if (constraints == null || constraints.IsReferenceType)
                                        return null;
-                               }
-                       } else if (VerifyApplicable_Predefined (ec, TypeManager.decimal_type)) {
-                               if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
-                                       Error_OperatorAmbiguous (loc, oper, l, r);
+                       } else if (l.IsInterface) {
+                               l = TypeManager.object_type;
+                       }
+
+                       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";
+
+                       //
+                       // 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;
+                       }
 
-                       l = left.Type;
-                       r = right.Type;
+                       if (Convert.ImplicitReferenceConversionExists (right, l)) {
+                               if (r == TypeManager.string_type)
+                                       Report.Warning (252, 2, loc, ref_comparison, "left");
+
+                               return this;
+                       }
+
+                       return null;
+               }
+
+
+               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;
+                               }
+
+                               if (!r.IsPointer) {
+                                       temp = Convert.ImplicitConversion (ec, right, l, right.Location);
+                                       if (temp == null)
+                                               return null;
+                                       right = temp;
+                               }
 
-                       if (l == TypeManager.decimal_type || l == TypeManager.string_type || r == TypeManager.string_type) {
-                               Type lookup = l;
-                               if (r == TypeManager.string_type)
-                                       lookup = r;
-                               MethodGroupExpr ops = (MethodGroupExpr) MemberLookup (
-                                       ec.ContainerType, lookup, oper_names [(int) oper],
-                                       MemberTypes.Method, AllBindingFlags, loc);
-                               ArrayList args = new ArrayList (2);
-                               args.Add (new Argument (left, Argument.AType.Expression));
-                               args.Add (new Argument (right, Argument.AType.Expression));
-                               ops = ops.OverloadResolve (ec, ref args, true, Location.Null);
-                               return new BinaryMethod (type, (MethodInfo)ops, args);
+                               type = TypeManager.bool_type;
+                               return this;
                        }
 
-                       return this;
+                       if (pointer_operators == null)
+                               CreatePointerOperatorsTable ();
+
+                       return ResolveOperatorPredefined (ec, pointer_operators, false);
                }
 
-               Constant EnumLiftUp (Constant left, Constant right)
+               //
+               // Build-in operators method overloading
+               //
+               protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only)
                {
-                       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);
+                       PredefinedOperator best_operator = null;
+                       Type l = left.Type;
+                       Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
 
-                                       break;
+                       bool left_is_null = left is NullLiteral && RootContext.Version >= LanguageVersion.ISO_2;
+                       bool right_is_null = right is NullLiteral && RootContext.Version >= LanguageVersion.ISO_2;
+                       
+                       foreach (PredefinedOperator po in operators) {
+                               if ((po.OperatorsMask & oper_mask) == 0)
+                                       continue;
 
-                               case Operator.Addition:
-                               case Operator.Subtraction:
-                                       return left;
+                               if (primitives_only) {
+                                       if (!po.IsPrimitiveApplicable (l))
+                                               continue;
+                               } else {
+                                       if (!po.IsApplicable (ec, left, right, left_is_null, right_is_null))
+                                               continue;
+                               }
 
-                               case Operator.Multiply:
-                               case Operator.Division:
-                               case Operator.Modulus:
-                               case Operator.LeftShift:
-                               case Operator.RightShift:
-                                       if (right is EnumConstant || left is EnumConstant)
+                               if (best_operator == null) {
+                                       best_operator = po;
+                                       if (primitives_only)
                                                break;
-                                       return left;
-                       }
-                       Error_OperatorCannotBeApplied ();
-                       return null;
-               }
-
-               public override Expression DoResolve (EmitContext ec)
-               {
-                       if (left == null)
-                               return null;
-
-                       if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
-                               left = ((ParenthesizedExpression) left).Expr;
-                               left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
-                               if (left == null)
-                                       return null;
 
-                               if (left.eclass == ExprClass.Type) {
-                                       Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
-                                       return null;
+                                       continue;
                                }
-                       } else
-                               left = left.Resolve (ec);
 
-                       if (left == null)
-                               return null;
+                               best_operator = po.ResolveBetterOperator (ec, left, right, best_operator);
 
-                       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))) {
+                               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 ());
 
-                               // 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;
+                                       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
+                       //
+                       // TODO: Rewrite !
+                       // Aparrently user-operators use different overloading rules especially for lifted arguments.
+                       // Some details are in 6.4.2, 7.2.7
+                       // Case 1: Arguments can be lifted for equal operators when the return type is bool and both
+                       // arguments are of same type and they are convertible.
+                       //                      
+                       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?");
+                       if (user_oper != oper) {
+                               // FIXME: This has to derive from UserOperatorCall to handle expression tree
+                               return new ConditionalLogicalOperator (oper == Operator.LogicalAnd,
+                                       left, right, left.Type, loc).Resolve (ec);
+                       }
+
+                       //
+                       // 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;
+                                       // FIXME: this breaks expression tree
+                                       if (left is NullLiteral || right is NullLiteral)
+                                               return this;
+                               } 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;
+                       // TODO: CreateExpressionTree is allocated every time
+                       return new UserOperatorCall (union, args, CreateExpressionTree, loc);
                }
 
                public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
@@ -2651,6 +2836,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 ||
@@ -2844,51 +3035,57 @@ 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;
+                       bool is_unsigned = IsUnsigned (l);
                        
                        switch (oper){
                        case Operator.Multiply:
@@ -3016,8 +3213,7 @@ namespace Mono.CSharp {
                                break;
 
                        default:
-                               throw new Exception ("This should not happen: Operator = "
-                                                    + oper.ToString ());
+                               throw new InternalErrorException (oper.ToString ());
                        }
 
                        ig.Emit (opcode);
@@ -3030,13 +3226,20 @@ namespace Mono.CSharp {
                        target.left = left.Clone (clonectx);
                        target.right = right.Clone (clonectx);
                }
-
+               
                public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       return CreateExpressionTree (ec, null);
+               }
+
+               Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)                
                {
                        string method_name;
+                       bool lift_arg = false;
+                       
                        switch (oper) {
                        case Operator.Addition:
-                               if (ec.CheckState)
+                               if (method == null && ec.CheckState)
                                        method_name = "AddChecked";
                                else
                                        method_name = "Add";
@@ -3044,9 +3247,37 @@ namespace Mono.CSharp {
                        case Operator.BitwiseAnd:
                                method_name = "And";
                                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.LessThan:
+                               method_name = "LessThan";
+                               break;
                        case Operator.LogicalAnd:
                                method_name = "AndAlso";
                                break;
+                       case Operator.Inequality:
+                               method_name = "NotEqual";
+                               lift_arg = true;
+                               break;
+                       case Operator.RightShift:
+                               method_name = "RightShift";
+                               break;
                                
                        case Operator.BitwiseOr:
                                method_name = "Or";
@@ -3062,6 +3293,13 @@ namespace Mono.CSharp {
                        ArrayList args = new ArrayList (2);
                        args.Add (new Argument (left.CreateExpressionTree (ec)));
                        args.Add (new Argument (right.CreateExpressionTree (ec)));
+                       if (method != null) {
+                               if (lift_arg)
+                                       args.Add (new Argument (new BoolConstant (false, loc)));
+                               
+                               args.Add (new Argument (method.CreateExpressionTree (ec)));
+                       }
+                       
                        return CreateExpressionFactoryCall (method_name, args);
                }
        }
@@ -3149,19 +3387,7 @@ namespace Mono.CSharp {
                                        return;
                                }
                        }
-                       
-                       //
-                       // Conversion to object
-                       //
-                       if (operand.Type != TypeManager.string_type) {
-                               Expression expr = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
-                               if (expr == null) {
-                                       Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
-                                       return;
-                               }
-                               operand = expr;
-                       }
-                       
+
                        arguments.Add (new Argument (operand));
                }
 
@@ -3227,9 +3453,13 @@ namespace Mono.CSharp {
        
        //
        // User-defined conditional logical operator
+       //
        public class ConditionalLogicalOperator : Expression {
                Expression left, right;
                bool is_and;
+               Expression op_true, op_false;
+               UserOperatorCall op;
+               LocalTemporary left_temp;
 
                public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
                {
@@ -3240,6 +3470,15 @@ namespace Mono.CSharp {
                        this.right = right;
                        this.is_and = is_and;
                }
+               
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       ArrayList args = new ArrayList (3);
+                       args.Add (new Argument (left.CreateExpressionTree (ec)));
+                       args.Add (new Argument (right.CreateExpressionTree (ec)));
+                       args.Add (new Argument (op.Method.CreateExpressionTree (ec)));
+                       return CreateExpressionFactoryCall (is_and ? "AndAlso" : "OrElse", args);
+               }               
 
                protected void Error19 ()
                {
@@ -3252,9 +3491,6 @@ namespace Mono.CSharp {
                               "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;
@@ -3283,7 +3519,7 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       op = new StaticCallExpr (method, arguments, loc);
+                       op = new UserOperatorCall (operator_group, arguments, null, loc);
 
                        op_true = GetOperatorTrue (ec, left_temp, loc);
                        op_false = GetOperatorFalse (ec, left_temp, loc);
@@ -3444,6 +3680,15 @@ namespace Mono.CSharp {
                        }
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       ArrayList args = new ArrayList (3);
+                       args.Add (new Argument (expr.CreateExpressionTree (ec)));
+                       args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
+                       args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
+                       return CreateExpressionFactoryCall ("Condition", args);
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        expr = expr.Resolve (ec);
@@ -3451,11 +3696,6 @@ namespace Mono.CSharp {
                        if (expr == null)
                                return null;
 
-#if GMCS_SOURCE
-                       if (TypeManager.IsNullableValueType (expr.Type))
-                               return new Nullable.LiftedConditional (expr, true_expr, false_expr, loc).Resolve (ec);
-#endif
-                       
                        if (expr.Type != TypeManager.bool_type){
                                expr = Expression.ResolveBoolean (
                                        ec, expr, loc);
@@ -3542,6 +3782,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);
@@ -4191,30 +4439,24 @@ namespace Mono.CSharp {
                        this.arguments_resolved = arguments_resolved;
                }
 
-               public static string FullMethodDesc (MethodBase mb)
+               public override Expression CreateExpressionTree (EmitContext ec)
                {
-                       if (mb == null)
-                               return "";
+                       ArrayList args;
 
-                       StringBuilder sb;
-                       if (mb is MethodInfo) {
-                               sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
-                               sb.Append (" ");
+                       //
+                       // Special conversion for nested expression trees
+                       //
+                       if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
+                               args = new ArrayList (1);
+                               args.Add (new Argument (this));
+                               return CreateExpressionFactoryCall ("Quote", args);
                        }
-                       else
-                               sb = new StringBuilder ();
-
-                       sb.Append (TypeManager.CSharpSignature (mb));
-                       return sb.ToString ();
-               }
 
-               public override Expression CreateExpressionTree (EmitContext ec)
-               {
-                       ArrayList args = new ArrayList (Arguments.Count + 3);
+                       args = new ArrayList (Arguments.Count + 3);
                        if (mg.IsInstance)
                                args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
                        else
-                               args.Add (new Argument (new NullConstant (loc).CreateExpressionTree (ec)));
+                               args.Add (new Argument (new NullLiteral (loc).CreateExpressionTree (ec)));
 
                        args.Add (new Argument (mg.CreateExpressionTree (ec)));
                        foreach (Argument a in Arguments) {
@@ -4244,9 +4486,21 @@ namespace Mono.CSharp {
                                        return (new DelegateInvocation (
                                                expr_resolved, Arguments, loc)).Resolve (ec);
                                }
+
+                               MemberExpr me = expr_resolved as MemberExpr;
+                               if (me == null) {
+                                       expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
+                                       return null;
+                               }
                                
-                               expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
-                               return null;
+                               mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name);
+                               if (mg == null) {
+                                       Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
+                                               expr_resolved.GetSignatureForError ());
+                                       return null;
+                               }
+
+                               ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
                        }
 
                        //
@@ -4455,25 +4709,6 @@ namespace Mono.CSharp {
 
                        Type decl_type = method.DeclaringType;
 
-                       if (!RootContext.StdLib) {
-                               // Replace any calls to the system's System.Array type with calls to
-                               // the newly created one.
-                               if (method == TypeManager.system_int_array_get_length)
-                                       method = TypeManager.int_array_get_length;
-                               else if (method == TypeManager.system_int_array_get_rank)
-                                       method = TypeManager.int_array_get_rank;
-                               else if (method == TypeManager.system_object_array_clone)
-                                       method = TypeManager.object_array_clone;
-                               else if (method == TypeManager.system_int_array_get_length_int)
-                                       method = TypeManager.int_array_get_length_int;
-                               else if (method == TypeManager.system_int_array_get_lower_bound_int)
-                                       method = TypeManager.int_array_get_lower_bound_int;
-                               else if (method == TypeManager.system_int_array_get_upper_bound_int)
-                                       method = TypeManager.int_array_get_upper_bound_int;
-                               else if (method == TypeManager.system_void_array_copyto_array_int)
-                                       method = TypeManager.void_array_copyto_array_int;
-                       }
-
                        if (!ec.IsInObsoleteScope) {
                                //
                                // This checks ObsoleteAttribute on the method and on the declaring type
@@ -4840,7 +5075,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;
                }
@@ -4936,6 +5171,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;
@@ -5347,7 +5590,7 @@ namespace Mono.CSharp {
 
                        return true;
                }
-               
+
                public override Expression CreateExpressionTree (EmitContext ec)
                {
                        if (dimensions != 1) {
@@ -5525,8 +5768,8 @@ namespace Mono.CSharp {
                        byte [] element;
                        int count = array_data.Count;
 
-                       if (array_element_type.IsEnum)
-                               array_element_type = TypeManager.EnumToUnderlying (array_element_type);
+                       if (TypeManager.IsEnumType (array_element_type))
+                               array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
                        
                        factor = GetTypeSize (array_element_type);
                        if (factor == 0)
@@ -5673,6 +5916,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
                        //
@@ -5859,8 +6111,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));
+                                       }
                        }
                }
        }
@@ -6316,6 +6576,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;
@@ -6376,31 +6647,32 @@ namespace Mono.CSharp {
                {
                        type = TypeManager.type_type;
                        typearg = TypeManager.void_type;
-                       // See description in TypeOf.
-                       eclass = ExprClass.Value;
-                       return this;
+
+                       return DoResolveBase ();
                }
        }
 
        internal class TypeOfMethod : Expression
        {
-               readonly MethodGroupExpr method;
-               static MethodInfo get_type_from_handle;
-
-               static TypeOfMethod ()
-               {
-                       get_type_from_handle = typeof (MethodBase).GetMethod ("GetMethodFromHandle",
-                               new Type [] { TypeManager.runtime_method_handle_type });
-               }
+               readonly MethodInfo method;
 
-               public TypeOfMethod (MethodGroupExpr method)
+               public TypeOfMethod (MethodInfo method, Location loc)
                {
                        this.method = method;
-                       loc = method.Location;
+                       this.loc = loc;
                }
 
                public override Expression DoResolve (EmitContext ec)
                {
+                       if (TypeManager.methodbase_get_type_from_handle == 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)
+                                       TypeManager.methodbase_get_type_from_handle = TypeManager.GetPredefinedMethod (t,
+                                               "GetMethodFromHandle", loc, handle_type);
+                       }
+
                        type = typeof (MethodBase);
                        eclass = ExprClass.Value;
                        return this;
@@ -6408,8 +6680,8 @@ namespace Mono.CSharp {
 
                public override void Emit (EmitContext ec)
                {
-                       ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo)method);
-                       ec.ig.Emit (OpCodes.Call, get_type_from_handle);
+                       ec.ig.Emit (OpCodes.Ldtoken, method);
+                       ec.ig.Emit (OpCodes.Call, TypeManager.methodbase_get_type_from_handle);
                }
        }
 
@@ -6440,8 +6712,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);
@@ -6914,6 +7186,12 @@ namespace Mono.CSharp {
                        Expr = e;
                        loc = l;
                }
+               
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
+                               return Expr.CreateExpressionTree (ec);
+               }
 
                public override Expression DoResolve (EmitContext ec)
                {
@@ -6963,6 +7241,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)
                {
@@ -7185,12 +7469,18 @@ namespace Mono.CSharp {
 #endif
 
                        Type t = ea.Expr.Type;
-                       if (t.GetArrayRank () != ea.Arguments.Count) {
+                       int rank = ea.Arguments.Count;
+                       if (t.GetArrayRank () != rank) {
                                Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
                                          ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
                                return null;
                        }
 
+                       if (rank != 1 && TypeManager.int_getlength_int == null) {
+                               TypeManager.int_getlength_int = TypeManager.GetPredefinedMethod (
+                                       TypeManager.array_type, "GetLength", loc, TypeManager.int32_type);
+                       }
+
                        type = TypeManager.GetElementType (t);
                        if (type.IsPointer && !ec.InUnsafe) {
                                UnsafeError (ea.Location);
@@ -7241,7 +7531,7 @@ namespace Mono.CSharp {
                        else if (type == TypeManager.intptr_type)
                                ig.Emit (OpCodes.Ldelem_I);
                        else if (TypeManager.IsEnumType (type)){
-                               EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type), rank);
+                               EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
                        } else if (type.IsValueType){
                                ig.Emit (OpCodes.Ldelema, type);
                                ig.Emit (OpCodes.Ldobj, type);
@@ -7270,7 +7560,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;
@@ -7751,7 +8041,7 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       type = pi.PropertyType;
+                       type = TypeManager.TypeToCoreType (pi.PropertyType);
                        if (type.IsPointer && !ec.InUnsafe)
                                UnsafeError (loc);
 
@@ -8119,14 +8409,14 @@ namespace Mono.CSharp {
        }       
 
        public class UserCast : Expression {
-               MethodBase method;
+               MethodInfo method;
                Expression source;
                
                public UserCast (MethodInfo method, Expression source, Location l)
                {
                        this.method = method;
                        this.source = source;
-                       type = method.ReturnType;
+                       type = TypeManager.TypeToCoreType (method.ReturnType);
                        eclass = ExprClass.Value;
                        loc = l;
                }
@@ -8136,6 +8426,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)
                {
@@ -8147,15 +8447,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);
                }
        }
 
@@ -8381,6 +8674,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);
@@ -8679,7 +8978,7 @@ namespace Mono.CSharp {
                                if (e == EmptyExpressionStatement.Instance)
                                        initializers.RemoveAt (i--);
                                else
-                                       initializers [i] = e;                           
+                                       initializers [i] = e;
                        }
 
                        type = typeof (CollectionOrObjectInitializers);
@@ -8764,6 +9063,9 @@ namespace Mono.CSharp {
 
                public override Expression DoResolve (EmitContext ec)
                {
+                       if (eclass != ExprClass.Invalid)
+                               return this;
+                       
                        Expression e = base.DoResolve (ec);
                        if (type == null)
                                return null;