2008-04-01 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / expression.cs
index a3dab3acec22bc50c2e86d5af60af93754557ef5..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,14 +64,11 @@ namespace Mono.CSharp {
 
                public override void Emit (EmitContext ec)
                {
-                       if (args != null) 
-                               Invocation.EmitArguments (ec, mi, args, false, null);
-
-                       ec.ig.Emit (OpCodes.Call, mi);
-                       return;
+                       mg.EmitCall (ec, arguments);
                }
-               
-               static public StaticCallExpr MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
+
+               [Obsolete ("It may not be compatible with expression trees")]
+               static public UserOperatorCall MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
                                                         Expression e, Location loc)
                {
                        ArrayList args;
@@ -66,23 +81,16 @@ namespace Mono.CSharp {
                                 return null;
 
                         args.Add (a);
-                       mg = mg.OverloadResolve (ec, args, false, loc);
+                       mg = mg.OverloadResolve (ec, ref args, false, loc);
 
                        if (mg == null)
                                return null;
 
-                       return new StaticCallExpr ((MethodInfo) mg, args, loc);
+                       return new UserOperatorCall (mg, args, null, loc);
                }
 
-               public override void EmitStatement (EmitContext ec)
-               {
-                       Emit (ec);
-                       if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
-                               ec.ig.Emit (OpCodes.Pop);
-               }
-               
-               public MethodInfo Method {
-                       get { return mi; }
+               public MethodGroupExpr Method {
+                       get { return mg; }
                }
        }
 
@@ -121,15 +129,9 @@ namespace Mono.CSharp {
                }
        }
        
-       /// <summary>
-       ///   Unary expressions.  
-       /// </summary>
-       ///
-       /// <remarks>
-       ///   Unary implements unary expressions.   It derives from
-       ///   ExpressionStatement becuase the pre/post increment/decrement
-       ///   operators can be used in a statement context.
-       /// </remarks>
+       //
+       //   Unary implements unary expressions.
+       //
        public class Unary : Expression {
                public enum Operator : byte {
                        UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
@@ -378,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){
@@ -576,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) {
@@ -612,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");
@@ -652,12 +681,12 @@ namespace Mono.CSharp {
                        }
                }
 
-               public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
+               public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
                {
                        if (Oper == Operator.LogicalNot)
-                               Expr.EmitBranchable (ec, target, !onTrue);
+                               Expr.EmitBranchable (ec, target, !on_true);
                        else
-                               base.EmitBranchable (ec, target, onTrue);
+                               base.EmitBranchable (ec, target, on_true);
                }
 
                public override string ToString ()
@@ -808,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)
                {
@@ -840,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);
@@ -864,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;
@@ -891,11 +920,7 @@ namespace Mono.CSharp {
                                if (expr == null)
                                        return null;
                        } else {
-                               if (expr.eclass == ExprClass.Value) {
-                                       Error_ValueAssignment (loc);
-                               } else {
-                                       expr.Error_UnexpectedKind (ec.DeclContainer, "variable, indexer or property access", loc);
-                               }
+                               Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
                                return null;
                        }
 
@@ -919,11 +944,6 @@ namespace Mono.CSharp {
                        return ResolveOperator (ec);
                }
 
-               static int PtrTypeSize (Type t)
-               {
-                       return GetTypeSize (TypeManager.GetElementType (t));
-               }
-
                //
                // Loads the proper "1" into the stack based on the type, then it emits the
                // opcode for the operation requested
@@ -943,10 +963,11 @@ namespace Mono.CSharp {
                        else if (t == TypeManager.float_type)
                                ig.Emit (OpCodes.Ldc_R4, 1.0F);
                        else if (t.IsPointer){
-                               int n = PtrTypeSize (t);
+                               Type et = TypeManager.GetElementType (t);
+                               int n = GetTypeSize (et);
                                
                                if (n == 0)
-                                       ig.Emit (OpCodes.Sizeof, t);
+                                       ig.Emit (OpCodes.Sizeof, et);
                                else
                                        IntConstant.EmitInt (ig, n);
                        } else 
@@ -1024,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;
                        }
@@ -1081,13 +1102,23 @@ namespace Mono.CSharp {
                        if (expr == null)
                                return null;
                        
-                       if (expr.Type.IsPointer) {
-                               Report.Error (244, loc, "\"is\" or \"as\" are not valid on pointer types");
+                       if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
+                               Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
+                                       OperatorName);
+                               return null;
+                       }
+
+                       if (expr.Type == TypeManager.anonymous_method_type) {
+                               Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
+                                       OperatorName);
                                return null;
                        }
+
                        return this;
                }
 
+               protected abstract string OperatorName { get; }
+
                protected override void CloneTo (CloneContext clonectx, Expression t)
                {
                        Probe target = (Probe) t;
@@ -1106,131 +1137,135 @@ namespace Mono.CSharp {
                        : base (expr, probe_type, l)
                {
                }
-
-               enum Action {
-                       AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
-               }
-
-               Action action;
                
                public override void Emit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
 
                        expr.Emit (ec);
-
-                       switch (action){
-                       case Action.AlwaysFalse:
-                               ig.Emit (OpCodes.Pop);
-                               IntConstant.EmitInt (ig, 0);
-                               return;
-                       case Action.AlwaysTrue:
-                               ig.Emit (OpCodes.Pop);
-                               IntConstant.EmitInt (ig, 1);
-                               return;
-                       case Action.LeaveOnStack:
-                               // the `e != null' rule.
-                               ig.Emit (OpCodes.Ldnull);
-                               ig.Emit (OpCodes.Ceq);
-                               ig.Emit (OpCodes.Ldc_I4_0);
-                               ig.Emit (OpCodes.Ceq);
-                               return;
-                       case Action.Probe:
-                               ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
-                               ig.Emit (OpCodes.Ldnull);
-                               ig.Emit (OpCodes.Cgt_Un);
-                               return;
-                       }
-                       throw new Exception ("never reached");
+                       ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
+                       ig.Emit (OpCodes.Ldnull);
+                       ig.Emit (OpCodes.Cgt_Un);
                }
 
-               public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
+               public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
                {
                        ILGenerator ig = ec.ig;
 
-                       switch (action){
-                       case Action.AlwaysFalse:
-                               if (! onTrue)
-                                       ig.Emit (OpCodes.Br, target);
-                               
-                               return;
-                       case Action.AlwaysTrue:
-                               if (onTrue)
-                                       ig.Emit (OpCodes.Br, target);
-                               
-                               return;
-                       case Action.LeaveOnStack:
-                               // the `e != null' rule.
-                               expr.Emit (ec);
-                               ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
-                               return;
-                       case Action.Probe:
-                               expr.Emit (ec);
-                               ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
-                               ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
-                               return;
-                       }
-                       throw new Exception ("never reached");
+                       expr.Emit (ec);
+                       ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
+                       ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
                }
 
-               public override Expression DoResolve (EmitContext ec)
+               Expression CreateConstantResult (bool result)
                {
-                       Expression e = base.DoResolve (ec);
+                       if (result)
+                               Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
+                                       TypeManager.CSharpName (probe_type_expr.Type));
+                       else
+                               Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
+                                       TypeManager.CSharpName (probe_type_expr.Type));
+
+                       return new BoolConstant (result, loc);
+               }
 
-                       if ((e == null) || (expr == null))
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       if (base.DoResolve (ec) == null)
                                return null;
 
-                       Type etype = expr.Type;
+                       Type d = expr.Type;
+                       bool d_is_nullable = false;
+
+                       if (expr is Constant) {
+                               //
+                               // If E is a method group or the null literal, of if the type of E is a reference
+                               // type or a nullable type and the value of E is null, the result is false
+                               //
+                               if (expr.IsNull)
+                                       return CreateConstantResult (false);
+                       } else if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
+                               d = TypeManager.GetTypeArguments (d) [0];
+                               d_is_nullable = true;
+                       }
+
                        type = TypeManager.bool_type;
                        eclass = ExprClass.Value;
+                       Type t = probe_type_expr.Type;
+                       bool t_is_nullable = false;
+                       if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
+                               t = TypeManager.GetTypeArguments (t) [0];
+                               t_is_nullable = true;
+                       }
 
-                       //
-                       // First case, if at compile time, there is an implicit conversion
-                       // then e != null (objects) or true (value types)
-                       //
-                       Type probe_type = probe_type_expr.Type;
-                       e = Convert.ImplicitConversionStandard (ec, expr, probe_type, loc);
-                       if (e != null){
-                               expr = e;
-                               if (etype.IsValueType)
-                                       action = Action.AlwaysTrue;
-                               else
-                                       action = Action.LeaveOnStack;
-
-                               Constant c = e as Constant;
-                               if (c != null && c.GetValue () == null) {
-                                       action = Action.AlwaysFalse;
-                                       Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
-                                               TypeManager.CSharpName (probe_type));
-                               } else if (etype.IsValueType) {
-                                       Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
-                                               TypeManager.CSharpName (probe_type));
+                       if (t.IsValueType) {
+                               if (d == t) {
+                                       //
+                                       // D and T are the same value types but D can be null
+                                       //
+                                       if (d_is_nullable && !t_is_nullable)
+                                               return Nullable.HasValue.Create (expr, ec);
+                                       
+                                       //
+                                       // The result is true if D and T are the same value types
+                                       //
+                                       return CreateConstantResult (true);
                                }
-                               return this;
-                       }
-                       
-                       if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){
-                               if (TypeManager.IsGenericParameter (etype))
-                                       expr = new BoxedCast (expr, etype);
+
+                               if (TypeManager.IsGenericParameter (d))
+                                       return ResolveGenericParameter (t, d);
 
                                //
-                               // Second case: explicit reference convresion
+                               // An unboxing conversion exists
                                //
-                               if (expr is NullLiteral)
-                                       action = Action.AlwaysFalse;
-                               else
-                                       action = Action.Probe;
-                       } else if (TypeManager.ContainsGenericParameters (etype) ||
-                                  TypeManager.ContainsGenericParameters (probe_type)) {
-                               expr = new BoxedCast (expr, etype);
-                               action = Action.Probe;
+                               if (Convert.ExplicitReferenceConversionExists (d, t))
+                                       return this;
                        } else {
-                               action = Action.AlwaysFalse;
-                               if (!(probe_type.IsInterface || expr.Type.IsInterface))
-                                       Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type", TypeManager.CSharpName (probe_type));
+                               if (TypeManager.IsGenericParameter (t))
+                                       return ResolveGenericParameter (d, t);
+
+                               if (d.IsValueType) {
+                                       bool temp;
+                                       if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
+                                               return CreateConstantResult (true);
+                               } else {
+                                       if (TypeManager.IsGenericParameter (d))
+                                               return ResolveGenericParameter (t, d);
+
+                                       if (TypeManager.ContainsGenericParameters (d))
+                                               return this;
+
+                                       if (Convert.ImplicitReferenceConversionExists (expr, t) ||
+                                               Convert.ExplicitReferenceConversionExists (d, t)) {
+                                               return this;
+                                       }
+                               }
                        }
 
+                       return CreateConstantResult (false);
+               }
+
+               Expression ResolveGenericParameter (Type d, Type t)
+               {
+#if GMCS_SOURCE
+                       GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
+                       if (constraints != null) {
+                               if (constraints.IsReferenceType && d.IsValueType)
+                                       return CreateConstantResult (false);
+
+                               if (constraints.IsValueType && !d.IsValueType)
+                                       return CreateConstantResult (false);
+                       }
+
+                       expr = new BoxedCast (expr, d);
                        return this;
+#else
+                       return null;
+#endif
+               }
+               
+               protected override string OperatorName {
+                       get { return "is"; }
                }
        }
 
@@ -1282,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;
                        
                        }
@@ -1313,7 +1348,11 @@ namespace Mono.CSharp {
                                }
                        }
 #endif
-
+                       if (expr.IsNull && TypeManager.IsNullableType (type)) {
+                               Report.Warning (458, 2, loc, "The result of the expression is always `null' of type `{0}'",
+                                       TypeManager.CSharpName (type));
+                       }
+                       
                        Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
                        if (e != null){
                                expr = e;
@@ -1339,10 +1378,14 @@ namespace Mono.CSharp {
                        Error_CannotConvertType (etype, type, loc);
                        return null;
                }
+
+               protected override string OperatorName {
+                       get { return "as"; }
+               }
        
-               public override bool GetAttributableValue (Type valueType, out object value)
+               public override bool GetAttributableValue (Type value_type, out object value)
                {
-                       return expr.GetAttributableValue (valueType, out value);
+                       return expr.GetAttributableValue (value_type, out value);
                }
        }
        
@@ -1426,226 +1469,445 @@ namespace Mono.CSharp {
                        target.expr = expr.Clone (clonectx);
                }
        }
+       
+       //
+       // C# 2.0 Default value expression
+       //
+       public class DefaultValueExpression : Expression
+       {
+               Expression expr;
 
-       /// <summary>
-       ///   Binary operators
-       /// </summary>
-       public class Binary : Expression {
-               public enum Operator : byte {
-                       Multiply, Division, Modulus,
-                       Addition, Subtraction,
-                       LeftShift, RightShift,
-                       LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual, 
-                       Equality, Inequality,
-                       BitwiseAnd,
-                       ExclusiveOr,
-                       BitwiseOr,
-                       LogicalAnd,
-                       LogicalOr,
-                       TOP
+               public DefaultValueExpression (Expression expr, Location loc)
+               {
+                       this.expr = expr;
+                       this.loc = loc;
                }
 
-               readonly Operator oper;
-               protected Expression left, right;
-               readonly bool is_compound;
-
-               // This must be kept in sync with Operator!!!
-               public static readonly string [] oper_names;
-               
-               static Binary ()
+               public override Expression CreateExpressionTree (EmitContext ec)
                {
-                       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";
+                       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 Binary (Operator oper, Expression left, Expression right, bool isCompound)
-                       : this (oper, left, right)
+               public override Expression DoResolve (EmitContext ec)
                {
-                       this.is_compound = isCompound;
+                       TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
+                       if (texpr == null)
+                               return null;
+
+                       type = texpr.Type;
+
+                       if (type == TypeManager.void_type) {
+                               Error_VoidInvalidInTheContext (loc);
+                               return null;
+                       }
+
+                       if (TypeManager.IsGenericParameter (type)) {
+                               GenericConstraints constraints = TypeManager.GetTypeParameterConstraints(type);
+                               if (constraints != null && constraints.IsReferenceType)
+                                       return new EmptyConstantCast (new NullLiteral (Location), type);
+                       } else {
+                               Constant c = New.Constantify (type);
+                               if (c != null)
+                                       return new EmptyConstantCast (c, type);
+
+                               if (!TypeManager.IsValueType (type))
+                                       return new EmptyConstantCast (new NullLiteral (Location), type);
+                       }
+                       eclass = ExprClass.Variable;
+                       return this;
                }
 
-               public Binary (Operator oper, Expression left, Expression right)
+               public override void Emit (EmitContext ec)
                {
-                       this.oper = oper;
-                       this.left = left;
-                       this.right = right;
-                       this.loc = left.Location;
-               }
+                       LocalTemporary temp_storage = new LocalTemporary(type);
 
-               public Operator Oper {
-                       get {
-                               return oper;
-                       }
+                       temp_storage.AddressOf(ec, AddressOp.LoadStore);
+                       ec.ig.Emit(OpCodes.Initobj, type);
+                       temp_storage.Emit(ec);
                }
                
-               /// <summary>
-               ///   Returns a stringified representation of the Operator
-               /// </summary>
-               string OperName (Operator oper)
+               protected override void CloneTo (CloneContext clonectx, Expression t)
                {
-                       string s;
-                       switch (oper){
-                       case Operator.Multiply:
-                               s = "*";
-                               break;
-                       case Operator.Division:
-                               s = "/";
-                               break;
-                       case Operator.Modulus:
-                               s = "%";
-                               break;
-                       case Operator.Addition:
-                               s = "+";
-                               break;
-                       case Operator.Subtraction:
-                               s = "-";
-                               break;
-                       case Operator.LeftShift:
-                               s = "<<";
-                               break;
-                       case Operator.RightShift:
-                               s = ">>";
-                               break;
-                       case Operator.LessThan:
-                               s = "<";
-                               break;
-                       case Operator.GreaterThan:
-                               s = ">";
-                               break;
-                       case Operator.LessThanOrEqual:
-                               s = "<=";
-                               break;
-                       case Operator.GreaterThanOrEqual:
-                               s = ">=";
-                               break;
-                       case Operator.Equality:
-                               s = "==";
-                               break;
-                       case Operator.Inequality:
-                               s = "!=";
-                               break;
-                       case Operator.BitwiseAnd:
-                               s = "&";
-                               break;
-                       case Operator.BitwiseOr:
-                               s = "|";
-                               break;
-                       case Operator.ExclusiveOr:
-                               s = "^";
-                               break;
-                       case Operator.LogicalOr:
-                               s = "||";
-                               break;
-                       case Operator.LogicalAnd:
-                               s = "&&";
-                               break;
-                       default:
-                               s = oper.ToString ();
-                               break;
+                       DefaultValueExpression target = (DefaultValueExpression) t;
+                       
+                       target.expr = expr.Clone (clonectx);
+               }
+       }
+
+       /// <summary>
+       ///   Binary operators
+       /// </summary>
+       public class Binary : Expression {
+
+               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)
+                       {
                        }
 
-                       if (is_compound)
-                               return s + "=";
+                       public PredefinedOperator (Type type, Operator op_mask, Type return_type)
+                               : this (type, type, op_mask, return_type)
+                       {
+                       }
 
-                       return s;
-               }
+                       public PredefinedOperator (Type type, Operator op_mask)
+                               : this (type, type, op_mask, type)
+                       {
+                       }
 
-               public override string ToString ()
-               {
-                       return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
-                               right.ToString () + ")";
+                       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;
+                       }
                }
-               
-               Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
-               {
-                       if (expr.Type == target_type)
-                               return expr;
 
-                       return Convert.ImplicitConversion (ec, expr, target_type, loc);
+               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);
+                       }
                }
 
-               void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
-               {
-                       Report.Error (
-                               34, loc, "Operator `" + OperName (oper) 
-                               + "' is ambiguous on operands of type `"
-                               + TypeManager.CSharpName (l) + "' "
-                               + "and `" + TypeManager.CSharpName (r)
-                               + "'");
+               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;
+                       }
                }
 
-               bool IsConvertible (EmitContext ec, Expression le, Expression re, Type t)
-               {
-                       return Convert.ImplicitConversionExists (ec, le, t) && Convert.ImplicitConversionExists (ec, re, t);
+               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);
+                       }
                }
 
-               bool VerifyApplicable_Predefined (EmitContext ec, Type t)
-               {
-                       if (!IsConvertible (ec, left, right, t))
-                               return false;
-                       left = ForceConversion (ec, left, t);
-                       right = ForceConversion (ec, right, t);
-                       type = t;
-                       return true;
+               [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
                }
 
-               bool IsApplicable_String (EmitContext ec, Expression le, Expression re, Operator oper)
-               {
-                       bool l = Convert.ImplicitConversionExists (ec, le, TypeManager.string_type);
-                       bool r = Convert.ImplicitConversionExists (ec, re, TypeManager.string_type);
+               readonly Operator oper;
+               protected Expression left, right;
+               readonly bool is_compound;
 
-                       if (oper == Operator.Equality || oper == Operator.Inequality)
-                               return l && r;
-                       if (oper == Operator.Addition)
-                               return l || r;
-                       return false;
+               // This must be kept in sync with Operator!!!
+               public static readonly string [] oper_names;
+
+               static PredefinedOperator [] standard_operators;
+               static PredefinedOperator [] pointer_operators;
+               
+               static Binary ()
+               {
+                       oper_names = new string [18];
+
+                       oper_names [(int) (Operator.Multiply & Operator.ValuesOnlyMask)] = "op_Multiply";
+                       oper_names [(int) (Operator.Division & Operator.ValuesOnlyMask)] = "op_Division";
+                       oper_names [(int) (Operator.Modulus & Operator.ValuesOnlyMask)] = "op_Modulus";
+                       oper_names [(int) (Operator.Addition & Operator.ValuesOnlyMask)] = "op_Addition";
+                       oper_names [(int) (Operator.Subtraction & Operator.ValuesOnlyMask)] = "op_Subtraction";
+                       oper_names [(int) (Operator.LeftShift & Operator.ValuesOnlyMask)] = "op_LeftShift";
+                       oper_names [(int) (Operator.RightShift & Operator.ValuesOnlyMask)] = "op_RightShift";
+                       oper_names [(int) (Operator.LessThan & Operator.ValuesOnlyMask)] = "op_LessThan";
+                       oper_names [(int) (Operator.GreaterThan & Operator.ValuesOnlyMask)] = "op_GreaterThan";
+                       oper_names [(int) (Operator.LessThanOrEqual & Operator.ValuesOnlyMask)] = "op_LessThanOrEqual";
+                       oper_names [(int) (Operator.GreaterThanOrEqual & Operator.ValuesOnlyMask)] = "op_GreaterThanOrEqual";
+                       oper_names [(int) (Operator.Equality & Operator.ValuesOnlyMask)] = "op_Equality";
+                       oper_names [(int) (Operator.Inequality & Operator.ValuesOnlyMask)] = "op_Inequality";
+                       oper_names [(int) (Operator.BitwiseAnd & Operator.ValuesOnlyMask)] = "op_BitwiseAnd";
+                       oper_names [(int) (Operator.BitwiseOr & Operator.ValuesOnlyMask)] = "op_BitwiseOr";
+                       oper_names [(int) (Operator.ExclusiveOr & Operator.ValuesOnlyMask)] = "op_ExclusiveOr";
+                       oper_names [(int) (Operator.LogicalOr & Operator.ValuesOnlyMask)] = "op_LogicalOr";
+                       oper_names [(int) (Operator.LogicalAnd & Operator.ValuesOnlyMask)] = "op_LogicalAnd";
                }
 
-               bool OverloadResolve_PredefinedString (EmitContext ec, Operator oper)
+               public Binary (Operator oper, Expression left, Expression right, bool isCompound)
+                       : this (oper, left, right)
                {
-                       if (!IsApplicable_String (ec, left, right, oper))
-                               return false;
-                       Type t = TypeManager.string_type;
-                       if (Convert.ImplicitConversionExists (ec, left, t))
-                               left = ForceConversion (ec, left, t);
-                       if (Convert.ImplicitConversionExists (ec, right, t))
-                               right = ForceConversion (ec, right, t);
-                       type = t;
-                       return true;
+                       this.is_compound = isCompound;
                }
 
-               bool OverloadResolve_PredefinedIntegral (EmitContext ec)
+               public Binary (Operator oper, Expression left, Expression right)
                {
-                       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;
+                       this.oper = oper;
+                       this.left = left;
+                       this.right = right;
+                       this.loc = left.Location;
                }
 
-               bool OverloadResolve_PredefinedFloating (EmitContext ec)
+               public Operator Oper {
+                       get {
+                               return oper;
+                       }
+               }
+               
+               /// <summary>
+               ///   Returns a stringified representation of the Operator
+               /// </summary>
+               string OperName (Operator oper)
                {
-                       return VerifyApplicable_Predefined (ec, TypeManager.float_type) ||
-                               VerifyApplicable_Predefined (ec, TypeManager.double_type) ||
-                               false;
+                       string s;
+                       switch (oper){
+                       case Operator.Multiply:
+                               s = "*";
+                               break;
+                       case Operator.Division:
+                               s = "/";
+                               break;
+                       case Operator.Modulus:
+                               s = "%";
+                               break;
+                       case Operator.Addition:
+                               s = "+";
+                               break;
+                       case Operator.Subtraction:
+                               s = "-";
+                               break;
+                       case Operator.LeftShift:
+                               s = "<<";
+                               break;
+                       case Operator.RightShift:
+                               s = ">>";
+                               break;
+                       case Operator.LessThan:
+                               s = "<";
+                               break;
+                       case Operator.GreaterThan:
+                               s = ">";
+                               break;
+                       case Operator.LessThanOrEqual:
+                               s = "<=";
+                               break;
+                       case Operator.GreaterThanOrEqual:
+                               s = ">=";
+                               break;
+                       case Operator.Equality:
+                               s = "==";
+                               break;
+                       case Operator.Inequality:
+                               s = "!=";
+                               break;
+                       case Operator.BitwiseAnd:
+                               s = "&";
+                               break;
+                       case Operator.BitwiseOr:
+                               s = "|";
+                               break;
+                       case Operator.ExclusiveOr:
+                               s = "^";
+                               break;
+                       case Operator.LogicalOr:
+                               s = "||";
+                               break;
+                       case Operator.LogicalAnd:
+                               s = "&&";
+                               break;
+                       default:
+                               s = oper.ToString ();
+                               break;
+                       }
+
+                       if (is_compound)
+                               return s + "=";
+
+                       return s;
                }
 
                static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
@@ -1659,828 +1921,849 @@ namespace Mono.CSharp {
                                name, left, right);
                }
                
-               protected void Error_OperatorCannotBeApplied ()
+               protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
                {
-                       Error_OperatorCannotBeApplied (Location, OperName (oper), TypeManager.CSharpName (left.Type),
-                               TypeManager.CSharpName(right.Type));
-               }
+                       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);
 
-               static bool is_unsigned (Type t)
-               {
-                       if (t.IsPointer)
-                               return is_unsigned (t.GetElementType ());
-                       
-                       return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
-                               t == TypeManager.short_type || t == TypeManager.byte_type);
-               }
+                       if (right.eclass == ExprClass.MethodGroup)
+                               r = left.ExprClassName;
+                       else
+                               r = TypeManager.CSharpName (right.Type);
 
-               Expression Make32or64 (EmitContext ec, Expression e)
-               {
-                       Type t= e.Type;
-                       
-                       if (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
-                           t == TypeManager.int64_type || t == TypeManager.uint64_type)
-                               return e;
-                       Expression ee = Convert.ImplicitConversion (ec, e, TypeManager.int32_type, loc);
-                       if (ee != null)
-                               return ee;
-                       ee = Convert.ImplicitConversion (ec, e, TypeManager.uint32_type, loc);
-                       if (ee != null)
-                               return ee;
-                       ee = Convert.ImplicitConversion (ec, e, TypeManager.int64_type, loc);
-                       if (ee != null)
-                               return ee;
-                       ee = Convert.ImplicitConversion (ec, e, TypeManager.uint64_type, loc);
-                       if (ee != null)
-                               return ee;
-                       return null;
-               }
-                                       
-               Expression CheckShiftArguments (EmitContext ec)
-               {
-                       Expression new_left = Make32or64 (ec, left);
-                       Expression new_right = ForceConversion (ec, right, TypeManager.int32_type);
-                       if (new_left == null || new_right == null) {
-                               Error_OperatorCannotBeApplied ();
-                               return null;
-                       }
-                       type = new_left.Type;
-                       int shiftmask = (type == TypeManager.int32_type || type == TypeManager.uint32_type) ? 31 : 63;
-                       left = new_left;
-                       right = new Binary (Binary.Operator.BitwiseAnd, new_right, new IntConstant (shiftmask, loc)).DoResolve (ec);
-                       return this;
+                       Error_OperatorCannotBeApplied (Location, OperName (oper), l, r);
                }
 
-               //
-               // 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)
+               public static string GetOperatorMetadataName (Operator op)
                {
-                       return t == TypeManager.object_type || t == TypeManager.string_type ||
-                               t == TypeManager.delegate_type || t.IsSubclassOf (TypeManager.delegate_type);
+                       return oper_names [(int)(op & Operator.ValuesOnlyMask)];
                }
 
-               static void Warning_UnintendedReferenceComparison (Location loc, string side, Type type)
+               static bool IsUnsigned (Type t)
                {
-                       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));
-               }
+                       while (t.IsPointer)
+                               t = TypeManager.GetElementType (t);
 
-               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"); 
+                       return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
+                               t == TypeManager.ushort_type || t == TypeManager.byte_type);
                }
-                       
+
                Expression ResolveOperator (EmitContext ec)
                {
                        Type l = left.Type;
                        Type r = right.Type;
+                       Expression expr;
+                       bool primitives_only = false;
 
-                       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;
-                                       } 
+                       //
+                       // 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;
 
-                                       //
-                                       // CSC 2 has this behavior, it allows structs to be compared
-                                       // with the null literal *outside* of a generics context and
-                                       // inlines that as true or false.
-                                       //
-                                       // This is, in my opinion, completely wrong.
-                                       //
-                                       if (RootContext.Version != LanguageVersion.ISO_1 && l.IsValueType){
-                                               Warning_Constant_Result (loc, oper == Operator.Inequality, l);
-                                               return new BoolLiteral (oper == Operator.Inequality, loc);
-                                       }
+                                       primitives_only = true;
                                }
+                       } else {
+                               // Pointers
+                               if (l.IsPointer || r.IsPointer)
+                                       return ResolveOperatorPointer (ec, l, r);
 
-                               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;
-                                       }
+                               // Enums
+                               bool lenum = TypeManager.IsEnumType (l);
+                               bool renum = TypeManager.IsEnumType (r);
+                               if (lenum || renum) {
+                                       expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
 
-                                       //
-                                       // CSC 2 has this behavior, it allows structs to be compared
-                                       // with the null literal *outside* of a generics context and
-                                       // inlines that as true or false.
-                                       //
-                                       // This is, in my opinion, completely wrong.
-                                       //
-                                       if (RootContext.Version != LanguageVersion.ISO_1 && r.IsValueType){
-                                               Warning_Constant_Result (loc, oper == Operator.Inequality, r);
-                                               return new BoolLiteral (oper == Operator.Inequality, loc);
-                                       }
+                                       // TODO: Can this be ambiguous
+                                       if (expr != null)
+                                               return expr;
                                }
 
-                               //
-                               // 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;
+                               // Delegates
+                               if (oper == Operator.Addition || oper == Operator.Subtraction) {
+                                       if (TypeManager.IsDelegateType (l))
+                                               return ResolveOperatorDelegateBinary (ec, l, r);
                                }
 
-                               // IntPtr equality
-                               if (l == TypeManager.intptr_type && r == TypeManager.intptr_type) {
-                                       Type = TypeManager.bool_type;
-                                       return this;
-                               }
+                               // User operators
+                               expr = ResolveUserOperator (ec, l, r);
+                               if (expr != null)
+                                       return expr;
 
-#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;
+                               // Predefined reference types equality
+                               if ((oper & Operator.EqualityMask) != 0) {
+                                       expr = ResolveOperatorEqualityRerefence (ec, l, r);
+                                       if (expr != null)
+                                               return expr;
                                }
+                       }
 
-                               if (mg != null) {
-                                       Expression e = ImplicitDelegateCreation.Create (ec, mg, delegate_type, loc);
-                                       if (e == null)
-                                               return null;
+                       if (standard_operators == null)
+                               CreateStandardOperatorsTable ();
 
-                                       // Find operator method
-                                       string op = oper_names[(int)oper];
-                                       MemberInfo[] mi = TypeManager.MemberLookup(ec.ContainerType, null,
-                                               TypeManager.delegate_type, MemberTypes.Method, AllBindingFlags, op, null);
+                       return ResolveOperatorPredefined (ec, standard_operators, primitives_only);
+               }
 
-                                       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));
+               Constant EnumLiftUp (Constant left, Constant right)
+               {
+                       switch (oper) {
+                       case Operator.BitwiseOr:
+                       case Operator.BitwiseAnd:
+                       case Operator.ExclusiveOr:
+                       case Operator.Equality:
+                       case Operator.Inequality:
+                       case Operator.LessThan:
+                       case Operator.LessThanOrEqual:
+                       case Operator.GreaterThan:
+                       case Operator.GreaterThanOrEqual:
+                               if (left is EnumConstant)
+                                       return left;
+                               
+                               if (left.IsZeroInteger)
+                                       return new EnumConstant (left, right.Type);
+                               
+                               break;
+                               
+                       case Operator.Addition:
+                       case Operator.Subtraction:
+                               return left;
+                               
+                       case Operator.Multiply:
+                       case Operator.Division:
+                       case Operator.Modulus:
+                       case Operator.LeftShift:
+                       case Operator.RightShift:
+                               if (right is EnumConstant || left is EnumConstant)
+                                       break;
+                               return left;
+                       }
+                       Error_OperatorCannotBeApplied (this.left, this.right);
+                       return null;
+               }
 
-                                       return new BinaryMethod (TypeManager.bool_type, (MethodInfo)mi [0], args);
-                               }
-#endif                         
-                               if (l == TypeManager.anonymous_method_type || r == TypeManager.anonymous_method_type) {
-                                       Error_OperatorCannotBeApplied(Location, OperName(oper),
-                                               left.ExprClassName, right.ExprClassName);
-                                       return null;
-                               }                               
+               //
+               // 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;
+                       }
+
+                       OpcodeCast rcast = right as OpcodeCast;
+                       if (rcast != null) {
+                               if (IsUnsigned (rcast.UnderlyingType))
+                                       rcast = null;
                        }
 
+                       if (lcast == null && rcast == null)
+                               return;
+
+                       // FIXME: consider constants
+
+                       Report.Warning (675, 3, loc,
+                               "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
+                               TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
+               }
+
+               static void CreatePointerOperatorsTable ()
+               {
+                       ArrayList temp = new ArrayList ();
 
                        //
-                       // Do not perform operator overload resolution when both sides are
-                       // built-in types
+                       // Pointer arithmetic:
                        //
-                       MethodGroupExpr left_operators = null, right_operators = null;
-                       if (!(TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r))) {
-                               //
-                               // Step 1: Perform Operator Overload location
-                               //
-                               string op = oper_names [(int) oper];
-
-                               MethodGroupExpr union;
-                               left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
-                               if (r != l){
-                                       right_operators = MemberLookup (
-                                               ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
-                                       union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
-                               } else
-                                       union = left_operators;
+                       // T* operator + (T* x, int y);         T* operator - (T* x, int y);
+                       // T* operator + (T* x, uint y);        T* operator - (T* x, uint y);
+                       // T* operator + (T* x, long y);        T* operator - (T* x, long y);
+                       // T* operator + (T* x, ulong y);       T* operator - (T* x, ulong y);
+                       //
+                       temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
+                       temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
+                       temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
+                       temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
+
+                       //
+                       // T* operator + (int y,   T* x);
+                       // T* operator + (uint y,  T *x);
+                       // T* operator + (long y,  T *x);
+                       // T* operator + (ulong y, T *x);
+                       //
+                       temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask));
+                       temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask));
+                       temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask));
+                       temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask));
+
+                       //
+                       // long operator - (T* x, T *y)
+                       //
+                       temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
 
-                               if (union != null) {
-                                       ArrayList args = new ArrayList (2);
-                                       args.Add (new Argument (left, Argument.AType.Expression));
-                                       args.Add (new Argument (right, Argument.AType.Expression));
+                       pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
+               }
+
+               static void CreateStandardOperatorsTable ()
+               {
+                       ArrayList temp = new ArrayList ();
+                       Type bool_type = TypeManager.bool_type;
 
-                                       union = union.OverloadResolve (ec, args, true, Location.Null);
+                       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));
 
-                                       if (union != null) {
-                                               MethodInfo mi = (MethodInfo) union;
-                                               return new BinaryMethod (mi.ReturnType, mi, args);
-                                       }
+                       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;
+
+                       Constant c = prim_expr as Constant;
+                       if (c != null) {
+                               temp = c.ConvertImplicitly (type);
+                               if (temp != null) {
+                                       prim_expr = temp;
+                                       return true;
                                }
                        }
 
-                       //
-                       // Step 0: String concatenation (because overloading will get this wrong)
-                       //
-                       if (oper == Operator.Addition){
+                       if (type == TypeManager.uint32_type) {
+                               etype = prim_expr.Type;
+                               if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
+                                       type = TypeManager.int64_type;
+
+                                       if (type != second_expr.Type) {
+                                               c = second_expr as Constant;
+                                               if (c != null)
+                                                       temp = c.ConvertImplicitly (type);
+                                               else
+                                                       temp = Convert.ImplicitNumericConversion (second_expr, type);
+                                               if (temp == null)
+                                                       return false;
+                                               second_expr = temp;
+                                       }
+                               }
+                       } else if (type == TypeManager.uint64_type) {
                                //
-                               // If any of the arguments is a string, cast to string
+                               // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
                                //
-                               
-                               // Simple constant folding
-                               if (left is StringConstant && right is StringConstant)
-                                       return new StringConstant (((StringConstant) left).Value + ((StringConstant) right).Value, left.Location);
-                               
-                               if (l == TypeManager.string_type || r == TypeManager.string_type) {
+                               if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
+                                       type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
+                                       return false;
+                       }
 
-                                       if (r == TypeManager.void_type || l == TypeManager.void_type) {
-                                               Error_OperatorCannotBeApplied ();
-                                               return null;
-                                       }
+                       temp = Convert.ImplicitNumericConversion (prim_expr, type);
+                       if (temp == null)
+                               return false;
 
-                                       // try to fold it in on the left
-                                       if (left is StringConcat) {
+                       prim_expr = temp;
+                       return true;
+               }
 
-                                               //
-                                               // We have to test here for not-null, since we can be doubly-resolved
-                                               // take care of not appending twice
-                                               //
-                                               if (type == null){
-                                                       type = TypeManager.string_type;
-                                                       ((StringConcat) left).Append (ec, right);
-                                                       return left.Resolve (ec);
-                                               } else {
-                                                       return left;
-                                               }
-                                       }
+               //
+               // 7.2.6.2 Binary numeric promotions
+               //
+               public bool DoBinaryOperatorPromotion (EmitContext ec)
+               {
+                       Type ltype = left.Type;
+                       Type rtype = right.Type;
+                       Expression temp;
 
-                                       // Otherwise, start a new concat expression
-                                       return new StringConcat (ec, loc, left, right).Resolve (ec);
-                               }
+                       foreach (Type t in ConstantFold.binary_promotions) {
+                               if (t == ltype)
+                                       return t == rtype || DoNumericPromotion (ref right, ref left, t);
 
-                               //
-                               // Transform a + ( - b) into a - b
-                               //
-                               if (right is Unary){
-                                       Unary right_unary = (Unary) right;
+                               if (t == rtype)
+                                       return t == ltype || DoNumericPromotion (ref left, ref right, t);
+                       }
 
-                                       if (right_unary.Oper == Unary.Operator.UnaryNegation){
-                                               return new Binary (Operator.Subtraction, left, right_unary.Expr).Resolve (ec);
-                                       }
-                               }
+                       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);
+
+                               if (temp == null)
+                                       return false;
+                               left = 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;
-                                       }
+                       if (rtype != int32) {
+                               Constant c = right as Constant;
+                               if (c != null)
+                                       temp = c.ImplicitConversionRequired (int32, loc);
+                               else
+                                       temp = Convert.ImplicitNumericConversion (right, int32);
 
-                                       type = TypeManager.bool_type;
-                                       return this;
-                               }
+                               if (temp == null)
+                                       return false;
+                               right = temp;
+                       }
 
-                               if (l.IsPointer || r.IsPointer) {
-                                       if (l.IsPointer && r.IsPointer) {
-                                               type = TypeManager.bool_type;
-                                               return this;
-                                       }
+                       return true;
+               }
 
-                                       if (l.IsPointer && r == TypeManager.null_type) {
-                                               right = new EmptyConstantCast (NullPointer.Null, l);
-                                               type = TypeManager.bool_type;
-                                               return this;
-                                       }
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       if (left == null)
+                               return null;
 
-                                       if (r.IsPointer && l == TypeManager.null_type) {
-                                               left = new EmptyConstantCast (NullPointer.Null, r);
-                                               type = TypeManager.bool_type;
-                                               return this;
-                                       }
+                       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 GMCS_SOURCE
-                               if (l.IsGenericParameter && r.IsGenericParameter) {
-                                       GenericConstraints l_gc, r_gc;
+                       if (left == null)
+                               return null;
 
-                                       l_gc = TypeManager.GetTypeParameterConstraints (l);
-                                       r_gc = TypeManager.GetTypeParameterConstraints (r);
+                       Constant lc = left as Constant;
 
-                                       if ((l_gc == null) || (r_gc == null) ||
-                                           !(l_gc.HasReferenceTypeConstraint || l_gc.HasClassConstraint) ||
-                                           !(r_gc.HasReferenceTypeConstraint || r_gc.HasClassConstraint)) {
-                                               Error_OperatorCannotBeApplied ();
-                                               return null;
-                                       }
+                       if (lc != null && lc.Type == TypeManager.bool_type &&
+                               ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
+                                (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
 
-                               }
-#endif
+                               // FIXME: resolve right expression as unreachable
+                               // right.Resolve (ec);
 
-                               //
-                               // 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;
+                               Report.Warning (429, 4, loc, "Unreachable expression code detected");
+                               return left;
+                       }
 
-                                       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 = right.Resolve (ec);
+                       if (right == null)
+                               return null;
 
-                                       if (!left_to_right && !right_to_left) {
-                                               Error_OperatorCannotBeApplied ();
-                                               return null;
-                                       }
+                       eclass = ExprClass.Value;
+                       Constant rc = right as Constant;
+
+                       // The conversion rules are ignored in enum context but why
+                       if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
+                               left = lc = EnumLiftUp (lc, rc);
+                               if (lc == null)
+                                       return null;
+
+                               right = rc = EnumLiftUp (rc, lc);
+                               if (rc == null)
+                                       return null;
+                       }
+
+                       if (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, 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, 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);
+               }
+
+               protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
+               {
+                       Expression expr = ResolveOperator (ec);
+                       if (expr == null)
+                               Error_OperatorCannotBeApplied (left_orig, right_orig);
+
+                       if (left == null || right == null)
+                               throw new InternalErrorException ("Invalid conversion");
+
+                       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;
+                       }
+
+                       MethodInfo method;
+                       ArrayList args = new ArrayList (2);
 
-                                               if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral)) {
-                                                       Error_OperatorCannotBeApplied ();
-                                                       return null;
-                                               }
+                       args = new ArrayList (2);
+                       args.Add (new Argument (left, Argument.AType.Expression));
+                       args.Add (new Argument (right, Argument.AType.Expression));
 
-                                               return new BinaryDelegate (l, method, args);
-                                       }
+                       if (oper == Operator.Addition) {
+                               if (TypeManager.delegate_combine_delegate_delegate == null) {
+                                       TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
+                                               TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
                                }
 
-                               //
-                               // Pointer arithmetic:
-                               //
-                               // T* operator + (T* x, int y);
-                               // T* operator + (T* x, uint y);
-                               // T* operator + (T* x, long y);
-                               // T* operator + (T* x, ulong y);
-                               //
-                               // T* operator + (int y,   T* x);
-                               // T* operator + (uint y,  T *x);
-                               // T* operator + (long y,  T *x);
-                               // T* operator + (ulong y, T *x);
-                               //
-                               // T* operator - (T* x, int y);
-                               // T* operator - (T* x, uint y);
-                               // T* operator - (T* x, long y);
-                               // T* operator - (T* x, ulong y);
-                               //
-                               // long operator - (T* x, T *y)
-                               //
-                               if (l.IsPointer){
-                                       if (r.IsPointer && oper == Operator.Subtraction){
-                                               if (r == l)
-                                                       return new PointerArithmetic (
-                                                               false, left, right, TypeManager.int64_type,
-                                                               loc).Resolve (ec);
-                                       } else {
-                                               Expression t = Make32or64 (ec, right);
-                                               if (t != null)
-                                                       return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc).Resolve (ec);
-                                       }
-                               } else if (r.IsPointer && oper == Operator.Addition){
-                                       Expression t = Make32or64 (ec, left);
-                                       if (t != null)
-                                               return new PointerArithmetic (true, right, t, r, loc).Resolve (ec);
+                               method = TypeManager.delegate_combine_delegate_delegate;
+                       } else {
+                               if (TypeManager.delegate_remove_delegate_delegate == null) {
+                                       TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
+                                               TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
                                }
+
+                               method = TypeManager.delegate_remove_delegate_delegate;
                        }
-                       
-                       //
-                       // 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;
-                                       }
-                               }
-                                       
+                       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";
 
-                       l = left.Type;
-                       r = right.Type;
+                       //
+                       // A standard implicit conversion exists from the type of either
+                       // operand to the type of the other operand
+                       //
+                       if (Convert.ImplicitReferenceConversionExists (left, r)) {
+                               if (l == TypeManager.string_type)
+                                       Report.Warning (253, 2, loc, ref_comparison, "right");
+
+                               return this;
+                       }
 
-                       if (l == TypeManager.decimal_type || l == TypeManager.string_type || r == TypeManager.string_type) {
-                               Type lookup = l;
+                       if (Convert.ImplicitReferenceConversionExists (right, l)) {
                                if (r == TypeManager.string_type)
-                                       lookup = r;
-                               MethodGroupExpr ops = (MethodGroupExpr) MemberLookup (
-                                       ec.ContainerType, lookup, oper_names [(int) oper],
-                                       MemberTypes.Method, AllBindingFlags, loc);
-                               ArrayList args = new ArrayList (2);
-                               args.Add (new Argument (left, Argument.AType.Expression));
-                               args.Add (new Argument (right, Argument.AType.Expression));
-                               ops = ops.OverloadResolve (ec, args, true, Location.Null);
-                               return new BinaryMethod (type, (MethodInfo)ops, args);
+                                       Report.Warning (252, 2, loc, ref_comparison, "left");
+
+                               return this;
                        }
 
-                       return this;
+                       return null;
                }
 
-               Constant EnumLiftUp (Constant left, Constant right)
-               {
-                       switch (oper) {
-                               case Operator.BitwiseOr:
-                               case Operator.BitwiseAnd:
-                               case Operator.ExclusiveOr:
-                               case Operator.Equality:
-                               case Operator.Inequality:
-                               case Operator.LessThan:
-                               case Operator.LessThanOrEqual:
-                               case Operator.GreaterThan:
-                               case Operator.GreaterThanOrEqual:
-                                       if (left is EnumConstant)
-                                               return left;
-
-                                       if (left.IsZeroInteger)
-                                               return new EnumConstant (left, right.Type);
 
-                                       break;
+               Expression ResolveOperatorPointer (EmitContext ec, Type l, Type r)
+               {
+                       //
+                       // bool operator == (void* x, void* y);
+                       // bool operator != (void* x, void* y);
+                       // bool operator < (void* x, void* y);
+                       // bool operator > (void* x, void* y);
+                       // bool operator <= (void* x, void* y);
+                       // bool operator >= (void* x, void* y);
+                       //
+                       if ((oper & Operator.ComparisonMask) != 0) {
+                               Expression temp;
+                               if (!l.IsPointer) {
+                                       temp = Convert.ImplicitConversion (ec, left, r, left.Location);
+                                       if (temp == null)
+                                               return null;
+                                       left = temp;
+                               }
 
-                               case Operator.Addition:
-                               case Operator.Subtraction:
-                                       return left;
+                               if (!r.IsPointer) {
+                                       temp = Convert.ImplicitConversion (ec, right, l, right.Location);
+                                       if (temp == null)
+                                               return null;
+                                       right = temp;
+                               }
 
-                               case Operator.Multiply:
-                               case Operator.Division:
-                               case Operator.Modulus:
-                               case Operator.LeftShift:
-                               case Operator.RightShift:
-                                       if (right is EnumConstant || left is EnumConstant)
-                                               break;
-                                       return left;
+                               type = TypeManager.bool_type;
+                               return this;
                        }
-                       Error_OperatorCannotBeApplied ();
-                       return null;
+
+                       if (pointer_operators == null)
+                               CreatePointerOperatorsTable ();
+
+                       return ResolveOperatorPredefined (ec, pointer_operators, false);
                }
 
-               public override Expression DoResolve (EmitContext ec)
+               //
+               // Build-in operators method overloading
+               //
+               protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only)
                {
-                       if (left == null)
-                               return null;
+                       PredefinedOperator best_operator = null;
+                       Type l = left.Type;
+                       Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
 
-                       if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
-                               left = ((ParenthesizedExpression) left).Expr;
-                               left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
-                               if (left == null)
-                                       return null;
+                       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;
 
-                               if (left.eclass == ExprClass.Type) {
-                                       Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
-                                       return null;
+                               if (primitives_only) {
+                                       if (!po.IsPrimitiveApplicable (l))
+                                               continue;
+                               } else {
+                                       if (!po.IsApplicable (ec, left, right, left_is_null, right_is_null))
+                                               continue;
                                }
-                       } else
-                               left = left.Resolve (ec);
 
-                       if (left == null)
-                               return null;
+                               if (best_operator == null) {
+                                       best_operator = po;
+                                       if (primitives_only)
+                                               break;
 
-                       Constant lc = left as Constant;
-                       if (lc != null && lc.Type == TypeManager.bool_type && 
-                               ((oper == Operator.LogicalAnd && (bool)lc.GetValue () == false) ||
-                                (oper == Operator.LogicalOr && (bool)lc.GetValue () == true))) {
+                                       continue;
+                               }
 
-                               // TODO: make a sense to resolve unreachable expression as we do for statement
-                               Report.Warning (429, 4, loc, "Unreachable expression code detected");
-                               return left;
+                               best_operator = po.ResolveBetterOperator (ec, left, right, best_operator);
+
+                               if (best_operator == null) {
+                                       Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
+                                               OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
+
+                                       best_operator = po;
+                                       break;
+                               }
                        }
 
-                       right = right.Resolve (ec);
-                       if (right == null)
+                       if (best_operator == null)
                                return null;
 
-                       eclass = ExprClass.Value;
-                       Constant rc = right as Constant;
+                       return best_operator.ConvertResult (ec, this);
+               }
 
-                       // The conversion rules are ignored in enum context but why
-                       if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
-                               left = lc = EnumLiftUp (lc, rc);
-                               if (lc == null)
-                                       return null;
+               //
+               // Performs user-operator overloading
+               //
+               protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
+               {
+                       Operator user_oper;
+                       if (oper == Operator.LogicalAnd)
+                               user_oper = Operator.BitwiseAnd;
+                       else if (oper == Operator.LogicalOr)
+                               user_oper = Operator.BitwiseOr;
+                       else
+                               user_oper = oper;
 
-                               right = rc = EnumLiftUp (rc, lc);
-                               if (rc == null)
-                                       return null;
-                       }
+                       string op = GetOperatorMetadataName (user_oper);
 
-                       if (oper == Operator.BitwiseAnd) {
-                               if (rc != null && rc.IsZeroInteger) {
-                                       return lc is EnumConstant ?
-                                               new EnumConstant (rc, lc.Type):
-                                               rc;
-                               }
+                       MethodGroupExpr union;
+                       MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
+                       if (!TypeManager.IsEqual (r, l)) {
+                               MethodGroupExpr right_operators = MemberLookup (
+                                       ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
+                               union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
+                       } else
+                               union = left_operators;
 
-                               if (lc != null && lc.IsZeroInteger) {
-                                       return rc is EnumConstant ?
-                                               new EnumConstant (lc, rc.Type):
-                                               lc;
-                               }
-                       }
-                       else if (oper == Operator.BitwiseOr) {
-                               if (lc is EnumConstant &&
-                                   rc != null && rc.IsZeroInteger)
-                                       return lc;
-                               if (rc is EnumConstant &&
-                                   lc != null && lc.IsZeroInteger)
-                                       return rc;
-                       } else if (oper == Operator.LogicalAnd) {
-                               if (rc != null && rc.IsDefaultValue && rc.Type == TypeManager.bool_type)
-                                       return rc;
-                               if (lc != null && lc.IsDefaultValue && lc.Type == TypeManager.bool_type)
-                                       return lc;
-                       }
+                       if (union == null)
+                               return null;
 
-                       if (rc != null && lc != null){
-                               int prev_e = Report.Errors;
-                               Expression e = ConstantFold.BinaryFold (
-                                       ec, oper, lc, rc, loc);
-                               if (e != null || Report.Errors != prev_e)
-                                       return e;
-                       }
+                       ArrayList args = new ArrayList (2);
+                       Argument larg = new Argument (left);
+                       args.Add (larg);
+                       Argument rarg = new Argument (right);
+                       args.Add (rarg);
 
-#if GMCS_SOURCE
-                       if ((left is NullLiteral || left.Type.IsValueType) &&
-                           (right is NullLiteral || right.Type.IsValueType) &&
-                           !(left is NullLiteral && right is NullLiteral) &&
-                           (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type)))
-                               return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
-#endif
+                       //
+                       // 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)
@@ -2553,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 ||
@@ -2589,7 +2878,7 @@ namespace Mono.CSharp {
                ///   The expression's code is generated, and we will generate a branch to `target'
                ///   if the resulting expression value is equal to isTrue
                /// </remarks>
-               public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
+               public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
                {
                        ILGenerator ig = ec.ig;
 
@@ -2600,7 +2889,7 @@ namespace Mono.CSharp {
                        // if we are comparing against null
                        //
                        if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
-                               bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
+                               bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
                                
                                //
                                // put the constant on the rhs, for simplicity
@@ -2631,7 +2920,7 @@ namespace Mono.CSharp {
 
                        } else if (oper == Operator.LogicalAnd) {
 
-                               if (onTrue) {
+                               if (on_true) {
                                        Label tests_end = ig.DefineLabel ();
                                        
                                        left.EmitBranchable (ec, tests_end, false);
@@ -2652,7 +2941,7 @@ namespace Mono.CSharp {
                                return;
                                
                        } else if (oper == Operator.LogicalOr){
-                               if (onTrue) {
+                               if (on_true) {
                                        left.EmitBranchable (ec, target, true);
                                        right.EmitBranchable (ec, target, true);
                                        
@@ -2668,7 +2957,7 @@ namespace Mono.CSharp {
                        } else if (!(oper == Operator.LessThan        || oper == Operator.GreaterThan ||
                                     oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
                                     oper == Operator.Equality        || oper == Operator.Inequality)) {
-                               base.EmitBranchable (ec, target, onTrue);
+                               base.EmitBranchable (ec, target, on_true);
                                return;
                        }
                        
@@ -2676,57 +2965,57 @@ namespace Mono.CSharp {
                        right.Emit (ec);
 
                        Type t = left.Type;
-                       bool isUnsigned = is_unsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
+                       bool is_unsigned = IsUnsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
                        
                        switch (oper){
                        case Operator.Equality:
-                               if (onTrue)
+                               if (on_true)
                                        ig.Emit (OpCodes.Beq, target);
                                else
                                        ig.Emit (OpCodes.Bne_Un, target);
                                break;
 
                        case Operator.Inequality:
-                               if (onTrue)
+                               if (on_true)
                                        ig.Emit (OpCodes.Bne_Un, target);
                                else
                                        ig.Emit (OpCodes.Beq, target);
                                break;
 
                        case Operator.LessThan:
-                               if (onTrue)
-                                       if (isUnsigned)
+                               if (on_true)
+                                       if (is_unsigned)
                                                ig.Emit (OpCodes.Blt_Un, target);
                                        else
                                                ig.Emit (OpCodes.Blt, target);
                                else
-                                       if (isUnsigned)
+                                       if (is_unsigned)
                                                ig.Emit (OpCodes.Bge_Un, target);
                                        else
                                                ig.Emit (OpCodes.Bge, target);
                                break;
 
                        case Operator.GreaterThan:
-                               if (onTrue)
-                                       if (isUnsigned)
+                               if (on_true)
+                                       if (is_unsigned)
                                                ig.Emit (OpCodes.Bgt_Un, target);
                                        else
                                                ig.Emit (OpCodes.Bgt, target);
                                else
-                                       if (isUnsigned)
+                                       if (is_unsigned)
                                                ig.Emit (OpCodes.Ble_Un, target);
                                        else
                                                ig.Emit (OpCodes.Ble, target);
                                break;
 
                        case Operator.LessThanOrEqual:
-                               if (onTrue)
-                                       if (isUnsigned)
+                               if (on_true)
+                                       if (is_unsigned)
                                                ig.Emit (OpCodes.Ble_Un, target);
                                        else
                                                ig.Emit (OpCodes.Ble, target);
                                else
-                                       if (isUnsigned)
+                                       if (is_unsigned)
                                                ig.Emit (OpCodes.Bgt_Un, target);
                                        else
                                                ig.Emit (OpCodes.Bgt, target);
@@ -2734,87 +3023,93 @@ namespace Mono.CSharp {
 
 
                        case Operator.GreaterThanOrEqual:
-                               if (onTrue)
-                                       if (isUnsigned)
+                               if (on_true)
+                                       if (is_unsigned)
                                                ig.Emit (OpCodes.Bge_Un, target);
                                        else
                                                ig.Emit (OpCodes.Bge, target);
                                else
-                                       if (isUnsigned)
+                                       if (is_unsigned)
                                                ig.Emit (OpCodes.Blt_Un, target);
                                        else
                                                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 isUnsigned = is_unsigned (left.Type);
+                       Type l = left.Type;
+                       OpCode opcode;
+                       bool is_unsigned = IsUnsigned (l);
                        
                        switch (oper){
                        case Operator.Multiply:
                                if (ec.CheckState){
                                        if (l == TypeManager.int32_type || l == TypeManager.int64_type)
                                                opcode = OpCodes.Mul_Ovf;
-                                       else if (isUnsigned)
+                                       else if (is_unsigned)
                                                opcode = OpCodes.Mul_Ovf_Un;
                                        else
                                                opcode = OpCodes.Mul;
                                } else
                                        opcode = OpCodes.Mul;
-
+                               
                                break;
-
+                               
                        case Operator.Division:
-                               if (isUnsigned)
+                               if (is_unsigned)
                                        opcode = OpCodes.Div_Un;
                                else
                                        opcode = OpCodes.Div;
                                break;
-
+                               
                        case Operator.Modulus:
-                               if (isUnsigned)
+                               if (is_unsigned)
                                        opcode = OpCodes.Rem_Un;
                                else
                                        opcode = OpCodes.Rem;
@@ -2824,7 +3119,7 @@ namespace Mono.CSharp {
                                if (ec.CheckState){
                                        if (l == TypeManager.int32_type || l == TypeManager.int64_type)
                                                opcode = OpCodes.Add_Ovf;
-                                       else if (isUnsigned)
+                                       else if (is_unsigned)
                                                opcode = OpCodes.Add_Ovf_Un;
                                        else
                                                opcode = OpCodes.Add;
@@ -2836,7 +3131,7 @@ namespace Mono.CSharp {
                                if (ec.CheckState){
                                        if (l == TypeManager.int32_type || l == TypeManager.int64_type)
                                                opcode = OpCodes.Sub_Ovf;
-                                       else if (isUnsigned)
+                                       else if (is_unsigned)
                                                opcode = OpCodes.Sub_Ovf_Un;
                                        else
                                                opcode = OpCodes.Sub;
@@ -2845,7 +3140,7 @@ namespace Mono.CSharp {
                                break;
 
                        case Operator.RightShift:
-                               if (isUnsigned)
+                               if (is_unsigned)
                                        opcode = OpCodes.Shr_Un;
                                else
                                        opcode = OpCodes.Shr;
@@ -2867,14 +3162,14 @@ namespace Mono.CSharp {
                                break;
 
                        case Operator.LessThan:
-                               if (isUnsigned)
+                               if (is_unsigned)
                                        opcode = OpCodes.Clt_Un;
                                else
                                        opcode = OpCodes.Clt;
                                break;
 
                        case Operator.GreaterThan:
-                               if (isUnsigned)
+                               if (is_unsigned)
                                        opcode = OpCodes.Cgt_Un;
                                else
                                        opcode = OpCodes.Cgt;
@@ -2883,7 +3178,7 @@ namespace Mono.CSharp {
                        case Operator.LessThanOrEqual:
                                Type lt = left.Type;
                                
-                               if (isUnsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
+                               if (is_unsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
                                        ig.Emit (OpCodes.Cgt_Un);
                                else
                                        ig.Emit (OpCodes.Cgt);
@@ -2895,7 +3190,7 @@ namespace Mono.CSharp {
                        case Operator.GreaterThanOrEqual:
                                Type le = left.Type;
                                
-                               if (isUnsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
+                               if (is_unsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
                                        ig.Emit (OpCodes.Clt_Un);
                                else
                                        ig.Emit (OpCodes.Clt);
@@ -2918,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);
@@ -2932,6 +3226,82 @@ 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 (method == null && ec.CheckState)
+                                       method_name = "AddChecked";
+                               else
+                                       method_name = "Add";
+                               break;
+                       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";
+                               break;
+
+                       case Operator.LogicalOr:
+                               method_name = "OrElse";
+                               break;
+                       default:
+                               throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
+                       }
+
+                       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);
+               }
        }
 
        //
@@ -2959,8 +3329,7 @@ namespace Mono.CSharp {
                {
                        ILGenerator ig = ec.ig;
                        
-                       if (Arguments != null) 
-                               Invocation.EmitArguments (ec, method, Arguments, false, null);
+                       Invocation.EmitArguments (ec, Arguments, false, null);
                        
                        if (method is MethodInfo)
                                ig.Emit (OpCodes.Call, (MethodInfo) method);
@@ -2974,30 +3343,21 @@ namespace Mono.CSharp {
        // b, c, d... may be strings or objects.
        //
        public class StringConcat : Expression {
-               ArrayList operands;
-               bool invalid = false;
-               bool emit_conv_done = false;
-               //
-               // Are we also concating objects?
-               //
-               bool is_strings_only = true;
+               ArrayList arguments;
                
                public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
                {
                        this.loc = loc;
                        type = TypeManager.string_type;
                        eclass = ExprClass.Value;
-               
-                       operands = new ArrayList (2);
+
+                       arguments = new ArrayList (2);
                        Append (ec, left);
                        Append (ec, right);
                }
                
                public override Expression DoResolve (EmitContext ec)
                {
-                       if (invalid)
-                               return null;
-                       
                        return this;
                }
                
@@ -3008,119 +3368,42 @@ namespace Mono.CSharp {
                        //
                        StringConstant sc = operand as StringConstant;
                        if (sc != null) {
-// TODO: it will be better to do this silently as an optimalization
-// int i = 0;
-// string s = "" + i;
-// because this code has poor performace
-//                             if (sc.Value.Length == 0)
-//                                     Report.Warning (-300, 3, Location, "Appending an empty string has no effect. Did you intend to append a space string?");
-
-                               if (operands.Count != 0) {
-                                       StringConstant last_operand = operands [operands.Count - 1] as StringConstant;
-                                       if (last_operand != null) {
-                                               operands [operands.Count - 1] = new StringConstant (last_operand.Value + ((StringConstant) operand).Value, last_operand.Location);
+                               if (arguments.Count != 0) {
+                                       Argument last_argument = (Argument) arguments [arguments.Count - 1];
+                                       StringConstant last_expr_constant = last_argument.Expr as StringConstant;
+                                       if (last_expr_constant != null) {
+                                               last_argument.Expr = new StringConstant (
+                                                       last_expr_constant.Value + sc.Value, sc.Location);
                                                return;
                                        }
                                }
-                       }
-                       
-
-                       //
-                       // Multiple (3+) concatenation are resolved as multiple StringConcat instances
-                       //
-                       StringConcat concat_oper = operand as StringConcat;
-                       if (concat_oper != null) {
-                               operands.AddRange (concat_oper.operands);
-                               return;
-                       }                       
-                       
-                       //
-                       // Conversion to object
-                       //
-                       if (operand.Type != TypeManager.string_type) {
-                               Expression no = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
-                               
-                               if (no == null) {
-                                       Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
-                                       invalid = true;
+                       } else {
+                               //
+                               // Multiple (3+) concatenation are resolved as multiple StringConcat instances
+                               //
+                               StringConcat concat_oper = operand as StringConcat;
+                               if (concat_oper != null) {
+                                       arguments.AddRange (concat_oper.arguments);
+                                       return;
                                }
-                               operand = no;
                        }
-                       
-                       operands.Add (operand);
+
+                       arguments.Add (new Argument (operand));
+               }
+
+               Expression CreateConcatInvocation ()
+               {
+                       return new Invocation (
+                               new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc),
+                               arguments, true);
                }
 
                public override void Emit (EmitContext ec)
                {
-                       MethodInfo concat_method = null;
-                       
-                       //
-                       // Do conversion to arguments; check for strings only
-                       //
-                       
-                       // This can get called multiple times, so we have to deal with that.
-                       if (!emit_conv_done) {
-                               emit_conv_done = true;
-                               for (int i = 0; i < operands.Count; i ++) {
-                                       Expression e = (Expression) operands [i];
-                                       is_strings_only &= e.Type == TypeManager.string_type;
-                               }
-                               
-                               for (int i = 0; i < operands.Count; i ++) {
-                                       Expression e = (Expression) operands [i];
-                                       
-                                       if (! is_strings_only && e.Type == TypeManager.string_type) {
-                                               // need to make sure this is an object, because the EmitParams
-                                               // method might look at the type of this expression, see it is a
-                                               // string and emit a string [] when we want an object [];
-                                               
-                                               e = EmptyCast.Create (e, TypeManager.object_type);
-                                       }
-                                       operands [i] = new Argument (e, Argument.AType.Expression);
-                               }
-                       }
-                       
-                       //
-                       // Find the right method
-                       //
-                       switch (operands.Count) {
-                       case 1:
-                               //
-                               // This should not be possible, because simple constant folding
-                               // is taken care of in the Binary code.
-                               //
-                               throw new Exception ("how did you get here?");
-                       
-                       case 2:
-                               concat_method = is_strings_only ? 
-                                       TypeManager.string_concat_string_string :
-                                       TypeManager.string_concat_object_object ;
-                               break;
-                       case 3:
-                               concat_method = is_strings_only ? 
-                                       TypeManager.string_concat_string_string_string :
-                                       TypeManager.string_concat_object_object_object ;
-                               break;
-                       case 4:
-                               //
-                               // There is not a 4 param overlaod for object (the one that there is
-                               // is actually a varargs methods, and is only in corlib because it was
-                               // introduced there before.).
-                               //
-                               if (!is_strings_only)
-                                       goto default;
-                               
-                               concat_method = TypeManager.string_concat_string_string_string_string;
-                               break;
-                       default:
-                               concat_method = is_strings_only ? 
-                                       TypeManager.string_concat_string_dot_dot_dot :
-                                       TypeManager.string_concat_object_dot_dot_dot ;
-                               break;
-                       }
-                       
-                       Invocation.EmitArguments (ec, concat_method, operands, false, null);
-                       ec.ig.Emit (OpCodes.Call, concat_method);
+                       Expression concat = CreateConcatInvocation ();
+                       concat = concat.Resolve (ec);
+                       if (concat != null)
+                               concat.Emit (ec);
                }
        }
 
@@ -3148,7 +3431,7 @@ namespace Mono.CSharp {
                {
                        ILGenerator ig = ec.ig;
                        
-                       Invocation.EmitArguments (ec, method, args, false, null);
+                       Invocation.EmitArguments (ec, args, false, null);
                        
                        ig.Emit (OpCodes.Call, (MethodInfo) method);
                        ig.Emit (OpCodes.Castclass, type);
@@ -3170,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)
                {
@@ -3183,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 ()
                {
@@ -3195,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;
@@ -3213,7 +3506,7 @@ namespace Mono.CSharp {
                        ArrayList arguments = new ArrayList (2);
                        arguments.Add (new Argument (left_temp, Argument.AType.Expression));
                        arguments.Add (new Argument (right, Argument.AType.Expression));
-                       operator_group = operator_group.OverloadResolve (ec, arguments, false, loc);
+                       operator_group = operator_group.OverloadResolve (ec, ref arguments, false, loc);
                        if (operator_group == null) {
                                Error19 ();
                                return null;
@@ -3226,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);
@@ -3359,13 +3652,13 @@ namespace Mono.CSharp {
        ///   Implements the ternary conditional operator (?:)
        /// </summary>
        public class Conditional : Expression {
-               Expression expr, trueExpr, falseExpr;
+               Expression expr, true_expr, false_expr;
                
-               public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
+               public Conditional (Expression expr, Expression true_expr, Expression false_expr)
                {
                        this.expr = expr;
-                       this.trueExpr = trueExpr;
-                       this.falseExpr = falseExpr;
+                       this.true_expr = true_expr;
+                       this.false_expr = false_expr;
                        this.loc = expr.Location;
                }
 
@@ -3377,16 +3670,25 @@ namespace Mono.CSharp {
 
                public Expression TrueExpr {
                        get {
-                               return trueExpr;
+                               return true_expr;
                        }
                }
 
                public Expression FalseExpr {
                        get {
-                               return falseExpr;
+                               return false_expr;
                        }
                }
 
+               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);
@@ -3394,11 +3696,6 @@ namespace Mono.CSharp {
                        if (expr == null)
                                return null;
 
-#if GMCS_SOURCE
-                       if (TypeManager.IsNullableValueType (expr.Type))
-                               return new Nullable.LiftedConditional (expr, trueExpr, falseExpr, loc).Resolve (ec);
-#endif
-                       
                        if (expr.Type != TypeManager.bool_type){
                                expr = Expression.ResolveBoolean (
                                        ec, expr, loc);
@@ -3412,51 +3709,51 @@ namespace Mono.CSharp {
                                Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
                        }
 
-                       trueExpr = trueExpr.Resolve (ec);
-                       falseExpr = falseExpr.Resolve (ec);
+                       true_expr = true_expr.Resolve (ec);
+                       false_expr = false_expr.Resolve (ec);
 
-                       if (trueExpr == null || falseExpr == null)
+                       if (true_expr == null || false_expr == null)
                                return null;
 
                        eclass = ExprClass.Value;
-                       if (trueExpr.Type == falseExpr.Type) {
-                               type = trueExpr.Type;
+                       if (true_expr.Type == false_expr.Type) {
+                               type = true_expr.Type;
                                if (type == TypeManager.null_type) {
                                        // TODO: probably will have to implement ConditionalConstant
                                        // to call method without return constant as well
                                        Report.Warning (-101, 1, loc, "Conditional expression will always return same value");
-                                       return trueExpr;
+                                       return true_expr;
                                }
                        } else {
                                Expression conv;
-                               Type true_type = trueExpr.Type;
-                               Type false_type = falseExpr.Type;
+                               Type true_type = true_expr.Type;
+                               Type false_type = false_expr.Type;
 
                                //
-                               // First, if an implicit conversion exists from trueExpr
-                               // to falseExpr, then the result type is of type falseExpr.Type
+                               // First, if an implicit conversion exists from true_expr
+                               // to false_expr, then the result type is of type false_expr.Type
                                //
-                               conv = Convert.ImplicitConversion (ec, trueExpr, false_type, loc);
+                               conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
                                if (conv != null){
                                        //
                                        // Check if both can convert implicitl to each other's type
                                        //
-                                       if (Convert.ImplicitConversion (ec, falseExpr, true_type, loc) != null){
+                                       if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null){
                                                Error (172,
                                                       "Can not compute type of conditional expression " +
-                                                      "as `" + TypeManager.CSharpName (trueExpr.Type) +
-                                                      "' and `" + TypeManager.CSharpName (falseExpr.Type) +
+                                                      "as `" + TypeManager.CSharpName (true_expr.Type) +
+                                                      "' and `" + TypeManager.CSharpName (false_expr.Type) +
                                                       "' convert implicitly to each other");
                                                return null;
                                        }
                                        type = false_type;
-                                       trueExpr = conv;
-                               } else if ((conv = Convert.ImplicitConversion(ec, falseExpr, true_type,loc))!= null){
+                                       true_expr = conv;
+                               } else if ((conv = Convert.ImplicitConversion(ec, false_expr, true_type,loc))!= null){
                                        type = true_type;
-                                       falseExpr = conv;
+                                       false_expr = conv;
                                } else {
                                        Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
-                                               trueExpr.GetSignatureForError (), falseExpr.GetSignatureForError ());
+                                               true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
                                        return null;
                                }
                        }
@@ -3465,8 +3762,8 @@ namespace Mono.CSharp {
                        if (expr is BoolConstant){
                                BoolConstant bc = (BoolConstant) expr;
 
-                               Report.Warning (429, 4, bc.Value ? falseExpr.Location : trueExpr.Location, "Unreachable expression code detected");
-                               return bc.Value ? trueExpr : falseExpr;
+                               Report.Warning (429, 4, bc.Value ? false_expr.Location : true_expr.Location, "Unreachable expression code detected");
+                               return bc.Value ? true_expr : false_expr;
                        }
 
                        return this;
@@ -3484,10 +3781,18 @@ namespace Mono.CSharp {
                        Label end_target = ig.DefineLabel ();
 
                        expr.EmitBranchable (ec, false_target, false);
-                       trueExpr.Emit (ec);
+                       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);
-                       falseExpr.Emit (ec);
+                       false_expr.Emit (ec);
                        ig.MarkLabel (end_target);
                }
 
@@ -3496,8 +3801,8 @@ namespace Mono.CSharp {
                        Conditional target = (Conditional) t;
 
                        target.expr = expr.Clone (clonectx);
-                       target.trueExpr = trueExpr.Clone (clonectx);
-                       target.falseExpr = falseExpr.Clone (clonectx);
+                       target.true_expr = true_expr.Clone (clonectx);
+                       target.false_expr = false_expr.Clone (clonectx);
                }
        }
 
@@ -3576,6 +3881,10 @@ namespace Mono.CSharp {
 
                        source.Emit (ec);
 
+                       // HACK: variable is already emitted when source is an initializer 
+                       if (source is NewInitialize)
+                               return;
+
                        if (leave_copy) {
                                ig.Emit (OpCodes.Dup);
                                if (IsRef || Variable.NeedsTemporary) {
@@ -3834,6 +4143,10 @@ namespace Mono.CSharp {
 
                public bool IsAssigned (EmitContext ec, Location loc)
                {
+                       // HACK: Variables are not captured in probing mode
+                       if (ec.IsInProbingMode)
+                               return true;
+                       
                        if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (VariableInfo))
                                return true;
 
@@ -3913,6 +4226,11 @@ namespace Mono.CSharp {
                        return Name == pr.Name && referenced == pr.referenced;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       return Parameter.ExpressionTreeVariableReference ();
+               }
+
                //
                // Notice that for ref/out parameters, the type exposed is not the
                // same type exposed externally.
@@ -4022,15 +4340,13 @@ namespace Mono.CSharp {
                        }
                }
 
-               public static string FullDesc (Argument a)
+               public string GetSignatureForError ()
                {
-                       if (a.ArgType == AType.ArgList)
-                               return "__arglist";
+                       if (Expr.eclass == ExprClass.MethodGroup)
+                               return Expr.ExprClassName;
 
-                       return (a.ArgType == AType.Ref ? "ref " :
-                               (a.ArgType == AType.Out ? "out " : "")) +
-                               TypeManager.CSharpName (a.Expr.Type);
-               }
+                       return Expr.GetSignatureForError ();
+               }               
 
                public bool ResolveMethodGroup (EmitContext ec)
                {
@@ -4086,19 +4402,6 @@ namespace Mono.CSharp {
                                ml.AddressOf (ec, mode);
                }
 
-               public void EmitArrayArgument (EmitContext ec)
-               {
-                       Type argtype = Expr.Type;
-                       Expr.Emit (ec);
-                               
-                       if (argtype == TypeManager.uint32_type)
-                               ec.ig.Emit (OpCodes.Conv_U);
-                       else if (argtype == TypeManager.int64_type)
-                               ec.ig.Emit (OpCodes.Conv_Ovf_I);
-                       else if (argtype == TypeManager.uint64_type)
-                               ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
-               }
-
                public Argument Clone (CloneContext clonectx)
                {
                        return new Argument (Expr.Clone (clonectx), ArgType);
@@ -4110,353 +4413,67 @@ namespace Mono.CSharp {
        /// </summary>
        public class Invocation : ExpressionStatement {
                protected ArrayList Arguments;
-               Expression expr;
-               protected MethodGroupExpr mg;
-               
-               //
-               // arguments is an ArrayList, but we do not want to typecast,
-               // as it might be null.
-               //
-               public Invocation (Expression expr, ArrayList arguments)
-               {
-                       SimpleName sn = expr as SimpleName;
-                       if (sn != null)
-                               this.expr = sn.GetMethodGroup ();
-                       else
-                               this.expr = expr;
-                       
-                       Arguments = arguments;
-                       loc = expr.Location;
-               }
-
-               public static string FullMethodDesc (MethodBase mb)
-               {
-                       if (mb == null)
-                               return "";
-
-                       StringBuilder sb;
-                       if (mb is MethodInfo) {
-                               sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
-                               sb.Append (" ");
-                       }
-                       else
-                               sb = new StringBuilder ();
-
-                       sb.Append (TypeManager.CSharpSignature (mb));
-                       return sb.ToString ();
-               }
-
-               public static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
-                                                            ArrayList arguments, int arg_count,
-                                                            ref MethodBase candidate)
-               {
-                       return IsParamsMethodApplicable (
-                               ec, me, arguments, arg_count, false, ref candidate) ||
-                               IsParamsMethodApplicable (
-                                       ec, me, arguments, arg_count, true, ref candidate);
-
-
-               }
-
-               static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
-                                                     ArrayList arguments, int arg_count,
-                                                     bool do_varargs, ref MethodBase candidate)
-               {
-#if GMCS_SOURCE
-                       if (!me.HasTypeArguments &&
-                           !TypeManager.InferParamsTypeArguments (ec, arguments, ref candidate))
-                               return false;
-
-                       if (TypeManager.IsGenericMethodDefinition (candidate))
-                               throw new InternalErrorException ("a generic method definition took part in overload resolution");
-#endif
-
-                       return IsParamsMethodApplicable (
-                               ec, arguments, arg_count, candidate, do_varargs);
-               }
-
-               /// <summary>
-               ///   Determines if the candidate method, if a params method, is applicable
-               ///   in its expanded form to the given set of arguments
-               /// </summary>
-               static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
-                                                     int arg_count, MethodBase candidate,
-                                                     bool do_varargs)
-               {
-                       ParameterData pd = TypeManager.GetParameterData (candidate);
-
-                       int pd_count = pd.Count;
-                       if (pd_count == 0)
-                               return false;
-
-                       int count = pd_count - 1;
-                       if (do_varargs) {
-                               if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
-                                       return false;
-                               if (pd_count != arg_count)
-                                       return false;
-
-                               if (!(((Argument) arguments [count]).Expr is Arglist))
-                                       return false;
-                               --pd_count;
-                       } else {
-                               if (!pd.HasParams)
-                                       return false;
-                       }
-                       
-                       if (count > arg_count)
-                               return false;
-                       
-                       if (pd_count == 1 && arg_count == 0)
-                               return true;
-
-                       //
-                       // If we have come this far, the case which
-                       // remains is when the number of parameters is
-                       // less than or equal to the argument count.
-                       //
-                       int argument_index = 0;
-                       Argument a;
-                       for (int i = 0; i < pd_count; ++i) {
-
-                               if ((pd.ParameterModifier (i) & Parameter.Modifier.PARAMS) != 0) {
-                                       Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
-                                       int params_args_count = arg_count - pd_count;
-                                       if (params_args_count < 0)
-                                               continue;
-
-                                       do {
-                                               a = (Argument) arguments [argument_index++];
-
-                                               if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
-                                                       return false;
-                                       } while (params_args_count-- > 0);
-                                       continue;
-                               }
-
-                               a = (Argument) arguments [argument_index++];
-
-                               Parameter.Modifier a_mod = a.Modifier & 
-                                       (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
-                               Parameter.Modifier p_mod = pd.ParameterModifier (i) &
-                                       (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
-
-                               if (a_mod == p_mod) {
-
-                                       if (a_mod == Parameter.Modifier.NONE)
-                                               if (!Convert.ImplicitConversionExists (ec,
-                                                       a.Expr,
-                                                       pd.ParameterType (i)))
-                                                       return false;
-
-                                       if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
-                                               Type pt = pd.ParameterType (i);
-
-                                               if (!pt.IsByRef)
-                                                       pt = TypeManager.GetReferenceType (pt);
-                                               
-                                               if (pt != a.Type)
-                                                       return false;
-                                       }
-                               } else
-                                       return false;
-                               
-                       }
-
-                       return true;
-               }
-
-               public static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
-                                                ArrayList arguments, int arg_count,
-                                                ref MethodBase method)
-               {
-                       MethodBase candidate = method;
-
-#if GMCS_SOURCE
-                       if (!me.HasTypeArguments &&
-                           !TypeManager.InferTypeArguments (ec, arguments, ref candidate))
-                               return false;
-
-                       if (TypeManager.IsGenericMethodDefinition (candidate))
-                               throw new InternalErrorException ("a generic method definition took part in overload resolution");
-#endif
-
-                       if (IsApplicable (ec, arguments, arg_count, candidate)) {
-                               method = candidate;
-                               return true;
-                       }
-
-                       return false;
-               }
-
-               /// <summary>
-               ///   Determines if the candidate method is applicable (section 14.4.2.1)
-               ///   to the given set of arguments
-               /// </summary>
-               public static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count,
-                                                MethodBase candidate)
-               {
-                       ParameterData pd = TypeManager.GetParameterData (candidate);
-
-                       if (arg_count != pd.Count)
-                               return false;
-
-                       for (int i = arg_count; i > 0; ) {
-                               i--;
-
-                               Argument a = (Argument) arguments [i];
-                               
-                               Parameter.Modifier a_mod = a.Modifier &
-                                       ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
-
-                               Parameter.Modifier p_mod = pd.ParameterModifier (i) &
-                                       ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK | Parameter.Modifier.PARAMS);
-
-                               if (a_mod != p_mod)
-                                       return false;
-
-                               Type pt = pd.ParameterType (i);
-
-                               if (TypeManager.IsEqual (pt, a.Type))
-                                       continue;
-
-                               if (a_mod != Parameter.Modifier.NONE)
-                                       return false;
-
-                               // FIXME: Kill this abomination (EmitContext.TempEc)
-                               EmitContext prevec = EmitContext.TempEc;
-                               EmitContext.TempEc = ec;
-                               try {
-                                       if (!Convert.ImplicitConversionExists (ec, a.Expr, pt))
-                                               return false;
-                               } finally {
-                                       EmitContext.TempEc = prevec;
-                               }
-                       }
-
-                       return true;
+               Expression expr;
+               protected MethodGroupExpr mg;
+               bool arguments_resolved;
+               
+               //
+               // arguments is an ArrayList, but we do not want to typecast,
+               // as it might be null.
+               //
+               public Invocation (Expression expr, ArrayList arguments)
+               {
+                       SimpleName sn = expr as SimpleName;
+                       if (sn != null)
+                               this.expr = sn.GetMethodGroup ();
+                       else
+                               this.expr = expr;
+                       
+                       Arguments = arguments;
+                       loc = expr.Location;
                }
 
-               public static void Error_WrongNumArguments (Location loc, String name, int arg_count)
+               public Invocation (Expression expr, ArrayList arguments, bool arguments_resolved)
+                       : this (expr, arguments)
                {
-                       Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
-                               name, arg_count.ToString ());
+                       this.arguments_resolved = arguments_resolved;
                }
-                        
-               static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
-                                                    Type delegate_type, Argument a, ParameterData expected_par)
-               {
-                       if (a is CollectionElementInitializer.ElementInitializerArgument) {
-                               Report.SymbolRelatedToPreviousError (method);
-                               if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
-                                       Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
-                                               TypeManager.CSharpSignature (method));
-                                       return;
-                               }
-                               Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
-                                         TypeManager.CSharpSignature (method));
-                       } else if (delegate_type == null) {
-                               Report.SymbolRelatedToPreviousError (method);
-                               Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
-                                                 TypeManager.CSharpSignature (method));
-                       } else
-                               Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
-                                       TypeManager.CSharpName (delegate_type));
-
-                       Parameter.Modifier mod = expected_par.ParameterModifier (idx);
 
-                       string index = (idx + 1).ToString ();
-                       if ((a.Modifier & Parameter.Modifier.ISBYREF) != 0 && mod != a.Modifier) {
-                               if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
-                                       Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
-                                               index, Parameter.GetModifierSignature (a.Modifier));
-                               else
-                                       Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
-                                               index, Parameter.GetModifierSignature (mod));
-                       } else {
-                               string p1 = Argument.FullDesc (a);
-                               string p2 = TypeManager.CSharpName (expected_par.ParameterType (idx));
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       ArrayList args;
 
-                               if (p1 == p2) {
-                                       Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
-                                       Report.SymbolRelatedToPreviousError (a.Expr.Type);
-                                       Report.SymbolRelatedToPreviousError (expected_par.ParameterType (idx));
-                               }
-                               Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
+                       //
+                       // 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);
                        }
-               }
-               
-               public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
-                                                         int arg_count, MethodBase method, 
-                                                         bool chose_params_expanded,
-                                                         Type delegate_type, bool may_fail,
-                                                         Location loc)
-               {
-                       ParameterData pd = TypeManager.GetParameterData (method);
-                       int j;
-                       int a_idx = 0;
-                       Argument a = null;
-                       for (j = 0; j < pd.Count; j++) {
-                               Type parameter_type = pd.ParameterType (j);
-                               Parameter.Modifier pm = pd.ParameterModifier (j);
-
-                               if (pm == Parameter.Modifier.ARGLIST) {
-                                       a = (Argument) Arguments [a_idx];
-                                       if (!(a.Expr is Arglist))
-                                               break;
-                                       ++a_idx;
-                                       continue;
-                               }
-
-                               int params_arg_count = 1;
-                               if (pm == Parameter.Modifier.PARAMS) {
-                                       pm = Parameter.Modifier.NONE;
-                                       params_arg_count = arg_count - pd.Count + 1;
-                                       if (chose_params_expanded)
-                                               parameter_type = TypeManager.GetElementType (parameter_type);
-                               }
-
-                               while (params_arg_count > 0) {
-                                       a = (Argument) Arguments [a_idx];
-                                       if (pm != a.Modifier)
-                                               break;
-
-                                       if (!TypeManager.IsEqual (a.Type, parameter_type)) {
-                                               if (pm == Parameter.Modifier.OUT || pm == Parameter.Modifier.REF)
-                                                       break;
-
-                                               Expression conv = Convert.ImplicitConversion (ec, a.Expr, parameter_type, loc);
-                                               if (conv == null)
-                                                       break;
 
-                                               // Update the argument with the implicit conversion
-                                               if (a.Expr != conv)
-                                                       a.Expr = conv;
-                                       }
-
-                                       --params_arg_count;
-                                       ++a_idx;
-                               }
-                               if (params_arg_count > 0)
-                                       break;
+                       args = new ArrayList (Arguments.Count + 3);
+                       if (mg.IsInstance)
+                               args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
+                       else
+                               args.Add (new Argument (new NullLiteral (loc).CreateExpressionTree (ec)));
 
-                               if (parameter_type.IsPointer && !ec.InUnsafe) {
-                                       if (!may_fail)
-                                               UnsafeError (loc);
-                                       return false;
-                               }
+                       args.Add (new Argument (mg.CreateExpressionTree (ec)));
+                       foreach (Argument a in Arguments) {
+                               Expression e = a.Expr.CreateExpressionTree (ec);
+                               if (e != null)
+                                       args.Add (new Argument (e));
                        }
 
-                       if (a_idx == arg_count)
-                               return true;
-
-                       if (!may_fail)
-                               Error_InvalidArguments (loc, a_idx, method, delegate_type, a, pd);
-                       return false;
+                       return CreateExpressionFactoryCall ("Call", args);
                }
 
                public override Expression DoResolve (EmitContext ec)
                {
+                       // Don't resolve already resolved expression
+                       if (eclass != ExprClass.Invalid)
+                               return this;
+                       
                        Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
                        if (expr_resolved == null)
                                return null;
@@ -4469,16 +4486,30 @@ namespace Mono.CSharp {
                                        return (new DelegateInvocation (
                                                expr_resolved, Arguments, loc)).Resolve (ec);
                                }
-                               expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
-                               return null;
+
+                               MemberExpr me = expr_resolved as MemberExpr;
+                               if (me == 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;
                        }
 
                        //
                        // Next, evaluate all the expressions in the argument list
                        //
-                       if (Arguments != null){
-                               foreach (Argument a in Arguments){
-                                       if (!a.Resolve (ec, loc))
+                       if (Arguments != null && !arguments_resolved) {
+                               for (int i = 0; i < Arguments.Count; ++i)
+                               {
+                                       if (!((Argument)Arguments[i]).Resolve(ec, loc))
                                                return null;
                                }
                        }
@@ -4490,21 +4521,18 @@ namespace Mono.CSharp {
                        MethodInfo method = (MethodInfo)mg;
                        if (method != null) {
                                type = TypeManager.TypeToCoreType (method.ReturnType);
+
+                               // TODO: this is a copy of mg.ResolveMemberAccess method
                                Expression iexpr = mg.InstanceExpression;
                                if (method.IsStatic) {
-                                       if (iexpr == null || 
-                                           iexpr is This || iexpr is EmptyExpression ||
-                                           mg.IdenticalTypeName) {
+                                       if (iexpr == null ||
+                                               iexpr is This || iexpr is EmptyExpression ||
+                                               mg.IdenticalTypeName) {
                                                mg.InstanceExpression = null;
                                        } else {
                                                MemberExpr.error176 (loc, mg.GetSignatureForError ());
                                                return null;
                                        }
-                               } else {
-                                       if (iexpr == null || iexpr is EmptyExpression) {
-                                               SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
-                                               return null;
-                                       }
                                }
                        }
 
@@ -4535,22 +4563,8 @@ namespace Mono.CSharp {
                                return null;
                        }
                        
-                       if (mg.InstanceExpression != null){
-                               mg.InstanceExpression.CheckMarshalByRefAccess ();
-
-                               //
-                               // This is used to check that no methods are called in struct
-                               // constructors before all the fields on the struct have been
-                               // initialized.
-                               //
-                               if (!method.IsStatic){
-                                       This mgthis = mg.InstanceExpression as This;
-                                       if (mgthis != null){
-                                               if (!mgthis.CheckThisUsage (ec))
-                                                       return  null;
-                                       }
-                               }
-                       }
+                       if (mg.InstanceExpression != null)
+                               mg.InstanceExpression.CheckMarshalByRefAccess (ec);
 
                        eclass = ExprClass.Value;
                        return this;
@@ -4558,7 +4572,7 @@ namespace Mono.CSharp {
 
                protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
                {
-                       return mg.OverloadResolve (ec, Arguments, false, loc);
+                       return mg.OverloadResolve (ec, ref Arguments, false, loc);
                }
 
                bool IsSpecialMethodInvocation (MethodBase method)
@@ -4573,38 +4587,6 @@ namespace Mono.CSharp {
                        return true;
                }
 
-               // <summary>
-               //   Emits the list of arguments as an array
-               // </summary>
-               static void EmitParams (EmitContext ec, ArrayList arguments, int idx, int count)
-               {
-                       ILGenerator ig = ec.ig;
-                       Type t = null;
-                       for (int j = 0; j < count; j++){
-                               Argument a = (Argument) arguments [j + idx];
-                               if (j == 0) {
-                                       t = a.Expr.Type;
-                                       IntConstant.EmitInt (ig, count);
-                                       ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
-                               }
-                               
-                               ig.Emit (OpCodes.Dup);
-                               IntConstant.EmitInt (ig, j);
-
-                               bool is_stobj, has_type_arg;
-                               OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
-                               if (is_stobj)
-                                       ig.Emit (OpCodes.Ldelema, t);
-
-                               a.Emit (ec);
-
-                               if (has_type_arg)
-                                       ig.Emit (op, t);
-                               else
-                                       ig.Emit (op);
-                       }
-               }
-               
                /// <summary>
                ///   Emits a list of resolved Arguments that are in the arguments
                ///   ArrayList.
@@ -4619,10 +4601,12 @@ namespace Mono.CSharp {
                ///   which will be duplicated before any other args. Only EmitCall
                ///   should be using this interface.
                /// </summary>
-               public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
+               public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
                {
-                       ParameterData pd = mb == null ? null : TypeManager.GetParameterData (mb);
-                       int top = pd.Count;
+                       if (arguments == null)
+                               return;
+
+                       int top = arguments.Count;
                        LocalTemporary [] temps = null;
                        
                        if (dup_args && top != 0)
@@ -4630,42 +4614,7 @@ namespace Mono.CSharp {
 
                        int argument_index = 0;
                        Argument a;
-                       for (int i = 0; i < top; i++){
-                               if (pd != null){
-                                       if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
-                                               Type p_type = pd.ParameterType (i);
-                                               int params_args_count = arguments == null ?
-                                                       0 : arguments.Count - top + 1;
-
-                                               // Fill not provided argument
-                                               if (params_args_count <= 0) {
-                                                       ILGenerator ig = ec.ig;
-                                                       IntConstant.EmitInt (ig, 0);
-                                                       ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (p_type));
-                                               } else {
-                                                       //
-                                                       // Special case if we are passing the same data as the
-                                                       // params argument, we do not need to recreate an array.
-                                                       //
-                                                       a = (Argument) arguments [argument_index];
-                                                       if (params_args_count == 1 && p_type == a.Type) {
-                                                               ++argument_index;
-                                                               a.Emit (ec);
-                                                       } else {
-                                                               EmitParams (ec, arguments, i, params_args_count);
-                                                               argument_index += params_args_count;
-                                                       }
-                                               }
-
-                                               if (dup_args) {
-                                                       ec.ig.Emit (OpCodes.Dup);
-                                                       temps [i] = new LocalTemporary (p_type);
-                                                       temps [i].Store (ec);
-                                               }
-                                               continue;
-                                       }
-                               }
-
+                       for (int i = 0; i < top; i++) {
                                a = (Argument) arguments [argument_index++];
                                a.Emit (ec);
                                if (dup_args) {
@@ -4701,19 +4650,21 @@ namespace Mono.CSharp {
                /// <summary>
                /// This checks the ConditionalAttribute on the method 
                /// </summary>
-               static bool IsMethodExcluded (MethodBase method)
+               public static bool IsMethodExcluded (MethodBase method)
                {
                        if (method.IsConstructor)
                                return false;
 
-                       IMethodData md = TypeManager.GetMethod (method);
-                       if (md != null)
-                               return md.IsExcluded ();
+                       method = TypeManager.DropGenericMethodArguments (method);
+                       if (method.DeclaringType.Module == CodeGen.Module.Builder) {
+                               IMethodData md = TypeManager.GetMethod (method);
+                               if (md != null)
+                                       return md.IsExcluded ();
 
-                       // For some methods (generated by delegate class) GetMethod returns null
-                       // because they are not included in builder_to_method table
-                       if (method.DeclaringType is TypeBuilder)
+                               // For some methods (generated by delegate class) GetMethod returns null
+                               // because they are not included in builder_to_method table
                                return false;
+                       }
 
                        return AttributeTester.IsConditionalMethodExcluded (method);
                }
@@ -4758,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
@@ -4863,7 +4795,7 @@ namespace Mono.CSharp {
                        }
 
                        if (!omit_args)
-                               EmitArguments (ec, method, Arguments, dup_args, this_arg);
+                               EmitArguments (ec, Arguments, dup_args, this_arg);
 
 #if GMCS_SOURCE
                        if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
@@ -5061,8 +4993,8 @@ namespace Mono.CSharp {
                // If set, the new expression is for a value_target, and
                // we will not leave anything on the stack.
                //
-               Expression value_target;
-               bool value_target_set = false;
+               protected Expression value_target;
+               protected bool value_target_set;
                bool is_type_parameter = false;
                
                public New (Expression requested_type, ArrayList arguments, Location l)
@@ -5072,7 +5004,7 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
-               public bool SetValueTypeVariable (Expression value)
+               public bool SetTargetVariable (Expression value)
                {
                        value_target = value;
                        value_target_set = true;
@@ -5143,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;
                }
@@ -5239,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;
@@ -5293,7 +5233,7 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       method = method.OverloadResolve (ec, Arguments, false, loc);
+                       method = method.OverloadResolve (ec, ref Arguments, false, loc);
                        if (method == null)
                                return null;
 
@@ -5428,6 +5368,12 @@ namespace Mono.CSharp {
 
                }
 
+               public virtual bool HasInitializer {
+                       get {
+                               return false;
+                       }
+               }
+
                public void AddressOf (EmitContext ec, AddressOp Mode)
                {
                        if (is_type_parameter) {
@@ -5558,6 +5504,11 @@ namespace Mono.CSharp {
                {
                        Error (178, "Invalid rank specifier: expected `,' or `]'");
                }
+
+               protected override void Error_NegativeArrayIndex (Location loc)
+               {
+                       Report.Error (248, loc, "Cannot create an array with a negative size");
+               }
                
                bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
                {
@@ -5639,6 +5590,23 @@ namespace Mono.CSharp {
 
                        return true;
                }
+
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       if (dimensions != 1) {
+                               Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
+                               return null;
+                       }
+
+                       ArrayList args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
+                       args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
+                       if (array_data != null) {
+                               foreach (Expression e in array_data)
+                                       args.Add (new Argument (e.CreateExpressionTree (ec)));
+                       }
+
+                       return CreateExpressionFactoryCall ("NewArrayInit", args);
+               }               
                
                public void UpdateIndices ()
                {
@@ -5764,13 +5732,9 @@ namespace Mono.CSharp {
 
                        foreach (Argument a in arguments){
                                if (!a.Resolve (ec, loc))
-                                       return null;
-
-                               Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
-                               if (real_arg == null)
-                                       return null;
+                                       continue;
 
-                               a.Expr = real_arg;
+                               a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
                        }
                                                        
                        eclass = ExprClass.Value;
@@ -5804,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)
@@ -5952,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
                        //
@@ -6056,17 +6029,13 @@ namespace Mono.CSharp {
                        }
                }
 
-               void EmitArrayArguments (EmitContext ec)
-               {
-                       foreach (Argument a in arguments)
-                               a.EmitArrayArgument (ec);
-               }
-               
                public override void Emit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
-                       
-                       EmitArrayArguments (ec);
+
+                       foreach (Argument a in arguments)
+                               a.Emit (ec);
+
                        if (arguments.Count == 1)
                                ig.Emit (OpCodes.Newarr, array_element_type);
                        else {
@@ -6090,7 +6059,7 @@ namespace Mono.CSharp {
                        }                               
                }
 
-               public override bool GetAttributableValue (Type valueType, out object value)
+               public override bool GetAttributableValue (Type value_type, out object value)
                {
                        if (arguments.Count != 1) {
                                // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
@@ -6142,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));
+                                       }
                        }
                }
        }
@@ -6156,6 +6133,9 @@ namespace Mono.CSharp {
                public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
                        : base (null, rank, initializers, loc)
                {
+                       if (RootContext.Version <= LanguageVersion.ISO_2)
+                               Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
+                               
                        if (rank.Length > 2) {
                                while (rank [++dimensions] == ',');
                        } else {
@@ -6312,7 +6292,6 @@ namespace Mono.CSharp {
                                                      "Consider copying `this' to a local variable " +
                                                      "outside the anonymous method and using the " +
                                                      "local instead.");
-                                       return false;
                                }
 
                                RootScopeInfo host = block.Toplevel.RootScope;
@@ -6333,17 +6312,22 @@ namespace Mono.CSharp {
                //
                // Called from Invocation to check if the invocation is correct
                //
-               public bool CheckThisUsage (EmitContext ec)
+               public override void CheckMarshalByRefAccess (EmitContext ec)
                {
                        if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
                            !variable_info.IsAssigned (ec)) {
                                Error (188, "The `this' object cannot be used before all of its " +
                                       "fields are assigned to");
                                variable_info.SetAssigned (ec);
-                               return false;
                        }
+               }
 
-                       return true;
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       ArrayList args = new ArrayList (2);
+                       args.Add (new Argument (this));
+                       args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
+                       return CreateExpressionFactoryCall ("Constant", args);
                }
                
                public override Expression DoResolve (EmitContext ec)
@@ -6356,7 +6340,7 @@ namespace Mono.CSharp {
                                Error (27, "Keyword `this' is not available in the current context");
                                return null;
                        }
-
+                       
                        return this;
                }
 
@@ -6501,6 +6485,12 @@ namespace Mono.CSharp {
                                return retval;
                        }
                }
+               
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
+                       return null;
+               }
 
                public override Expression DoResolve (EmitContext ec)
                {
@@ -6586,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;
@@ -6598,7 +6599,7 @@ namespace Mono.CSharp {
                        ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
                }
 
-               public override bool GetAttributableValue (Type valueType, out object value)
+               public override bool GetAttributableValue (Type value_type, out object value)
                {
                        if (TypeManager.ContainsGenericParameters (typearg) &&
                                !TypeManager.IsGenericTypeDefinition (typearg)) {
@@ -6609,7 +6610,7 @@ namespace Mono.CSharp {
                                return false;
                        }
 
-                       if (valueType == TypeManager.object_type) {
+                       if (value_type == TypeManager.object_type) {
                                value = (object)typearg;
                                return true;
                        }
@@ -6646,10 +6647,42 @@ namespace Mono.CSharp {
                {
                        type = TypeManager.type_type;
                        typearg = TypeManager.void_type;
-                       // See description in TypeOf.
+
+                       return DoResolveBase ();
+               }
+       }
+
+       internal class TypeOfMethod : Expression
+       {
+               readonly MethodInfo method;
+
+               public TypeOfMethod (MethodInfo method, Location loc)
+               {
+                       this.method = method;
+                       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;
                }
+
+               public override void Emit (EmitContext ec)
+               {
+                       ec.ig.Emit (OpCodes.Ldtoken, method);
+                       ec.ig.Emit (OpCodes.Call, TypeManager.methodbase_get_type_from_handle);
+               }
        }
 
        /// <summary>
@@ -6679,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);
@@ -6731,9 +6764,6 @@ namespace Mono.CSharp {
 
                public QualifiedAliasMember (string alias, string identifier, Location l)
                {
-                       if (RootContext.Version == LanguageVersion.ISO_1)
-                               Report.FeatureIsNotISO1 (l, "namespace alias qualifier");
-
                        this.alias = alias;
                        this.identifier = identifier;
                        loc = l;
@@ -6894,6 +6924,11 @@ namespace Mono.CSharp {
                                        "System.NullReferenceException");
                        }
 
+                       if (args != null) {
+                               if (!args.Resolve (ec))
+                                       return null;
+                       }
+
                        Expression member_lookup;
                        member_lookup = MemberLookup (
                                ec.ContainerType, expr_type, expr_type, Identifier, loc);
@@ -6904,20 +6939,30 @@ namespace Mono.CSharp {
                        }
 #endif
                        if (member_lookup == null) {
-                               ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Identifier);
-                               if (ex_method_lookup != null) {
-                                       ex_method_lookup.ExtensionExpression = expr_resolved;
+                               ExprClass expr_eclass = expr_resolved.eclass;
 
-                                       if (args != null)
-                                               return ex_method_lookup.ResolveGeneric (ec, args);
+                               //
+                               // Extension methods are not allowed on all expression types
+                               //
+                               if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
+                                       expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
+                                       expr_eclass == ExprClass.EventAccess) {
+                                       ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Identifier);
+                                       if (ex_method_lookup != null) {
+                                               ex_method_lookup.ExtensionExpression = expr_resolved;
+
+                                               if (args != null) {
+                                                       ex_method_lookup.SetTypeArguments (args);
+                                               }
 
-                                       return ex_method_lookup.DoResolve (ec);
+                                               return ex_method_lookup.DoResolve (ec);
+                                       }
                                }
 
-                               if (!ec.IsInProbingMode)
-                                       Error_MemberLookupFailed (
-                                               ec.ContainerType, expr_type, expr_type, Identifier, null,
-                                               AllMemberTypes, AllBindingFlags);
+                               expr = expr_resolved;
+                               Error_MemberLookupFailed (
+                                       ec.ContainerType, expr_type, expr_type, Identifier, null,
+                                       AllMemberTypes, AllBindingFlags);
                                return null;
                        }
 
@@ -6956,21 +7001,16 @@ namespace Mono.CSharp {
                        }
 
                        MemberExpr me = (MemberExpr) member_lookup;
-                       member_lookup = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
-                       if (member_lookup == null)
-                               return me;
+                       me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
+                       if (me == null)
+                               return null;
 
                        if (args != null) {
-                               MethodGroupExpr mg = member_lookup as MethodGroupExpr;
-                               if (mg == null)
-                                       throw new InternalErrorException ();
-
-                               return mg.ResolveGeneric (ec, args);
+                               me.SetTypeArguments (args);
                        }
 
                        if (original != null && !TypeManager.IsValueType (expr_type)) {
-                               me = member_lookup as MemberExpr;
-                               if (me != null && me.IsInstance) {
+                               if (me.IsInstance) {
                                        LocalVariableReference var = expr_resolved as LocalVariableReference;
                                        if (var != null && !var.VerifyAssigned (ec))
                                                return null;
@@ -6981,9 +7021,9 @@ namespace Mono.CSharp {
                        // check.
 
                        if (right_side != null)
-                               return member_lookup.DoResolveLValue (ec, right_side);
+                               return me.DoResolveLValue (ec, right_side);
                        else
-                               return member_lookup.DoResolve (ec);
+                               return me.DoResolve (ec);
                }
 
                public override Expression DoResolve (EmitContext ec)
@@ -7039,17 +7079,30 @@ namespace Mono.CSharp {
                                if (silent)
                                        return null;
 
-                               member_lookup = MemberLookup(
-                                   rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
-                                       MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
+                               member_lookup = MemberLookup (
+                                       rc.DeclContainer.TypeBuilder, expr_type, expr_type, SimpleName.RemoveGenericArity (LookupIdentifier),
+                                       MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
+
+                               if (member_lookup != null) {
+                                       tnew_expr = member_lookup.ResolveAsTypeTerminal (rc, false);
+                                       if (tnew_expr == null)
+                                               return null;
+
+                                       Namespace.Error_TypeArgumentsCannotBeUsed (tnew_expr.Type, loc);
+                                       return null;
+                               }
+
+                               member_lookup = MemberLookup (
+                                       rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
+                                               MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
 
-                               if (member_lookup == null) {
+                               if (member_lookup == null) {
                                        Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
-                                                     Identifier, new_expr.GetSignatureForError ());
+                                                         Identifier, new_expr.GetSignatureForError ());
                                } else {
-                               // TODO: Report.SymbolRelatedToPreviousError
-                                   member_lookup.Error_UnexpectedKind (null, "type", loc);
-                               }
+                                       // TODO: Report.SymbolRelatedToPreviousError
+                                       member_lookup.Error_UnexpectedKind (null, "type", loc);
+                               }
                                return null;
                        }
 
@@ -7059,11 +7112,14 @@ namespace Mono.CSharp {
 
 #if GMCS_SOURCE
                        TypeArguments the_args = args;
-                       if (TypeManager.HasGenericArguments (expr_type)) {
-                               Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
-
+                       Type declaring_type = texpr.Type.DeclaringType;
+                       if (TypeManager.HasGenericArguments (declaring_type)) {
+                               while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
+                                       expr_type = expr_type.BaseType;
+                               }
+                               
                                TypeArguments new_args = new TypeArguments (loc);
-                               foreach (Type decl in decl_args)
+                               foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
                                        new_args.Add (new TypeExpression (decl, loc));
 
                                if (args != null)
@@ -7086,6 +7142,20 @@ namespace Mono.CSharp {
                        throw new Exception ("Should not happen");
                }
 
+               protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
+               {
+                       if (RootContext.Version > LanguageVersion.ISO_2 &&
+                               ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
+                               Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
+                                       "extension method `{1}' of type `{0}' could be found " +
+                                       "(are you missing a using directive or an assembly reference?)",
+                                       TypeManager.CSharpName (type), name);
+                               return;
+                       }
+
+                       base.Error_TypeDoesNotContainDefinition (type, name);
+               }
+
                public override string ToString ()
                {
                        return expr + "." + MemberName.MakeName (Identifier, args);
@@ -7116,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)
                {
@@ -7139,10 +7215,10 @@ namespace Mono.CSharp {
                                Expr.Emit (ec);
                }
 
-               public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
+               public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
                {
                        using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
-                               Expr.EmitBranchable (ec, target, onTrue);
+                               Expr.EmitBranchable (ec, target, on_true);
                }
 
                protected override void CloneTo (CloneContext clonectx, Expression t)
@@ -7165,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)
                {
@@ -7188,10 +7270,10 @@ namespace Mono.CSharp {
                                Expr.Emit (ec);
                }
                
-               public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
+               public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
                {
                        using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
-                               Expr.EmitBranchable (ec, target, onTrue);
+                               Expr.EmitBranchable (ec, target, on_true);
                }
 
                protected override void CloneTo (CloneContext clonectx, Expression t)
@@ -7242,6 +7324,16 @@ namespace Mono.CSharp {
                        return Expr != null;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       ArrayList args = new ArrayList (Arguments.Count + 1);
+                       args.Add (new Argument (Expr.CreateExpressionTree (ec)));
+                       foreach (Argument a in Arguments)
+                               args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
+
+                       return CreateExpressionFactoryCall ("ArrayIndex", args);
+               }
+
                Expression MakePointerAccess (EmitContext ec, Type t)
                {
                        if (t == TypeManager.void_ptr_type){
@@ -7298,12 +7390,15 @@ namespace Mono.CSharp {
                        if (!CommonResolve (ec))
                                return null;
 
-                       Type t = Expr.Type;
-                       if (t.IsArray)
+                       type = Expr.Type;
+                       if (type.IsArray)
                                return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
 
-                       if (t.IsPointer)
-                               return MakePointerAccess (ec, t);
+                       if (type.IsPointer)
+                               return MakePointerAccess (ec, type);
+
+                       if (Expr.eclass != ExprClass.Variable && type.IsValueType)
+                               Error_CannotModifyIntermediateExpressionValue (ec);
 
                        return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
                }
@@ -7313,6 +7408,11 @@ namespace Mono.CSharp {
                        throw new Exception ("Should never be reached");
                }
 
+               public override string GetSignatureForError ()
+               {
+                       return Expr.GetSignatureForError ();
+               }
+
                protected override void CloneTo (CloneContext clonectx, Expression t)
                {
                        ElementAccess target = (ElementAccess) t;
@@ -7345,6 +7445,11 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       return ea.CreateExpressionTree (ec);
+               }
+
                public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
                {
                        return DoResolve (ec);
@@ -7364,41 +7469,26 @@ namespace Mono.CSharp {
 #endif
 
                        Type t = ea.Expr.Type;
-                       if (t.GetArrayRank () != ea.Arguments.Count){
+                       int rank = ea.Arguments.Count;
+                       if (t.GetArrayRank () != rank) {
                                Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
                                          ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
                                return null;
                        }
 
-                        type = TypeManager.GetElementType (t);
-                        if (type.IsPointer && !ec.InUnsafe){
-                               UnsafeError (ea.Location);
-                               return null;
+                       if (rank != 1 && TypeManager.int_getlength_int == null) {
+                               TypeManager.int_getlength_int = TypeManager.GetPredefinedMethod (
+                                       TypeManager.array_type, "GetLength", loc, TypeManager.int32_type);
                        }
 
-                       foreach (Argument a in ea.Arguments){
-                               Type argtype = a.Type;
-
-                               if (argtype == TypeManager.int32_type ||
-                                   argtype == TypeManager.uint32_type ||
-                                   argtype == TypeManager.int64_type ||
-                                   argtype == TypeManager.uint64_type) {
-                                       Constant c = a.Expr as Constant;
-                                       if (c != null && c.IsNegative) {
-                                               Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)");
-                                       }
-                                       continue;
-                               }
-
-                               //
-                               // Mhm.  This is strage, because the Argument.Type is not the same as
-                               // Argument.Expr.Type: the value changes depending on the ref/out setting.
-                               //
-                               // Wonder if I will run into trouble for this.
-                               //
-                               a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
-                               if (a.Expr == null)
-                                       return null;
+                       type = TypeManager.GetElementType (t);
+                       if (type.IsPointer && !ec.InUnsafe) {
+                               UnsafeError (ea.Location);
+                               return null;
+                       }
+
+                       foreach (Argument a in ea.Arguments) {
+                               a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
                        }
                        
                        eclass = ExprClass.Variable;
@@ -7441,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);
@@ -7455,6 +7545,11 @@ namespace Mono.CSharp {
                                ig.Emit (OpCodes.Ldelem_Ref);
                }
 
+               protected override void Error_NegativeArrayIndex (Location loc)
+               {
+                       Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
+               }
+
                /// <summary>
                ///    Returns the right opcode to store an object of Type `t'
                ///    from an array of T.  
@@ -7465,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;
@@ -7552,22 +7647,22 @@ namespace Mono.CSharp {
                // initialized), then load the arguments the first time and store them
                // in locals.  otherwise load from local variables.
                //
-               // prepareForLoad is used in compound assignments to cache original index
+               // prepare_for_load is used in compound assignments to cache original index
                // values ( label[idx++] += s )
                //
-               LocalTemporary [] LoadArrayAndArguments (EmitContext ec, bool prepareForLoad)
+               LocalTemporary [] LoadArrayAndArguments (EmitContext ec, bool prepare_for_load)
                {
                        ea.Expr.Emit (ec);
 
                        LocalTemporary[] indexes = null;
-                       if (prepareForLoad) {
+                       if (prepare_for_load) {
                                ec.ig.Emit (OpCodes.Dup);
                                indexes = new LocalTemporary [ea.Arguments.Count];
                        }
 
                        for (int i = 0; i < ea.Arguments.Count; ++i) {
-                               ((Argument)ea.Arguments [i]).EmitArrayArgument (ec);
-                               if (!prepareForLoad)
+                               ((Argument)ea.Arguments [i]).Emit (ec);
+                               if (!prepare_for_load)
                                        continue;
 
                                // Keep original array index value on the stack
@@ -7725,118 +7820,135 @@ namespace Mono.CSharp {
                        }
                }
        }
-       
-       class Indexers {
-               // note that the ArrayList itself in mutable.  We just can't assign to 'Properties' again.
-               public readonly ArrayList Properties;
-               static Indexers empty;
-
-               public struct Indexer {
-                       public readonly PropertyInfo PropertyInfo;
-                       public readonly MethodInfo Getter, Setter;
 
-                       public Indexer (PropertyInfo property_info, MethodInfo get, MethodInfo set)
+       /// <summary>
+       ///   Expressions that represent an indexer call.
+       /// </summary>
+       public class IndexerAccess : Expression, IAssignMethod
+       {
+               class IndexerMethodGroupExpr : MethodGroupExpr
+               {
+                       public IndexerMethodGroupExpr (Indexers indexers, Location loc)
+                               : base (null, loc)
                        {
-                               this.PropertyInfo = property_info;
-                               this.Getter = get;
-                               this.Setter = set;
+                               Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
                        }
-               }
-
-               static Indexers ()
-               {
-                       empty = new Indexers (null);
-               }
 
-               Indexers (ArrayList array)
-               {
-                       Properties = array;
-               }
+                       public override string Name {
+                               get {
+                                       return "this";
+                               }
+                       }
 
-               static void Append (ref Indexers ix, Type caller_type, MemberInfo [] mi)
-               {
-                       bool dummy;
-                       if (mi == null)
-                               return;
-                       foreach (PropertyInfo property in mi){
-                               MethodInfo get, set;
+                       protected override int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
+                       {
+                               //
+                               // Here is the trick, decrease number of arguments by 1 when only
+                               // available property method is setter. This makes overload resolution
+                               // work correctly for indexers.
+                               //
                                
-                               get = property.GetGetMethod (true);
-                               set = property.GetSetMethod (true);
-                               if (get != null && !Expression.IsAccessorAccessible (caller_type, get, out dummy))
-                                       get = null;
-                               if (set != null && !Expression.IsAccessorAccessible (caller_type, set, out dummy))
-                                       set = null;
-                               if (get != null || set != null) {
-                                       if (ix == empty)
-                                               ix = new Indexers (new ArrayList ());
-                                       ix.Properties.Add (new Indexer (property, get, set));
-                               }
+                               if (method.Name [0] == 'g')
+                                       return parameters.Count;
+
+                               return parameters.Count - 1;
                        }
                }
 
-               static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
+               class Indexers
                {
-                       string p_name = TypeManager.IndexerPropertyName (lookup_type);
+                       // Contains either property getter or setter
+                       public ArrayList Methods;
+                       public ArrayList Properties;
 
-                       return TypeManager.MemberLookup (
-                               caller_type, caller_type, lookup_type, MemberTypes.Property,
-                               BindingFlags.Public | BindingFlags.Instance |
-                               BindingFlags.DeclaredOnly, p_name, null);
-               }
-               
-               static public Indexers GetIndexersForType (Type caller_type, Type lookup_type) 
-               {
-                       Indexers ix = empty;
+                       Indexers ()
+                       {
+                       }
 
-#if GMCS_SOURCE
-                       if (lookup_type.IsGenericParameter) {
-                               GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
-                               if (gc == null)
-                                       return empty;
+                       void Append (Type caller_type, MemberInfo [] mi)
+                       {
+                               if (mi == null)
+                                       return;
 
-                               if (gc.HasClassConstraint)
-                                       Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
+                               foreach (PropertyInfo property in mi) {
+                                       MethodInfo accessor = property.GetGetMethod (true);
+                                       if (accessor == null)
+                                               accessor = property.GetSetMethod (true);
 
-                               Type[] ifaces = gc.InterfaceConstraints;
-                               foreach (Type itype in ifaces)
-                                       Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
+                                       if (Methods == null) {
+                                               Methods = new ArrayList ();
+                                               Properties = new ArrayList ();
+                                       }
 
-                               return ix;
+                                       Methods.Add (accessor);
+                                       Properties.Add (property);
+                               }
                        }
-#endif
 
-                       Type copy = lookup_type;
-                       while (copy != TypeManager.object_type && copy != null){
-                               Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
-                               copy = copy.BaseType;
+                       static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
+                       {
+                               string p_name = TypeManager.IndexerPropertyName (lookup_type);
+
+                               return TypeManager.MemberLookup (
+                                       caller_type, caller_type, lookup_type, MemberTypes.Property,
+                                       BindingFlags.Public | BindingFlags.Instance |
+                                       BindingFlags.DeclaredOnly, p_name, null);
                        }
+                       
+                       public static Indexers GetIndexersForType (Type caller_type, Type lookup_type) 
+                       {
+                               Indexers ix = new Indexers ();
 
-                       if (lookup_type.IsInterface) {
-                               Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
-                               if (ifaces != null) {
+       #if GMCS_SOURCE
+                               if (lookup_type.IsGenericParameter) {
+                                       GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
+                                       if (gc == null)
+                                               return ix;
+
+                                       if (gc.HasClassConstraint)
+                                               ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
+
+                                       Type[] ifaces = gc.InterfaceConstraints;
                                        foreach (Type itype in ifaces)
-                                               Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
+                                               ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
+
+                                       return ix;
+                               }
+       #endif
+
+                               Type copy = lookup_type;
+                               while (copy != TypeManager.object_type && copy != null){
+                                       ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
+                                       copy = copy.BaseType;
+                               }
+
+                               if (lookup_type.IsInterface) {
+                                       Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
+                                       if (ifaces != null) {
+                                               foreach (Type itype in ifaces)
+                                                       ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
+                                       }
                                }
+
+                               return ix;
                        }
+               }
 
-                       return ix;
+               enum AccessorType
+               {
+                       Get,
+                       Set
                }
-       }
 
-       /// <summary>
-       ///   Expressions that represent an indexer call.
-       /// </summary>
-       public class IndexerAccess : Expression, IAssignMethod {
                //
                // Points to our "data" repository
                //
                MethodInfo get, set;
-               ArrayList set_arguments;
                bool is_base_indexer;
                bool prepared;
                LocalTemporary temp;
                LocalTemporary prepared_value;
+               Expression set_expr;
 
                protected Type indexer_type;
                protected Type current_type;
@@ -7858,6 +7970,17 @@ namespace Mono.CSharp {
                        this.loc = loc;
                }
 
+               static string GetAccessorName (AccessorType at)
+               {
+                       if (at == AccessorType.Set)
+                               return "set";
+
+                       if (at == AccessorType.Get)
+                               return "get";
+
+                       throw new NotImplementedException (at.ToString ());
+               }
+
                protected virtual bool CommonResolve (EmitContext ec)
                {
                        indexer_type = instance_expr.Type;
@@ -7868,67 +7991,7 @@ namespace Mono.CSharp {
 
                public override Expression DoResolve (EmitContext ec)
                {
-                       if (!CommonResolve (ec))
-                               return null;
-
-                       //
-                       // Step 1: Query for all `Item' *properties*.  Notice
-                       // that the actual methods are pointed from here.
-                       //
-                       // This is a group of properties, piles of them.  
-
-                       ArrayList AllGetters = null;
-
-                       Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
-                       if (ilist.Properties != null) {
-                               AllGetters = new ArrayList(ilist.Properties.Count);
-                               foreach (Indexers.Indexer ix in ilist.Properties) {
-                                       if (ix.Getter != null)
-                                               AllGetters.Add (ix.Getter);
-                               }
-                       }
-
-                       if (AllGetters == null) {
-                               Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
-                                       TypeManager.CSharpName (indexer_type));
-                               return null;
-                       }
-
-                       if (AllGetters.Count == 0) {
-                               // FIXME: we cannot simply select first one as the error message is missleading when
-                               // multiple indexers exist
-                               Indexers.Indexer first_indexer = (Indexers.Indexer)ilist.Properties[ilist.Properties.Count - 1];
-                               Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
-                                       TypeManager.GetFullNameSignature (first_indexer.PropertyInfo));
-                               return null;
-                       }
-
-                       get = (MethodInfo)new MethodGroupExpr (AllGetters, type, loc).OverloadResolve (ec,
-                                       arguments, false, loc);
-
-                       if (get == null) {
-                               Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
-                               return null;
-                       }
-
-                       //
-                       // Only base will allow this invocation to happen.
-                       //
-                       if (get.IsAbstract && this is BaseIndexerAccess){
-                               Error_CannotCallAbstractBase (TypeManager.CSharpSignature (get));
-                               return null;
-                       }
-
-                       type = get.ReturnType;
-                       if (type.IsPointer && !ec.InUnsafe){
-                               UnsafeError (loc);
-                               return null;
-                       }
-
-                       instance_expr.CheckMarshalByRefAccess ();
-                       
-                       eclass = ExprClass.IndexerAccess;
-                       return this;
+                       return ResolveAccessor (ec, AccessorType.Get);
                }
 
                public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
@@ -7941,72 +8004,93 @@ namespace Mono.CSharp {
 
                        // if the indexer returns a value type, and we try to set a field in it
                        if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
-                               Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
-                                             GetSignatureForError ());
-                               return null;
+                               Error_CannotModifyIntermediateExpressionValue (ec);
                        }
 
-                       ArrayList AllSetters = new ArrayList();
-                       if (!CommonResolve (ec))
+                       Expression e = ResolveAccessor (ec, AccessorType.Set);
+                       if (e == null)
                                return null;
 
-                       bool found_any = false, found_any_setters = false;
+                       set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
+                       return e;
+               }
 
-                       Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
-                       if (ilist.Properties != null) {
-                               found_any = true;
-                               foreach (Indexers.Indexer ix in ilist.Properties) {
-                                       if (ix.Setter != null)
-                                               AllSetters.Add (ix.Setter);
-                               }
-                       }
-                       if (AllSetters.Count > 0) {
-                               found_any_setters = true;
-                               set_arguments = (ArrayList) arguments.Clone ();
-                               set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
-                               set = (MethodInfo)(new MethodGroupExpr (AllSetters, type, loc)).OverloadResolve (
-                                       ec,
-                                       set_arguments, false, loc);
-                       }
+               Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
+               {
+                       if (!CommonResolve (ec))
+                               return null;
 
-                       if (!found_any) {
+                       Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
+                       if (ilist.Methods == null) {
                                Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
-                                             TypeManager.CSharpName (indexer_type));
+                                                 TypeManager.CSharpName (indexer_type));
                                return null;
                        }
 
-                       if (!found_any_setters) {
-                               Error (154, "indexer can not be used in this context, because " +
-                                      "it lacks a `set' accessor");
+                       MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
+                       mg = mg.OverloadResolve (ec, ref arguments, false, loc);
+                       if (mg == null)
                                return null;
+
+                       MethodInfo mi = (MethodInfo) mg;
+                       PropertyInfo pi = null;
+                       for (int i = 0; i < ilist.Methods.Count; ++i) {
+                               if (ilist.Methods [i] == mi) {
+                                       pi = (PropertyInfo) ilist.Properties [i];
+                                       break;
+                               }
+                       }
+
+                       type = TypeManager.TypeToCoreType (pi.PropertyType);
+                       if (type.IsPointer && !ec.InUnsafe)
+                               UnsafeError (loc);
+
+                       MethodInfo accessor;
+                       if (accessorType == AccessorType.Get) {
+                               accessor = get = pi.GetGetMethod (true);
+                       } else {
+                               accessor = set = pi.GetSetMethod (true);
+                               if (accessor == null && pi.GetGetMethod (true) != null) {
+                                       Report.SymbolRelatedToPreviousError (pi);
+                                       Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
+                                               TypeManager.GetFullNameSignature (pi));
+                                       return null;
+                               }
                        }
 
-                       if (set == null) {
-                               Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
+                       if (accessor == null) {
+                               Report.SymbolRelatedToPreviousError (pi);
+                               Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
+                                       TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
                                return null;
                        }
 
                        //
                        // Only base will allow this invocation to happen.
                        //
-                       if (set.IsAbstract && this is BaseIndexerAccess){
-                               Error_CannotCallAbstractBase (TypeManager.CSharpSignature (set));
-                               return null;
+                       if (accessor.IsAbstract && this is BaseIndexerAccess) {
+                               Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
                        }
 
-                       //
-                       // Now look for the actual match in the list of indexers to set our "return" type
-                       //
-                       type = TypeManager.void_type;   // default value
-                       foreach (Indexers.Indexer ix in ilist.Properties){
-                               if (ix.Setter == set){
-                                       type = ix.PropertyInfo.PropertyType;
-                                       break;
+                       bool must_do_cs1540_check;
+                       if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
+                               if (set == null)
+                                       set = pi.GetSetMethod (true);
+                               else
+                                       get = pi.GetGetMethod (true);
+
+                               if (set != null && get != null &&
+                                       (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
+                                       Report.SymbolRelatedToPreviousError (accessor);
+                                       Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
+                                               TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
+                               } else {
+                                       Report.SymbolRelatedToPreviousError (pi);
+                                       ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
                                }
                        }
 
-                       instance_expr.CheckMarshalByRefAccess ();
-
+                       instance_expr.CheckMarshalByRefAccess (ec);
                        eclass = ExprClass.IndexerAccess;
                        return this;
                }
@@ -8035,8 +8119,8 @@ namespace Mono.CSharp {
                public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
                {
                        prepared = prepare_for_load;
-                       Argument a = (Argument) set_arguments [set_arguments.Count - 1];
-                       
+                       Expression value = set_expr;
+
                        if (prepared) {
                                Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
                                        arguments, loc, true, false);
@@ -8055,10 +8139,11 @@ namespace Mono.CSharp {
                                temp = new LocalTemporary (Type);
                                source.Emit (ec);
                                temp.Store (ec);
-                               a.Expr = temp;
+                               value = temp;
                        }
                        
-                       Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, set_arguments, loc, false, prepared);
+                       arguments.Add (new Argument (value, Argument.AType.Expression));
+                       Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
                        
                        if (temp != null) {
                                temp.Emit (ec);
@@ -8066,7 +8151,6 @@ namespace Mono.CSharp {
                        }
                }
                
-               
                public override void Emit (EmitContext ec)
                {
                        Emit (ec, false);
@@ -8074,8 +8158,7 @@ namespace Mono.CSharp {
 
                public override string GetSignatureForError ()
                {
-                       // FIXME: print the argument list of the indexer
-                       return instance_expr.GetSignatureForError () + ".this[...]";
+                       return TypeManager.CSharpSignature (get != null ? get : set, false);
                }
 
                protected override void CloneTo (CloneContext clonectx, Expression t)
@@ -8174,31 +8257,17 @@ namespace Mono.CSharp {
                                left = ec.GetThis (loc);
 
                        MemberExpr me = (MemberExpr) member_lookup;
-                       
-                       Expression e = me.ResolveMemberAccess (ec, left, loc, null);
-
-                       if (e is PropertyExpr) {
-                               PropertyExpr pe = (PropertyExpr) e;
-                               pe.IsBase = true;
-                       } else if (e is EventExpr) {
-                               EventExpr ee = (EventExpr) e;
-                               ee.IsBase = true;
-                       }
-
-                       MethodGroupExpr mg = e as MethodGroupExpr;
-                       if (mg != null)
-                               mg.IsBase = true;
+                       me = me.ResolveMemberAccess (ec, left, loc, null);
+                       if (me == null)
+                               return null;
 
+                       me.IsBase = true;
                        if (args != null) {
-                               if (mg != null)
-                                       return mg.ResolveGeneric (ec, args);
-
-                               Report.Error (307, loc, "`{0}' cannot be used with type arguments",
-                                             Identifier);
-                               return null;
+                               args.Resolve (ec);
+                               me.SetTypeArguments (args);
                        }
 
-                       return e;
+                       return me;
                }
 
                public override void Emit (EmitContext ec)
@@ -8210,7 +8279,8 @@ namespace Mono.CSharp {
                {
                        BaseAccess target = (BaseAccess) t;
 
-                       target.args = args.Clone ();
+                       if (args != null)
+                               target.args = args.Clone ();
                }
        }
 
@@ -8339,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;
                }
@@ -8356,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)
                {
@@ -8367,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);
                }
        }
 
@@ -8401,18 +8474,16 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
-#if GMCS_SOURCE
                public Expression RemoveNullable ()
                {
                        if (dim.EndsWith ("?")) {
                                dim = dim.Substring (0, dim.Length - 1);
-                               if (dim == "")
+                               if (dim.Length == 0)
                                        return left;
                        }
 
                        return this;
                }
-#endif
 
                protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
                {
@@ -8533,6 +8604,52 @@ namespace Mono.CSharp {
                }
        }
 
+       //
+       // Encapsulates a conversion rules required for array indexes
+       //
+       public class ArrayIndexCast : Expression
+       {
+               Expression expr;
+
+               public ArrayIndexCast (Expression expr)
+               {
+                       this.expr = expr;
+                       this.loc = expr.Location;
+               }
+
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       ArrayList args = new ArrayList (2);
+                       args.Add (new Argument (expr.CreateExpressionTree (ec)));
+                       args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
+                       return CreateExpressionFactoryCall ("ConvertChecked", args);
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       type = expr.Type;
+                       eclass = expr.eclass;
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       expr.Emit (ec);
+                               
+                       if (type == TypeManager.int32_type)
+                               return;
+
+                       if (type == TypeManager.uint32_type)
+                               ec.ig.Emit (OpCodes.Conv_U);
+                       else if (type == TypeManager.int64_type)
+                               ec.ig.Emit (OpCodes.Conv_Ovf_I);
+                       else if (type == TypeManager.uint64_type)
+                               ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
+                       else
+                               throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
+               }
+       }
+
        //
        // Used by the fixed statement
        //
@@ -8557,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);
@@ -8686,7 +8809,18 @@ namespace Mono.CSharp {
                                return initializer;
                        }
 
-                       return new Assign (element_member, initializer, loc).Resolve (ec);
+                       Assign a = new Assign (element_member, initializer, loc);
+                       if (a.Resolve (ec) == null)
+                               return null;
+
+                       //
+                       // Ignore field initializers with default value
+                       //
+                       Constant c = a.Source as Constant;
+                       if (c != null && c.IsDefaultInitializer (a.Type) && a.Target.eclass == ExprClass.Variable)
+                               return EmptyExpressionStatement.Instance;
+
+                       return a;
                }
 
                protected override Expression Error_MemberLookupFailed (MemberInfo[] members)
@@ -8840,7 +8974,11 @@ namespace Mono.CSharp {
                                        }
                                }
 
-                               initializers [i] = initializer.Resolve (ec);
+                               Expression e = initializer.Resolve (ec);
+                               if (e == EmptyExpressionStatement.Instance)
+                                       initializers.RemoveAt (i--);
+                               else
+                                       initializers [i] = e;
                        }
 
                        type = typeof (CollectionOrObjectInitializers);
@@ -8865,8 +9003,49 @@ namespace Mono.CSharp {
        //
        public class NewInitialize : New
        {
+               //
+               // This class serves as a proxy for variable initializer target instances.
+               // A real variable is assigned later when we resolve left side of an
+               // assignment
+               //
+               sealed class InitializerTargetExpression : Expression, IMemoryLocation
+               {
+                       NewInitialize new_instance;
+
+                       public InitializerTargetExpression (NewInitialize newInstance)
+                       {
+                               this.type = newInstance.type;
+                               this.loc = newInstance.loc;
+                               this.eclass = newInstance.eclass;
+                               this.new_instance = newInstance;
+                       }
+
+                       public override Expression DoResolve (EmitContext ec)
+                       {
+                               return this;
+                       }
+
+                       public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
+                       {
+                               return this;
+                       }
+
+                       public override void Emit (EmitContext ec)
+                       {
+                               new_instance.value_target.Emit (ec);
+                       }
+
+                       #region IMemoryLocation Members
+
+                       public void AddressOf (EmitContext ec, AddressOp mode)
+                       {
+                               ((IMemoryLocation)new_instance.value_target).AddressOf (ec, mode);
+                       }
+
+                       #endregion
+               }
+
                CollectionOrObjectInitializers initializers;
-               TemporaryVariable type_instance;
 
                public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
                        : base (requested_type, arguments, l)
@@ -8879,11 +9058,14 @@ namespace Mono.CSharp {
                        base.CloneTo (clonectx, t);
 
                        NewInitialize target = (NewInitialize) t;
-                       target.initializers = (CollectionOrObjectInitializers)initializers.Clone (clonectx);
+                       target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
                }
 
                public override Expression DoResolve (EmitContext ec)
                {
+                       if (eclass != ExprClass.Invalid)
+                               return this;
+                       
                        Expression e = base.DoResolve (ec);
                        if (type == null)
                                return null;
@@ -8892,11 +9074,8 @@ namespace Mono.CSharp {
                        if (initializers.IsEmpty)
                                return e;
 
-                       type_instance = new TemporaryVariable (type, loc);
-                       type_instance = (TemporaryVariable)type_instance.Resolve (ec);
-
                        Expression previous = ec.CurrentInitializerVariable;
-                       ec.CurrentInitializerVariable = type_instance;
+                       ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
                        initializers.Resolve (ec);
                        ec.CurrentInitializerVariable = previous;
                        return this;
@@ -8906,9 +9085,50 @@ namespace Mono.CSharp {
                {
                        base.Emit (ec);
 
-                       type_instance.EmitStore (ec);
+                       //
+                       // If target is a value, let's use it
+                       //
+                       VariableReference variable = value_target as VariableReference;
+                       if (variable != null) {
+                               if (variable.IsRef)
+                                       StoreFromPtr (ec.ig, type);
+                               else
+                                       variable.Variable.EmitAssign (ec);
+                       } else {
+                               if (value_target == null || value_target_set)
+                                       value_target = new LocalTemporary (type);
+
+                               ((LocalTemporary) value_target).Store (ec);
+                       }
+
                        initializers.Emit (ec);
-                       type_instance.Emit (ec);
+
+                       if (variable == null)
+                               value_target.Emit (ec);
+               }
+
+               public override void EmitStatement (EmitContext ec)
+               {
+                       if (initializers.IsEmpty) {
+                               base.EmitStatement (ec);
+                               return;
+                       }
+
+                       base.Emit (ec);
+
+                       if (value_target == null) {
+                               LocalTemporary variable = new LocalTemporary (type);
+                               variable.Store (ec);
+                               value_target = variable;
+                       }
+
+                       initializers.EmitStatement (ec);
+               }
+
+               public override bool HasInitializer {
+                       get {
+                               return !initializers.IsEmpty;
+                       }
                }
        }
 
@@ -9043,14 +9263,19 @@ namespace Mono.CSharp {
                        type = e.Type;
                        if (type == TypeManager.void_type || type == TypeManager.null_type ||
                                type == TypeManager.anonymous_method_type || type.IsPointer) {
-                               Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
-                                       Name, e.GetSignatureForError ());
+                               Error_InvalidInitializer (e);
                                return null;
                        }
 
                        return e;
                }
 
+               protected virtual void Error_InvalidInitializer (Expression initializer)
+               {
+                       Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
+                               Name, initializer.GetSignatureForError ());
+               }
+
                public override void Emit (EmitContext ec)
                {
                        throw new InternalErrorException ("Should not be reached");