Inflate custom site container delegates correctly.
[mono.git] / mcs / mcs / expression.cs
index 9f0f3f4c8d628adb44ab2786b69d0bebdab2ca03..ccfb19e030fbbe7eff683e228474a8a2acd59ed0 100644 (file)
@@ -8,7 +8,6 @@
 // Copyright 2001, 2002, 2003 Ximian, Inc.
 // Copyright 2003-2008 Novell, Inc.
 //
-#define USE_OLD
 
 namespace Mono.CSharp {
        using System;
@@ -24,19 +23,17 @@ namespace Mono.CSharp {
        // resolve phase
        //
        public class UserOperatorCall : Expression {
-               public delegate Expression ExpressionTreeExpression (ResolveContext ec, MethodGroupExpr mg);
-
                protected readonly Arguments arguments;
-               protected readonly MethodGroupExpr mg;
-               readonly ExpressionTreeExpression expr_tree;
+               protected readonly MethodSpec oper;
+               readonly Func<ResolveContext, Expression, Expression> expr_tree;
 
-               public UserOperatorCall (MethodGroupExpr mg, Arguments args, ExpressionTreeExpression expr_tree, Location loc)
+               public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)
                {
-                       this.mg = mg;
+                       this.oper = oper;
                        this.arguments = args;
                        this.expr_tree = expr_tree;
 
-                       type = mg.BestCandidate.ReturnType;
+                       type = oper.ReturnType;
                        eclass = ExprClass.Value;
                        this.loc = loc;
                }
@@ -44,11 +41,11 @@ namespace Mono.CSharp {
                public override Expression CreateExpressionTree (ResolveContext ec)
                {
                        if (expr_tree != null)
-                               return expr_tree (ec, mg);
+                               return expr_tree (ec, new TypeOfMethod (oper, loc));
 
                        Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
                                new NullLiteral (loc),
-                               mg.CreateExpressionTree (ec));
+                               new TypeOfMethod (oper, loc));
 
                        return CreateExpressionFactoryCall (ec, "Call", args);
                }
@@ -68,18 +65,14 @@ namespace Mono.CSharp {
 
                public override void Emit (EmitContext ec)
                {
-                       mg.EmitCall (ec, arguments);
+                       Invocation.EmitCall (ec, null, oper, arguments, loc);
                }
 
                public override SLE.Expression MakeExpression (BuilderContext ctx)
                {
-                       var method = mg.BestCandidate.GetMetaInfo () as MethodInfo;
+                       var method = oper.GetMetaInfo () as MethodInfo;
                        return SLE.Expression.Call (method, Arguments.MakeExpression (arguments, ctx));
                }
-
-               public MethodGroupExpr Method {
-                       get { return mg; }
-               }
        }
 
        public class ParenthesizedExpression : ShimExpression
@@ -330,7 +323,7 @@ namespace Mono.CSharp {
                        return CreateExpressionTree (ec, null);
                }
 
-               Expression CreateExpressionTree (ResolveContext ec, MethodGroupExpr user_op)
+               Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
                {
                        string method_name;
                        switch (Oper) {
@@ -357,7 +350,8 @@ namespace Mono.CSharp {
                        Arguments args = new Arguments (2);
                        args.Add (new Argument (Expr.CreateExpressionTree (ec)));
                        if (user_op != null)
-                               args.Add (new Argument (user_op.CreateExpressionTree (ec)));
+                               args.Add (new Argument (user_op));
+
                        return CreateExpressionFactoryCall (ec, method_name, args);
                }
 
@@ -628,7 +622,7 @@ namespace Mono.CSharp {
                                VariableInfo vi = vr.VariableInfo;
                                if (vi != null) {
                                        if (vi.LocalInfo != null)
-                                               vi.LocalInfo.Used = true;
+                                               vi.LocalInfo.SetIsUsed ();
 
                                        //
                                        // A variable is considered definitely assigned if you take its address.
@@ -687,20 +681,21 @@ namespace Mono.CSharp {
                                throw new InternalErrorException (Oper.ToString ());
                        }
 
-                       string op_name = CSharp.Operator.GetMetadataName (op_type);
-                       MethodGroupExpr user_op = MethodLookup (ec.Compiler, ec.CurrentType, expr.Type, MemberKind.Operator, op_name, 0, expr.Location);
-                       if (user_op == null)
+                       var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
+                       if (methods == null)
                                return null;
 
                        Arguments args = new Arguments (1);
                        args.Add (new Argument (expr));
-                       user_op = user_op.OverloadResolve (ec, ref args, false, expr.Location);
 
-                       if (user_op == null)
+                       var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
+                       var oper = res.ResolveOperator (ec, ref args);
+
+                       if (oper == null)
                                return null;
 
                        Expr = args [0].Expr;
-                       return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
+                       return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
                }
 
                //
@@ -734,7 +729,7 @@ namespace Mono.CSharp {
                                        continue;
                                }
 
-                               int result = MethodGroupExpr.BetterTypeConversion (ec, best_expr.Type, t);
+                               int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
                                if (result == 0) {
                                        ec.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
                                                OperName (Oper), TypeManager.CSharpName (expr.Type));
@@ -862,7 +857,7 @@ namespace Mono.CSharp {
                        }
 
                        if (expr.Type == TypeManager.void_ptr_type) {
-                               ec.Report.Error (242, loc, "The operation in question is undefined on void pointers");
+                               Error_VoidPointerOperation (ec);
                                return null;
                        }
 
@@ -979,6 +974,8 @@ namespace Mono.CSharp {
                // Holds the real operation
                Expression operation;
 
+               static TypeSpec[] predefined;
+
                public UnaryMutator (Mode m, Expression e, Location loc)
                {
                        mode = m;
@@ -991,6 +988,29 @@ namespace Mono.CSharp {
                        return new SimpleAssign (this, this).CreateExpressionTree (ec);
                }
 
+               void CreatePredefinedOperators ()
+               {
+                       //
+                       // Predefined ++ and -- operators exist for the following types: 
+                       // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
+                       //
+                       predefined = new TypeSpec[] {
+                               TypeManager.int32_type,
+
+                               TypeManager.sbyte_type,
+                               TypeManager.byte_type,
+                               TypeManager.short_type,
+                               TypeManager.ushort_type,
+                               TypeManager.uint32_type,
+                               TypeManager.int64_type,
+                               TypeManager.uint64_type,
+                               TypeManager.char_type,
+                               TypeManager.float_type,
+                               TypeManager.double_type,
+                               TypeManager.decimal_type
+                       };
+               }
+
                protected override Expression DoResolve (ResolveContext ec)
                {
                        expr = expr.Resolve (ec);
@@ -1016,7 +1036,108 @@ namespace Mono.CSharp {
 
                        eclass = ExprClass.Value;
                        type = expr.Type;
-                       return ResolveOperator (ec);
+
+                       if (expr is RuntimeValueExpression) {
+                               operation = expr;
+                       } else {
+                               // Use itself at the top of the stack
+                               operation = new EmptyExpression (type);
+                       }
+
+                       //
+                       // The operand of the prefix/postfix increment decrement operators
+                       // should be an expression that is classified as a variable,
+                       // a property access or an indexer access
+                       //
+                       // TODO: Move to parser, expr is ATypeNameExpression
+                       if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
+                               expr = expr.ResolveLValue (ec, expr);
+                       } else {
+                               ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
+                       }
+
+                       //
+                       // Step 1: Try to find a user operator, it has priority over predefined ones
+                       //
+                       var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
+                       var methods = MemberCache.GetUserOperator (type, user_op, false);
+
+                       if (methods != null) {
+                               Arguments args = new Arguments (1);
+                               args.Add (new Argument (expr));
+
+                               var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
+                               var method = res.ResolveOperator (ec, ref args);
+                               if (method == null)
+                                       return null;
+
+                               args[0].Expr = operation;
+                               operation = new UserOperatorCall (method, args, null, loc);
+                               operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
+                               return this;
+                       }
+
+                       //
+                       // Step 2: Try predefined types
+                       //
+                       if (predefined == null)
+                               CreatePredefinedOperators ();
+
+                       // Predefined without user conversion first for speed-up
+                       Expression source = null;
+                       bool primitive_type = false;
+                       foreach (var t in predefined) {
+                               if (t == type) {
+                                       source = operation;
+                                       primitive_type = true;
+                                       break;
+                               }
+                       }
+
+                       // ++/-- on pointer variables of all types except void*
+                       if (source == null && type.IsPointer) {
+                               if (type == TypeManager.void_ptr_type) {
+                                       Error_VoidPointerOperation (ec);
+                                       return null;
+                               }
+
+                               source = operation;
+                       }
+
+                       if (source == null) {
+                               // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
+                               foreach (var t in predefined) {
+                                       source = Convert.ImplicitUserConversion (ec, operation, t, loc);
+                                       if (source != null) {
+                                               break;
+                                       }
+                               }
+                       }
+
+                       // ++/-- on enum types
+                       if (source == null && type.IsEnum)
+                               source = operation;
+
+                       if (source == null) {
+                               Unary.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
+                               return null;
+                       }
+
+                       var one = new IntConstant (1, loc);
+                       var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
+                       operation = new Binary (op, source, one, loc);
+                       operation = operation.Resolve (ec);
+                       if (operation == null)
+                               throw new NotImplementedException ("should not be reached");
+
+                       if (operation.Type != type) {
+                               if (primitive_type)
+                                       operation = Convert.ExplicitNumericConversion (operation, type);
+                               else
+                                       operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
+                       }
+
+                       return this;
                }
 
                void EmitCode (EmitContext ec, bool is_expr)
@@ -1062,18 +1183,6 @@ namespace Mono.CSharp {
                        get { return (mode & Mode.IsDecrement) != 0; }
                }
 
-               //
-               //   Returns whether an object of type `t' can be incremented
-               //   or decremented with add/sub (ie, basically whether we can
-               //   use pre-post incr-decr operations on it, but it is not a
-               //   System.Decimal, which we require operator overloading to catch)
-               //
-               static bool IsPredefinedOperator (TypeSpec t)
-               {
-                       return (TypeManager.IsPrimitiveType (t) && t != TypeManager.bool_type) ||
-                               TypeManager.IsEnumType (t) ||
-                               t.IsPointer && t != TypeManager.void_ptr_type;
-               }
 
 #if NET_4_0
                public override SLE.Expression MakeExpression (BuilderContext ctx)
@@ -1084,82 +1193,16 @@ namespace Mono.CSharp {
                }
 #endif
 
-               protected override void CloneTo (CloneContext clonectx, Expression t)
+               public static void Reset ()
                {
-                       UnaryMutator target = (UnaryMutator) t;
-
-                       target.expr = expr.Clone (clonectx);
+                       predefined = null;
                }
 
-               Expression ResolveOperator (ResolveContext ec)
+               protected override void CloneTo (CloneContext clonectx, Expression t)
                {
-                       if (expr is RuntimeValueExpression) {
-                               operation = expr;
-                       } else {
-                               // Use itself at the top of the stack
-                               operation = new EmptyExpression (type);
-                       }
-
-                       //
-                       // The operand of the prefix/postfix increment decrement operators
-                       // should be an expression that is classified as a variable,
-                       // a property access or an indexer access
-                       //
-                       if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
-                               expr = expr.ResolveLValue (ec, expr);
-                       } else {
-                               ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
-                       }
-
-                       //
-                       // 1. Check predefined types
-                       //
-                       if (IsPredefinedOperator (type)) {
-                               // TODO: Move to IntConstant once I get rid of int32_type
-                               var one = new IntConstant (1, loc);
-
-                               // TODO: Cache this based on type when using EmptyExpression in
-                               // context cache
-                               Binary.Operator op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
-                               operation = new Binary (op, operation, one, loc);
-                               operation = operation.Resolve (ec);
-                               if (operation != null && operation.Type != type)
-                                       operation = Convert.ExplicitNumericConversion (operation, type);
-
-                               return this;
-                       }
-
-                       //
-                       // Step 2: Perform Operator Overload location
-                       //
-                       string op_name;
-
-                       if (IsDecrement)
-                               op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
-                       else
-                               op_name = Operator.GetMetadataName (Operator.OpType.Increment);
-
-                       var mg = MethodLookup (ec.Compiler, ec.CurrentType, type, MemberKind.Operator, op_name, 0, loc);
-
-                       if (mg != null) {
-                               Arguments args = new Arguments (1);
-                               args.Add (new Argument (expr));
-                               mg = mg.OverloadResolve (ec, ref args, false, loc);
-                               if (mg == null)
-                                       return null;
-
-                               args[0].Expr = operation;
-                               operation = new UserOperatorCall (mg, args, null, loc);
-                               operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
-                               return this;
-                       }
-
-                       string name = IsDecrement ?
-                               Operator.GetName (Operator.OpType.Decrement) :
-                               Operator.GetName (Operator.OpType.Increment);
+                       UnaryMutator target = (UnaryMutator) t;
 
-                       Unary.Error_OperatorCannotBeApplied (ec, loc, name, type);
-                       return null;
+                       target.expr = expr.Clone (clonectx);
                }
        }
 
@@ -1351,6 +1394,12 @@ namespace Mono.CSharp {
                                if (TypeManager.IsGenericParameter (t))
                                        return ResolveGenericParameter (ec, d, (TypeParameterSpec) t);
 
+                               if (t == InternalType.Dynamic) {
+                                       ec.Report.Warning (1981, 3, loc,
+                                               "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
+                                               OperatorName, t.GetSignatureForError ());
+                               }
+
                                if (TypeManager.IsStruct (d)) {
                                        if (Convert.ImplicitBoxingConversion (null, d, t) != null)
                                                return CreateConstantResult (ec, true);
@@ -1454,11 +1503,16 @@ namespace Mono.CSharp {
                        if (expr.IsNull && TypeManager.IsNullableType (type)) {
                                return Nullable.LiftedNull.CreateFromExpression (ec, this);
                        }
+
+                       // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
+                       if (etype == InternalType.Dynamic) {
+                               do_isinst = true;
+                               return this;
+                       }
                        
                        Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
                        if (e != null){
                                expr = e;
-                               do_isinst = false;
                                return this;
                        }
 
@@ -1488,19 +1542,11 @@ namespace Mono.CSharp {
                }
        }
        
-       /// <summary>
-       ///   This represents a typecast in the source language.
-       ///
-       ///   FIXME: Cast expressions have an unusual set of parsing
-       ///   rules, we need to figure those out.
-       /// </summary>
+       //
+       // This represents a typecast in the source language.
+       //
        public class Cast : ShimExpression {
                Expression target_type;
-                       
-               public Cast (Expression cast_type, Expression expr)
-                       : this (cast_type, expr, cast_type.Location)
-               {
-               }
 
                public Cast (Expression cast_type, Expression expr, Location loc)
                        : base (expr)
@@ -1541,14 +1587,13 @@ namespace Mono.CSharp {
 
                        if (type.IsPointer && !ec.IsUnsafe) {
                                UnsafeError (ec, loc);
-                       } else if (expr.Type == InternalType.Dynamic) {
-                               Arguments arg = new Arguments (1);
-                               arg.Add (new Argument (expr));
-                               return new DynamicConversion (type, CSharpBinderFlags.ConvertExplicit, arg, loc).Resolve (ec);
                        }
 
-                       expr = Convert.ExplicitConversion (ec, expr, type, loc);
-                       return expr;
+                       var res = Convert.ExplicitConversion (ec, expr, type, loc);
+                       if (res == expr)
+                               return EmptyCast.Create (res, type);
+
+                       return res;
                }
                
                protected override void CloneTo (CloneContext clonectx, Expression t)
@@ -1626,7 +1671,7 @@ namespace Mono.CSharp {
                        if (TypeManager.IsReferenceType (type))
                                return new NullConstant (type, loc);
 
-                       Constant c = New.Constantify (type);
+                       Constant c = New.Constantify (type, expr.Location);
                        if (c != null)
                                return c.Resolve (ec);
 
@@ -1705,7 +1750,7 @@ namespace Mono.CSharp {
 
                                var c = b.right as Constant;
                                if (c != null) {
-                                       if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.BitwiseOr || b.oper == Operator.Subtraction))
+                                       if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.Subtraction || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
                                                return ReducedExpression.Create (b.left, b).Resolve (ec);
                                        if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
                                                return ReducedExpression.Create (b.left, b).Resolve (ec);
@@ -1714,7 +1759,7 @@ namespace Mono.CSharp {
 
                                c = b.left as Constant;
                                if (c != null) {
-                                       if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.BitwiseOr))
+                                       if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.Subtraction || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
                                                return ReducedExpression.Create (b.right, b).Resolve (ec);
                                        if (b.oper == Operator.Multiply && c.IsOneInteger)
                                                return ReducedExpression.Create (b.right, b).Resolve (ec);
@@ -1734,8 +1779,8 @@ namespace Mono.CSharp {
 
                        public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
                        {
-                               if (TypeManager.IsEqual (left, lexpr.Type) &&
-                                       TypeManager.IsEqual (right, rexpr.Type))
+                               // Quick path
+                               if (left == lexpr.Type && right == rexpr.Type)
                                        return true;
 
                                return Convert.ImplicitConversionExists (ec, lexpr, left) &&
@@ -1746,14 +1791,14 @@ namespace Mono.CSharp {
                        {
                                int result = 0;
                                if (left != null && best_operator.left != null) {
-                                       result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
+                                       result = OverloadResolver.BetterTypeConversion (ec, best_operator.left, left);
                                }
 
                                //
-                               // When second arguments are same as the first one, the result is same
+                               // When second argument is same as the first one, the result is same
                                //
                                if (right != null && (left != right || best_operator.left != best_operator.right)) {
-                                       result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
+                                       result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right, right);
                                }
 
                                if (result == 0 || result > 2)
@@ -1836,7 +1881,49 @@ namespace Mono.CSharp {
                        }
                }
 
-               class PredefinedPointerOperator : PredefinedOperator {
+               class PredefinedEqualityOperator : PredefinedOperator
+               {
+                       MethodSpec equal_method, inequal_method;
+
+                       public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
+                               : base (arg, arg, Operator.EqualityMask, retType)
+                       {
+                       }
+
+                       public override Expression ConvertResult (ResolveContext ec, Binary b)
+                       {
+                               b.type = ReturnType;
+
+                               b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
+                               b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
+
+                               Arguments args = new Arguments (2);
+                               args.Add (new Argument (b.left));
+                               args.Add (new Argument (b.right));
+
+                               MethodSpec method;
+                               if (b.oper == Operator.Equality) {
+                                       if (equal_method == null) {
+                                               equal_method = TypeManager.GetPredefinedMethod (left,
+                                                       new MemberFilter (CSharp.Operator.GetMetadataName (CSharp.Operator.OpType.Equality), 0, MemberKind.Operator, null, ReturnType), b.loc);
+                                       }
+
+                                       method = equal_method;
+                               } else {
+                                       if (inequal_method == null) {
+                                               inequal_method = TypeManager.GetPredefinedMethod (left,
+                                                       new MemberFilter (CSharp.Operator.GetMetadataName (CSharp.Operator.OpType.Inequality), 0, MemberKind.Operator, null, ReturnType), b.loc);
+                                       }
+
+                                       method = inequal_method;
+                               }
+
+                               return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
+                       }
+               }
+
+               class PredefinedPointerOperator : PredefinedOperator
+               {
                        public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
                                : base (ltype, rtype, op_mask)
                        {
@@ -1942,18 +2029,28 @@ namespace Mono.CSharp {
                        RelationalMask  = 1 << 13
                }
 
+               protected enum State
+               {
+                       None = 0,
+                       Compound = 1 << 1,
+                       LeftNullLifted = 1 << 2,
+                       RightNullLifted = 1 << 3
+               }
+
                readonly Operator oper;
                protected Expression left, right;
-               readonly bool is_compound;
+               protected State state;
                Expression enum_conversion;
 
                static PredefinedOperator[] standard_operators;
+               static PredefinedOperator[] equality_operators;
                static PredefinedOperator[] pointer_operators;
                
                public Binary (Operator oper, Expression left, Expression right, bool isCompound, Location loc)
                        : this (oper, left, right, loc)
                {
-                       this.is_compound = isCompound;
+                       if (isCompound)
+                               state |= State.Compound;
                }
 
                public Binary (Operator oper, Expression left, Expression right, Location loc)
@@ -1964,12 +2061,22 @@ namespace Mono.CSharp {
                        this.loc = loc;
                }
 
+               #region Properties
+
+               public bool IsCompound {
+                       get {
+                               return (state & State.Compound) != 0;
+                       }
+               }
+
                public Operator Oper {
                        get {
                                return oper;
                        }
                }
-               
+
+               #endregion
+
                /// <summary>
                ///   Returns a stringified representation of the Operator
                /// </summary>
@@ -2036,7 +2143,7 @@ namespace Mono.CSharp {
                                break;
                        }
 
-                       if (is_compound)
+                       if (IsCompound)
                                return s + "=";
 
                        return s;
@@ -2069,15 +2176,15 @@ namespace Mono.CSharp {
                {
                        switch (oper) {
                        case Operator.Addition:
-                               return is_compound ? "AddAssign" : "Add";
+                               return IsCompound ? "AddAssign" : "Add";
                        case Operator.BitwiseAnd:
-                               return is_compound ? "AndAssign" : "And";
+                               return IsCompound ? "AndAssign" : "And";
                        case Operator.BitwiseOr:
-                               return is_compound ? "OrAssign" : "Or";
+                               return IsCompound ? "OrAssign" : "Or";
                        case Operator.Division:
-                               return is_compound ? "DivideAssign" : "Divide";
+                               return IsCompound ? "DivideAssign" : "Divide";
                        case Operator.ExclusiveOr:
-                               return is_compound ? "ExclusiveOrAssign" : "ExclusiveOr";
+                               return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
                        case Operator.Equality:
                                return "Equal";
                        case Operator.GreaterThan:
@@ -2087,7 +2194,7 @@ namespace Mono.CSharp {
                        case Operator.Inequality:
                                return "NotEqual";
                        case Operator.LeftShift:
-                               return is_compound ? "LeftShiftAssign" : "LeftShift";
+                               return IsCompound ? "LeftShiftAssign" : "LeftShift";
                        case Operator.LessThan:
                                return "LessThan";
                        case Operator.LessThanOrEqual:
@@ -2097,59 +2204,58 @@ namespace Mono.CSharp {
                        case Operator.LogicalOr:
                                return "Or";
                        case Operator.Modulus:
-                               return is_compound ? "ModuloAssign" : "Modulo";
+                               return IsCompound ? "ModuloAssign" : "Modulo";
                        case Operator.Multiply:
-                               return is_compound ? "MultiplyAssign" : "Multiply";
+                               return IsCompound ? "MultiplyAssign" : "Multiply";
                        case Operator.RightShift:
-                               return is_compound ? "RightShiftAssign" : "RightShift";
+                               return IsCompound ? "RightShiftAssign" : "RightShift";
                        case Operator.Subtraction:
-                               return is_compound ? "SubtractAssign" : "Subtract";
+                               return IsCompound ? "SubtractAssign" : "Subtract";
                        default:
                                throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
                        }
                }
 
-               static string GetOperatorMetadataName (Operator op)
+               static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
                {
-                       CSharp.Operator.OpType op_type;
                        switch (op) {
                        case Operator.Addition:
-                               op_type = CSharp.Operator.OpType.Addition; break;
+                               return CSharp.Operator.OpType.Addition;
                        case Operator.BitwiseAnd:
-                               op_type = CSharp.Operator.OpType.BitwiseAnd; break;
+                       case Operator.LogicalAnd:
+                               return CSharp.Operator.OpType.BitwiseAnd;
                        case Operator.BitwiseOr:
-                               op_type = CSharp.Operator.OpType.BitwiseOr; break;
+                       case Operator.LogicalOr:
+                               return CSharp.Operator.OpType.BitwiseOr;
                        case Operator.Division:
-                               op_type = CSharp.Operator.OpType.Division; break;
+                               return CSharp.Operator.OpType.Division;
                        case Operator.Equality:
-                               op_type = CSharp.Operator.OpType.Equality; break;
+                               return CSharp.Operator.OpType.Equality;
                        case Operator.ExclusiveOr:
-                               op_type = CSharp.Operator.OpType.ExclusiveOr; break;
+                               return CSharp.Operator.OpType.ExclusiveOr;
                        case Operator.GreaterThan:
-                               op_type = CSharp.Operator.OpType.GreaterThan; break;
+                               return CSharp.Operator.OpType.GreaterThan;
                        case Operator.GreaterThanOrEqual:
-                               op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
+                               return CSharp.Operator.OpType.GreaterThanOrEqual;
                        case Operator.Inequality:
-                               op_type = CSharp.Operator.OpType.Inequality; break;
+                               return CSharp.Operator.OpType.Inequality;
                        case Operator.LeftShift:
-                               op_type = CSharp.Operator.OpType.LeftShift; break;
+                               return CSharp.Operator.OpType.LeftShift;
                        case Operator.LessThan:
-                               op_type = CSharp.Operator.OpType.LessThan; break;
+                               return CSharp.Operator.OpType.LessThan;
                        case Operator.LessThanOrEqual:
-                               op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
+                               return CSharp.Operator.OpType.LessThanOrEqual;
                        case Operator.Modulus:
-                               op_type = CSharp.Operator.OpType.Modulus; break;
+                               return CSharp.Operator.OpType.Modulus;
                        case Operator.Multiply:
-                               op_type = CSharp.Operator.OpType.Multiply; break;
+                               return CSharp.Operator.OpType.Multiply;
                        case Operator.RightShift:
-                               op_type = CSharp.Operator.OpType.RightShift; break;
+                               return CSharp.Operator.OpType.RightShift;
                        case Operator.Subtraction:
-                               op_type = CSharp.Operator.OpType.Subtraction; break;
+                               return CSharp.Operator.OpType.Subtraction;
                        default:
                                throw new InternalErrorException (op.ToString ());
                        }
-
-                       return CSharp.Operator.GetMetadataName (op_type);
                }
 
                public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l)
@@ -2300,7 +2406,7 @@ namespace Mono.CSharp {
 
                public static void Reset ()
                {
-                       pointer_operators = standard_operators = null;
+                       equality_operators = pointer_operators = standard_operators = null;
                }
 
                Expression ResolveOperator (ResolveContext ec)
@@ -2329,19 +2435,17 @@ namespace Mono.CSharp {
                                        return ResolveOperatorPointer (ec, l, r);
 
                                // Enums
-                               bool lenum = TypeManager.IsEnumType (l);
-                               bool renum = TypeManager.IsEnumType (r);
+                               bool lenum = l.IsEnum;
+                               bool renum = r.IsEnum;
                                if (lenum || renum) {
                                        expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
 
-                                       // TODO: Can this be ambiguous
                                        if (expr != null)
                                                return expr;
                                }
 
                                // Delegates
-                               if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
-                                        (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
+                               if ((oper == Operator.Addition || oper == Operator.Subtraction) && (l.IsDelegate || r.IsDelegate)) {
                                                
                                        expr = ResolveOperatorDelegate (ec, l, r);
 
@@ -2357,7 +2461,7 @@ namespace Mono.CSharp {
 
                                // Predefined reference types equality
                                if ((oper & Operator.EqualityMask) != 0) {
-                                       expr = ResolveOperatorEqualityRerefence (ec, l, r);
+                                       expr = ResolveOperatorEquality (ec, l, r);
                                        if (expr != null)
                                                return expr;
                                }
@@ -2489,8 +2593,6 @@ namespace Mono.CSharp {
                        temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
                        temp.Add (new PredefinedOperator (TypeManager.decimal_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));
@@ -2504,6 +2606,14 @@ namespace Mono.CSharp {
                        temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
 
                        standard_operators = temp.ToArray ();
+
+                       var equality = new List<PredefinedOperator> () {
+                               new PredefinedEqualityOperator (TypeManager.string_type, bool_type),
+                               new PredefinedEqualityOperator (TypeManager.delegate_type, bool_type),
+                               new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type)
+                       };
+
+                       equality_operators = equality.ToArray ();
                }
 
                //
@@ -2751,21 +2861,18 @@ namespace Mono.CSharp {
                //
                // D operator + (D x, D y)
                // D operator - (D x, D y)
-               // bool operator == (D x, D y)
-               // bool operator != (D x, D y)
                //
                Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
                {
-                       bool is_equality = (oper & Operator.EqualityMask) != 0;
-                       if (!TypeManager.IsEqual (l, r) && !TypeSpecComparer.Variant.IsEqual (r, l)) {
+                       if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
                                Expression tmp;
-                               if (right.eclass == ExprClass.MethodGroup || (r == InternalType.AnonymousMethod && !is_equality)) {
+                               if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.Null) {
                                        tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
                                        if (tmp == null)
                                                return null;
                                        right = tmp;
                                        r = right.Type;
-                               } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod && !is_equality)) {
+                               } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod)) {
                                        tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
                                        if (tmp == null)
                                                return null;
@@ -2776,12 +2883,6 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       //
-                       // Resolve delegate equality as a user operator
-                       //
-                       if (is_equality)
-                               return ResolveUserOperator (ec, l, r);
-
                        MethodSpec method;
                        Arguments args = new Arguments (2);
                        args.Add (new Argument (left));
@@ -2794,22 +2895,20 @@ namespace Mono.CSharp {
                                }
 
                                method = TypeManager.delegate_combine_delegate_delegate;
-                       } else {
+                       } else if (oper == Operator.Subtraction) {
                                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;
-                       }
-
-                       if (method == null)
+                       } else {
                                return new EmptyExpression (TypeManager.decimal_type);
+                       }
 
-                       MethodGroupExpr mg = new MethodGroupExpr (method, TypeManager.delegate_type, loc);
-                       mg = mg.OverloadResolve (ec, ref args, false, loc);
-
-                       return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
+                       MethodGroupExpr mg = MethodGroupExpr.CreatePredefined (method, TypeManager.delegate_type, loc);
+                       Expression expr = new UserOperatorCall (mg.BestCandidate, args, CreateExpressionTree, loc);
+                       return new ClassCast (expr, l);
                }
 
                //
@@ -2831,89 +2930,134 @@ namespace Mono.CSharp {
                        //
                        // U operator - (E e, E f)
                        // E operator - (E e, U x)
+                       // E operator - (U x, E e)      // LAMESPEC: Not covered by the specification
                        //
-                       // E operator + (U x, E e)
                        // E operator + (E e, U x)
+                       // E operator + (U x, E e)
                        //
-                       if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
-                               (oper == Operator.Subtraction && lenum) ||
-                               (oper == Operator.Addition && (lenum != renum || type != null))))       // type != null for lifted null
-                               return null;
-
                        Expression ltemp = left;
                        Expression rtemp = right;
                        TypeSpec underlying_type;
+                       TypeSpec underlying_type_result;
+                       TypeSpec res_type;
                        Expression expr;
                        
+                       //
+                       // LAMESPEC: There is never ambiguous conversion between enum operators
+                       // the one which contains more enum parameters always wins even if there
+                       // is an implicit conversion involved
+                       //
                        if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
                                if (renum) {
+                                       underlying_type = EnumSpec.GetUnderlyingType (rtype);
                                        expr = Convert.ImplicitConversion (ec, left, rtype, loc);
-                                       if (expr != null) {
+                                       if (expr == null)
+                                               return null;
+
+                                       left = expr;
+                                       ltype = expr.Type;
+                               } else if (lenum) {
+                                       underlying_type = EnumSpec.GetUnderlyingType (ltype);
+                                       expr = Convert.ImplicitConversion (ec, right, ltype, loc);
+                                       if (expr == null)
+                                               return null;
+
+                                       right = expr;
+                                       rtype = expr.Type;
+                               } else {
+                                       return null;
+                               }
+
+                               if ((oper & Operator.BitwiseMask) != 0) {
+                                       res_type = ltype;
+                                       underlying_type_result = underlying_type;
+                               } else {
+                                       res_type = null;
+                                       underlying_type_result = null;
+                               }
+                       } else if (oper == Operator.Subtraction) {
+                               if (renum) {
+                                       underlying_type = EnumSpec.GetUnderlyingType (rtype);
+                                       if (ltype != rtype) {
+                                               expr = Convert.ImplicitConversion (ec, left, rtype, left.Location);
+                                               if (expr == null) {
+                                                       expr = Convert.ImplicitConversion (ec, left, underlying_type, left.Location);
+                                                       if (expr == null)
+                                                               return null;
+
+                                                       res_type = rtype;
+                                               } else {
+                                                       res_type = underlying_type;
+                                               }
+
                                                left = expr;
-                                               ltype = expr.Type;
+                                       } else {
+                                               res_type = underlying_type;
                                        }
+
+                                       underlying_type_result = underlying_type;
                                } else if (lenum) {
-                                       expr = Convert.ImplicitConversion (ec, right, ltype, loc);
-                                       if (expr != null) {
+                                       underlying_type = EnumSpec.GetUnderlyingType (ltype);
+                                       expr = Convert.ImplicitConversion (ec, right, ltype, right.Location);
+                                       if (expr == null) {
+                                               expr = Convert.ImplicitConversion (ec, right, underlying_type, right.Location);
+                                               if (expr == null)
+                                                       return null;
+
+                                               res_type = ltype;
+                                       } else {
+                                               res_type = underlying_type;
+                                       }
+
+                                       right = expr;
+                                       underlying_type_result = underlying_type;
+                               } else {
+                                       return null;
+                               }
+                       } else if (oper == Operator.Addition) {
+                               if (lenum) {
+                                       underlying_type = EnumSpec.GetUnderlyingType (ltype);
+                                       res_type = ltype;
+
+                                       if (rtype != underlying_type && (state & (State.RightNullLifted | State.LeftNullLifted)) == 0) {
+                                               expr = Convert.ImplicitConversion (ec, right, underlying_type, right.Location);
+                                               if (expr == null)
+                                                       return null;
+
                                                right = expr;
-                                               rtype = expr.Type;
+                                       }
+                               } else {
+                                       underlying_type = EnumSpec.GetUnderlyingType (rtype);
+                                       res_type = rtype;
+                                       if (ltype != underlying_type) {
+                                               expr = Convert.ImplicitConversion (ec, left, underlying_type, left.Location);
+                                               if (expr == null)
+                                                       return null;
+
+                                               left = expr;
                                        }
                                }
-                       }                       
 
-                       if (TypeManager.IsEqual (ltype, rtype)) {
-                               underlying_type = EnumSpec.GetUnderlyingType (ltype);
+                               underlying_type_result = underlying_type;
+                       } else {
+                               return null;
+                       }
 
+                       // Unwrap the constant correctly, so DoBinaryOperatorPromotion can do the magic
+                       // with constants and expressions
+                       if (left.Type != underlying_type) {
                                if (left is Constant)
                                        left = ((Constant) left).ConvertExplicitly (false, underlying_type).Resolve (ec);
                                else
                                        left = EmptyCast.Create (left, underlying_type);
+                       }
 
+                       if (right.Type != underlying_type) {
                                if (right is Constant)
                                        right = ((Constant) right).ConvertExplicitly (false, underlying_type).Resolve (ec);
                                else
                                        right = EmptyCast.Create (right, underlying_type);
-                       } else if (lenum) {
-                               underlying_type = EnumSpec.GetUnderlyingType (ltype);
-
-                               if (oper != Operator.Subtraction && oper != Operator.Addition) {
-                                       Constant c = right as Constant;
-                                       if (c == null || !c.IsDefaultValue)
-                                               return null;
-                               } else {
-                                       if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
-                                               return null;
-
-                                       right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
-                               }
-
-                               if (left is Constant)
-                                       left = ((Constant) left).ConvertExplicitly (false, underlying_type).Resolve (ec);
-                               else
-                                       left = EmptyCast.Create (left, underlying_type);
-
-                       } else if (renum) {
-                               underlying_type = EnumSpec.GetUnderlyingType (rtype);
-
-                               if (oper != Operator.Addition) {
-                                       Constant c = left as Constant;
-                                       if (c == null || !c.IsDefaultValue)
-                                               return null;
-                               } else {
-                                       if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
-                                               return null;
-
-                                       left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
-                               }
-
-                               if (right is Constant)
-                                       right = ((Constant) right).ConvertExplicitly (false, underlying_type).Resolve (ec);
-                               else
-                                       right = EmptyCast.Create (right, underlying_type);
-
-                       } else {
-                               return null;
-                       }
+                       }
 
                        //
                        // C# specification uses explicit cast syntax which means binary promotion
@@ -2925,22 +3069,15 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       TypeSpec res_type = null;
-                       if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
-                               TypeSpec promoted_type = lenum ? left.Type : right.Type;
-                               enum_conversion = Convert.ExplicitNumericConversion (
-                                       new EmptyExpression (promoted_type), underlying_type);
-
-                               if (oper == Operator.Subtraction && renum && lenum)
-                                       res_type = underlying_type;
-                               else if (oper == Operator.Addition && renum)
-                                       res_type = rtype;
-                               else
-                                       res_type = ltype;
+                       if (underlying_type_result != null && left.Type != underlying_type_result) {
+                               enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (left.Type), underlying_type_result);
                        }
-                       
+
                        expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
-                       if (!is_compound || expr == null)
+                       if (expr == null)
+                               return null;
+
+                       if (!IsCompound)
                                return expr;
 
                        //
@@ -2972,123 +3109,132 @@ namespace Mono.CSharp {
                //
                // 7.9.6 Reference type equality operators
                //
-               Binary ResolveOperatorEqualityRerefence (ResolveContext ec, TypeSpec l, TypeSpec r)
+               Expression ResolveOperatorEquality (ResolveContext ec, TypeSpec l, TypeSpec r)
                {
+                       Expression result;
+                       type = TypeManager.bool_type;
+
+                       //
+                       // 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 constraint
                        //
-                       // operator != (object a, object b)
-                       // operator == (object a, object b)
+                       // LAMESPEC: Very confusing details in the specification, basically any
+                       // reference like type-parameter is allowed
                        //
+                       var tparam_l = l as TypeParameterSpec;
+                       var tparam_r = r as TypeParameterSpec;
+                       if (tparam_l != null) {
+                               if (right is NullLiteral && !tparam_l.HasSpecialStruct) {
+                                       left = new BoxedCast (left, TypeManager.object_type);
+                                       return this;
+                               }
 
-                       // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
-
-                       if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
-                               return null;
-
-                       type = TypeManager.bool_type;
-
-                       var lgen = l as TypeParameterSpec;
+                               if (!tparam_l.IsReferenceType)
+                                       return null;
 
-                       if (l == r) {
-                               if (l is InternalType)
+                               l = tparam_l.GetEffectiveBase ();
+                               left = new BoxedCast (left, l);
+                       } else if (left is NullLiteral && tparam_r == null) {
+                               if (!TypeManager.IsReferenceType (r) || r.Kind == MemberKind.InternalCompilerType)
                                        return null;
 
-                               if (lgen != null) {
-                                       //
-                                       // Only allow to compare same reference type parameter
-                                       //
-                                       if (TypeManager.IsReferenceType (l)) {
-                                               left = new BoxedCast (left, TypeManager.object_type);
-                                               right = new BoxedCast (right, TypeManager.object_type);
-                                               return this;
-                                       }
+                               return this;
+                       }
 
-                                       return null;
+                       if (tparam_r != null) {
+                               if (left is NullLiteral && !tparam_r.HasSpecialStruct) {
+                                       right = new BoxedCast (right, TypeManager.object_type);
+                                       return this;
                                }
 
-                               if (TypeManager.IsValueType (l))
+                               if (!tparam_r.IsReferenceType)
+                                       return null;
+
+                               r = tparam_r.GetEffectiveBase ();
+                               right = new BoxedCast (right, r);
+                       } else if (right is NullLiteral) {
+                               if (!TypeManager.IsReferenceType (l) || l.Kind == MemberKind.InternalCompilerType)
                                        return null;
 
                                return this;
                        }
 
-                       var rgen = r as TypeParameterSpec;
-
                        //
-                       // 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
+                       // LAMESPEC: method groups can be compared when they convert to other side delegate
                        //
-                       if (left is NullLiteral || right is NullLiteral) {
-                               if (lgen != null) {
-                                       if (lgen.HasSpecialStruct)
+                       if (l.IsDelegate) {
+                               if (right.eclass == ExprClass.MethodGroup) {
+                                       result = Convert.ImplicitConversion (ec, right, l, loc);
+                                       if (result == null)
                                                return null;
 
-                                       left = new BoxedCast (left, TypeManager.object_type);
-                                       return this;
+                                       right = result;
+                                       r = l;
+                               } else if (r.IsDelegate && l != r) {
+                                       return null;
                                }
+                       } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
+                               result = Convert.ImplicitConversionRequired (ec, left, r, loc);
+                               if (result == null)
+                                       return null;
 
-                               if (rgen != null) {
-                                       if (rgen.HasSpecialStruct)
-                                               return null;
-
-                                       right = new BoxedCast (right, TypeManager.object_type);
-                                       return this;
-                               }
+                               left = result;
+                               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.
+                       // bool operator != (string a, string b)
+                       // bool operator == (string a, string b)
                        //
-                       if (lgen != null) {
-                               if (!TypeManager.IsReferenceType (l))
-                                       return null;
-
-                               l = TypeManager.object_type;
-                               left = new BoxedCast (left, l);
-                       } else if (l.IsInterface) {
-                               l = TypeManager.object_type;
-                       } else if (TypeManager.IsStruct (l)) {
-                               return null;
-                       }
-
-                       if (rgen != null) {
-                               if (!TypeManager.IsReferenceType (r))
-                                       return null;
-
-                               r = TypeManager.object_type;
-                               right = new BoxedCast (right, r);
-                       } else if (r.IsInterface) {
-                               r = TypeManager.object_type;
-                       } else if (TypeManager.IsStruct (r)) {
-                               return null;
+                       // bool operator != (Delegate a, Delegate b)
+                       // bool operator == (Delegate a, Delegate b)
+                       //
+                       // bool operator != (bool a, bool b)
+                       // bool operator == (bool a, bool b)
+                       //
+                       // LAMESPEC: Reference equality comparison can apply to value types when
+                       // they implement an implicit conversion to any of types above.
+                       //
+                       if (r != TypeManager.object_type && l != TypeManager.object_type) {
+                               result = ResolveOperatorPredefined (ec, equality_operators, false, null);
+                               if (result != null)
+                                       return result;
                        }
 
-
-                       const string ref_comparison = "Possible unintended reference comparison. " +
-                               "Consider casting the {0} side of the expression to `string' to compare the values";
-
                        //
-                       // A standard implicit conversion exists from the type of either
-                       // operand to the type of the other operand
+                       // bool operator != (object a, object b)
+                       // bool operator == (object a, object b)
+                       //
+                       // An explicit reference 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)
-                                       ec.Report.Warning (253, 2, loc, ref_comparison, "right");
 
-                               return this;
+                       // Optimize common path
+                       if (l == r) {
+                               return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
                        }
 
-                       if (Convert.ImplicitReferenceConversionExists (right, l)) {
-                               if (r == TypeManager.string_type)
-                                       ec.Report.Warning (252, 2, loc, ref_comparison, "left");
+                       if (!Convert.ExplicitReferenceConversionExists (l, r) &&
+                               !Convert.ExplicitReferenceConversionExists (r, l))
+                               return null;
 
-                               return this;
-                       }
+                       // Reject allowed explicit conversions like int->object
+                       if (!TypeManager.IsReferenceType (l) || !TypeManager.IsReferenceType (r))
+                               return null;
 
-                       return null;
+                       if (l == TypeManager.string_type || l == TypeManager.delegate_type || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
+                               ec.Report.Warning (253, 2, loc,
+                                       "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
+                                       l.GetSignatureForError ());
+
+                       if (r == TypeManager.string_type || r == TypeManager.delegate_type || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
+                               ec.Report.Warning (252, 2, loc,
+                                       "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
+                                       r.GetSignatureForError ());
+
+                       return this;
                }
 
 
@@ -3180,7 +3326,7 @@ namespace Mono.CSharp {
                        if (oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) {
                                Constant rc = right as Constant;
                                Constant lc = left as Constant;
-                               if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
+                               if (((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) && !(this is Nullable.LiftedBinaryOperator)) {
                                        //
                                        // The result is a constant with side-effect
                                        //
@@ -3207,21 +3353,12 @@ namespace Mono.CSharp {
                //
                protected virtual Expression ResolveUserOperator (ResolveContext ec, TypeSpec l, TypeSpec 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;
-
-                       string op = GetOperatorMetadataName (user_oper);
+                       var op = ConvertBinaryToUserOperator (oper);
+                       IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
+                       IList<MemberSpec> right_operators = null;
 
-                       MethodGroupExpr left_operators = MethodLookup (ec.Compiler, ec.CurrentType, l, MemberKind.Operator, op, 0, loc);
-                       MethodGroupExpr right_operators = null;
-
-                       if (!TypeManager.IsEqual (r, l)) {
-                               right_operators = MethodLookup (ec.Compiler, ec.CurrentType, r, MemberKind.Operator, op, 0, loc);
+                       if (l != r) {
+                               right_operators = MemberCache.GetUserOperator (r, op, false);
                                if (right_operators == null && left_operators == null)
                                        return null;
                        } else if (left_operators == null) {
@@ -3234,63 +3371,31 @@ namespace Mono.CSharp {
                        Argument rarg = new Argument (right);
                        args.Add (rarg);
 
-                       MethodGroupExpr union;
-
                        //
                        // User-defined operator implementations always take precedence
                        // over predefined operator implementations
                        //
                        if (left_operators != null && right_operators != null) {
-                               if (IsPredefinedUserOperator (l, user_oper)) {
-                                       union = right_operators.OverloadResolve (ec, ref args, true, loc);
-                                       if (union == null)
-                                               union = left_operators;
-                               } else if (IsPredefinedUserOperator (r, user_oper)) {
-                                       union = left_operators.OverloadResolve (ec, ref args, true, loc);
-                                       if (union == null)
-                                               union = right_operators;
-                               } else {
-                                       union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
-                               }
-                       } else if (left_operators != null) {
-                               union = left_operators;
-                       } else {
-                               union = right_operators;
+                               left_operators = CombineUserOperators (left_operators, right_operators);
+                       } else if (right_operators != null) {
+                               left_operators = right_operators;
                        }
 
-                       union = union.OverloadResolve (ec, ref args, true, loc);
-                       if (union == null)
+                       var res = new OverloadResolver (left_operators, OverloadResolver.Restrictions.ProbingOnly | 
+                               OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded, loc);
+
+                       var oper_method = res.ResolveOperator (ec, ref args);
+                       if (oper_method == null)
                                return null;
 
                        Expression oper_expr;
 
                        // TODO: CreateExpressionTree is allocated every time
-                       if (user_oper != oper) {
-                               oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
+                       if ((oper & Operator.LogicalMask) != 0) {
+                               oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
                                        oper == Operator.LogicalAnd, loc).Resolve (ec);
                        } else {
-                               oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
-
-                               //
-                               // This is used to check if a test 'x == null' can be optimized to a reference equals,
-                               // and not invoke user operator
-                               //
-                               if ((oper & Operator.EqualityMask) != 0) {
-                                       if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
-                                               (right is NullLiteral && IsBuildInEqualityOperator (l))) {
-                                               type = TypeManager.bool_type;
-                                               if (left is NullLiteral || right is NullLiteral)
-                                                       oper_expr = ReducedExpression.Create (this, oper_expr);
-                                       } else if (l != r) {
-                                               var mi = union.BestCandidate;
-                                               
-                                               //
-                                               // Two System.Delegate(s) are never equal
-                                               //
-                                               if (mi.DeclaringType == TypeManager.multicast_delegate_type)
-                                                       return null;
-                                       }
-                               }
+                               oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
                        }
 
                        left = larg.Expr;
@@ -3298,6 +3403,30 @@ namespace Mono.CSharp {
                        return oper_expr;
                }
 
+               //
+               // Merge two sets of user operators into one, they are mostly distinguish
+               // expect when they share base type and it contains an operator
+               //
+               static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
+               {
+                       var combined = new List<MemberSpec> (left.Count + right.Count);
+                       combined.AddRange (left);
+                       foreach (var r in right) {
+                               bool same = false;
+                               foreach (var l in left) {
+                                       if (l.DeclaringType == r.DeclaringType) {
+                                               same = true;
+                                               break;
+                                       }
+                               }
+
+                               if (!same)
+                                       combined.Add (r);
+                       }
+
+                       return combined;
+               }
+
                public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
                {
                        return null;
@@ -3368,20 +3497,6 @@ namespace Mono.CSharp {
                                type == TypeManager.uint32_type && value >= 0x100000000;
                }
 
-               static bool IsBuildInEqualityOperator (TypeSpec t)
-               {
-                       return t == TypeManager.object_type || t == TypeManager.string_type ||
-                               t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
-               }
-
-               static bool IsPredefinedUserOperator (TypeSpec t, Operator op)
-               {
-                       //
-                       // Some predefined types have user operators
-                       //
-                       return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
-               }
-
                private static bool IsTypeIntegral (TypeSpec type)
                {
                        return type == TypeManager.uint64_type ||
@@ -3667,7 +3782,7 @@ namespace Mono.CSharp {
                        return CreateExpressionTree (ec, null);
                }
 
-               Expression CreateExpressionTree (ResolveContext ec, MethodGroupExpr method)             
+               Expression CreateExpressionTree (ResolveContext ec, Expression method)          
                {
                        string method_name;
                        bool lift_arg = false;
@@ -3753,8 +3868,8 @@ namespace Mono.CSharp {
                        if (method != null) {
                                if (lift_arg)
                                        args.Add (new Argument (new BoolConstant (false, loc)));
-                               
-                               args.Add (new Argument (method.CreateExpressionTree (ec)));
+
+                               args.Add (new Argument (method));
                        }
                        
                        return CreateExpressionFactoryCall (ec, method_name, args);
@@ -3767,6 +3882,7 @@ namespace Mono.CSharp {
        //
        public class StringConcat : Expression {
                Arguments arguments;
+               static IList<MemberSpec> concat_members;
                
                public StringConcat (Expression left, Expression right, Location loc)
                {
@@ -3808,21 +3924,22 @@ namespace Mono.CSharp {
                        concat_args.Add (arguments [pos]);
                        add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
 
-                       MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
-                       if (method == null)
+                       var methods = CreateConcatMethodCandidates ();
+                       if (methods == null)
                                return null;
 
-                       method = method.OverloadResolve (ec, ref concat_args, false, loc);
+                       var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
+                       var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
                        if (method == null)
                                return null;
 
-                       add_args.Add (new Argument (method.CreateExpressionTree (ec)));
+                       add_args.Add (new Argument (new TypeOfMethod (method, loc)));
 
                        Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
                        if (++pos == arguments.Count)
                                return expr;
 
-                       left = new Argument (new EmptyExpression (method.BestCandidate.ReturnType));
+                       left = new Argument (new EmptyExpression (method.ReturnType));
                        return CreateExpressionAddCall (ec, left, expr, pos);
                }
 
@@ -3861,17 +3978,22 @@ namespace Mono.CSharp {
                        arguments.Add (new Argument (operand));
                }
 
-               Expression CreateConcatMemberExpression ()
+               IList<MemberSpec> CreateConcatMethodCandidates ()
                {
-                       return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
+                       if (concat_members == null) {
+                               concat_members = MemberCache.FindMembers (type, "Concat", true);
+                       }
+
+                       return concat_members;
                }
 
                public override void Emit (EmitContext ec)
                {
-                       Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
-                       concat = concat.Resolve (new ResolveContext (ec.MemberContext));
-                       if (concat != null)
-                               concat.Emit (ec);
+                       var members = CreateConcatMethodCandidates ();
+                       var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
+                       var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
+                       if (method != null)
+                               Invocation.EmitCall (ec, null, method, arguments, loc);
                }
 
                public override SLE.Expression MakeExpression (BuilderContext ctx)
@@ -3882,6 +4004,11 @@ namespace Mono.CSharp {
                        var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
                        return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
                }
+
+               public static void Reset ()
+               {
+                       concat_members = null;
+               }
        }
 
        //
@@ -3889,11 +4016,10 @@ namespace Mono.CSharp {
        //
        public class ConditionalLogicalOperator : UserOperatorCall {
                readonly bool is_and;
-               Expression oper;
+               Expression oper_expr;
 
-               public ConditionalLogicalOperator (MethodGroupExpr oper_method, Arguments arguments,
-                       ExpressionTreeExpression expr_tree, bool is_and, Location loc)
-                       : base (oper_method, arguments, expr_tree, loc)
+               public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
+                       : base (oper, arguments, expr_tree, loc)
                {
                        this.is_and = is_and;
                        eclass = ExprClass.Unresolved;
@@ -3901,13 +4027,11 @@ namespace Mono.CSharp {
                
                protected override Expression DoResolve (ResolveContext ec)
                {
-                       var method = mg.BestCandidate;
-                       type = method.ReturnType;
-                       AParametersCollection pd = method.Parameters;
-                       if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
+                       AParametersCollection pd = oper.Parameters;
+                       if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
                                ec.Report.Error (217, loc,
                                        "A user-defined operator `{0}' must have parameters and return values of the same type in order to be applicable as a short circuit operator",
-                                       TypeManager.CSharpSignature (method));
+                                       oper.GetSignatureForError ());
                                return null;
                        }
 
@@ -3917,11 +4041,11 @@ namespace Mono.CSharp {
                        if (op_true == null || op_false == null) {
                                ec.Report.Error (218, loc,
                                        "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
-                                       TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
+                                       TypeManager.CSharpName (type), oper.GetSignatureForError ());
                                return null;
                        }
 
-                       oper = is_and ? op_false : op_true;
+                       oper_expr = is_and ? op_false : op_true;
                        eclass = ExprClass.Value;
                        return this;
                }
@@ -3937,7 +4061,7 @@ namespace Mono.CSharp {
                        ec.Emit (OpCodes.Dup);
                        arguments.RemoveAt (0);
 
-                       oper.EmitBranchable (ec, end_target, true);
+                       oper_expr.EmitBranchable (ec, end_target, true);
                        base.Emit (ec);
                        ec.MarkLabel (end_target);
                }
@@ -3970,7 +4094,7 @@ namespace Mono.CSharp {
                        eclass = ExprClass.Variable;
                        
                        if (left.Type == TypeManager.void_ptr_type) {
-                               ec.Report.Error (242, loc, "The operation in question is undefined on void pointers");
+                               Error_VoidPointerOperation (ec);
                                return null;
                        }
                        
@@ -4149,12 +4273,12 @@ namespace Mono.CSharp {
        public class Conditional : Expression {
                Expression expr, true_expr, false_expr;
 
-               public Conditional (BooleanExpression expr, Expression true_expr, Expression false_expr)
+               public Conditional (BooleanExpression expr, Expression true_expr, Expression false_expr, Location loc)
                {
                        this.expr = expr;
                        this.true_expr = true_expr;
                        this.false_expr = false_expr;
-                       this.loc = expr.Location;
+                       this.loc = loc;
                }
 
                public Expression Expr {
@@ -4202,19 +4326,23 @@ namespace Mono.CSharp {
                        // First, if an implicit conversion exists from true_expr
                        // to false_expr, then the result type is of type false_expr.Type
                        //
-                       if (!TypeManager.IsEqual (true_type, false_type)) {
+                       if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
                                Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
                                if (conv != null) {
                                        //
                                        // Check if both can convert implicitly to each other's type
                                        //
-                                       if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
-                                               ec.Report.Error (172, true_expr.Location,
-                                                       "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
-                                                       TypeManager.CSharpName (true_type), TypeManager.CSharpName (false_type));
-                                               return null;
+                                       if (true_type != InternalType.Dynamic) {
+                                               type = false_type;
+
+                                               if (false_type != InternalType.Dynamic && Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
+                                                       ec.Report.Error (172, true_expr.Location,
+                                                               "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
+                                                               TypeManager.CSharpName (true_type), TypeManager.CSharpName (false_type));
+                                                       return null;
+                                               }
                                        }
-                                       type = false_type;
+
                                        true_expr = conv;
                                } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
                                        false_expr = conv;
@@ -4383,8 +4511,11 @@ namespace Mono.CSharp {
                        New n_source = source as New;
                        if (n_source != null) {
                                if (!n_source.Emit (ec, this)) {
-                                       if (leave_copy)
+                                       if (leave_copy) {
                                                EmitLoad (ec);
+                                               if (IsRef)
+                                                       ec.EmitLoadFromPtr (type);
+                                       }
                                        return;
                                }
                        } else {
@@ -4418,34 +4549,19 @@ namespace Mono.CSharp {
                }
        }
 
-       /// <summary>
-       ///   Local variables
-       /// </summary>
-       public class LocalVariableReference : VariableReference {
-               readonly string name;
-               public Block Block;
-               public LocalInfo local_info;
-               bool is_readonly;
+       //
+       // Resolved reference to a local variable
+       //
+       public class LocalVariableReference : VariableReference
+       {
+               public LocalVariable local_info;
 
-               public LocalVariableReference (Block block, string name, Location l)
+               public LocalVariableReference (LocalVariable li, Location l)
                {
-                       Block = block;
-                       this.name = name;
+                       this.local_info = li;
                        loc = l;
                }
 
-               //
-               // Setting `is_readonly' to false will allow you to create a writable
-               // reference to a read-only variable.  This is used by foreach and using.
-               //
-               public LocalVariableReference (Block block, string name, Location l,
-                                              LocalInfo local_info, bool is_readonly)
-                       : this (block, name, l)
-               {
-                       this.local_info = local_info;
-                       this.is_readonly = is_readonly;
-               }
-
                public override VariableInfo VariableInfo {
                        get { return local_info.VariableInfo; }
                }
@@ -4466,12 +4582,8 @@ namespace Mono.CSharp {
                        get { return false; }
                }
 
-               public bool IsReadOnly {
-                       get { return is_readonly; }
-               }
-
                public override string Name {
-                       get { return name; }
+                       get { return local_info.Name; }
                }
 
                public bool VerifyAssigned (ResolveContext ec)
@@ -4480,15 +4592,6 @@ namespace Mono.CSharp {
                        return variable_info == null || variable_info.IsAssigned (ec, loc);
                }
 
-               void ResolveLocalInfo ()
-               {
-                       if (local_info == null) {
-                               local_info = Block.GetLocalInfo (Name);
-                               type = local_info.VariableType;
-                               is_readonly = local_info.ReadOnly;
-                       }
-               }
-
                public override void SetHasAddressTaken ()
                {
                        local_info.AddressTaken = true;
@@ -4507,10 +4610,6 @@ namespace Mono.CSharp {
 
                Expression DoResolveBase (ResolveContext ec)
                {
-                       Expression e = Block.GetConstantExpression (Name);
-                       if (e != null)
-                               return e.Resolve (ec);
-
                        VerifyAssigned (ec);
 
                        //
@@ -4528,43 +4627,24 @@ namespace Mono.CSharp {
                        }
 
                        eclass = ExprClass.Variable;
-                       type = local_info.VariableType;
+                       type = local_info.Type;
                        return this;
                }
 
                protected override Expression DoResolve (ResolveContext ec)
                {
-                       ResolveLocalInfo ();
-                       local_info.Used = true;
+                       local_info.SetIsUsed ();
 
-                       if (type == null && local_info.Type is VarExpr) {
-                           local_info.VariableType = TypeManager.object_type;
-                               Error_VariableIsUsedBeforeItIsDeclared (ec.Report, Name);
-                           return null;
-                       }
-                       
                        return DoResolveBase (ec);
                }
 
                public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
                {
-                       ResolveLocalInfo ();
-
                        // is out param
                        if (right_side == EmptyExpression.OutAccess.Instance)
-                               local_info.Used = true;
+                               local_info.SetIsUsed ();
 
-                       // Infer implicitly typed local variable
-                       if (type == null) {
-                               VarExpr ve = local_info.Type as VarExpr;
-                               if (ve != null) {
-                                       if (!ve.InferType (ec, right_side))
-                                               return null;
-                                       type = local_info.VariableType = ve.Type;
-                               }
-                       }
-                                               
-                       if (is_readonly) {
+                       if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
                                int code;
                                string msg;
                                if (right_side == EmptyExpression.OutAccess.Instance) {
@@ -4588,7 +4668,7 @@ namespace Mono.CSharp {
 
                public override int GetHashCode ()
                {
-                       return Name.GetHashCode ();
+                       return local_info.GetHashCode ();
                }
 
                public override bool Equals (object obj)
@@ -4597,7 +4677,7 @@ namespace Mono.CSharp {
                        if (lvr == null)
                                return false;
 
-                       return Name == lvr.Name && Block == lvr.Block;
+                       return local_info == lvr.local_info;
                }
 
                protected override ILocalVariable Variable {
@@ -4611,11 +4691,7 @@ namespace Mono.CSharp {
 
                protected override void CloneTo (CloneContext clonectx, Expression t)
                {
-                       LocalVariableReference target = (LocalVariableReference) t;
-                       
-                       target.Block = clonectx.LookupBlock (Block);
-                       if (local_info != null)
-                               target.local_info = clonectx.LookupVariable (local_info);
+                       // Nothing
                }
        }
 
@@ -4623,15 +4699,18 @@ namespace Mono.CSharp {
        ///   This represents a reference to a parameter in the intermediate
        ///   representation.
        /// </summary>
-       public class ParameterReference : VariableReference {
-               readonly ToplevelParameterInfo pi;
+       public class ParameterReference : VariableReference
+       {
+               protected ParametersBlock.ParameterInfo pi;
 
-               public ParameterReference (ToplevelParameterInfo pi, Location loc)
+               public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
                {
                        this.pi = pi;
                        this.loc = loc;
                }
 
+               #region Properties
+
                public override bool IsRef {
                        get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
                }
@@ -4669,6 +4748,8 @@ namespace Mono.CSharp {
                        get { return Parameter; }
                }
 
+               #endregion
+
                public bool IsAssigned (ResolveContext ec, Location loc)
                {
                        // HACK: Variables are not captured in probing mode
@@ -4698,42 +4779,24 @@ namespace Mono.CSharp {
                        type = pi.ParameterType;
                        eclass = ExprClass.Variable;
 
-                       AnonymousExpression am = ec.CurrentAnonymousMethod;
-                       if (am == null)
-                               return true;
-
-                       Block b = ec.CurrentBlock;
-                       while (b != null) {
-                               b = b.Toplevel;
-                               IParameterData[] p = b.Toplevel.Parameters.FixedParameters;
-                               for (int i = 0; i < p.Length; ++i) {
-                                       if (p [i] != Parameter)
-                                               continue;
-
-                                       //
-                                       // Don't capture local parameters
-                                       //
-                                       if (b == ec.CurrentBlock.Toplevel && !am.IsIterator)
-                                               return true;
-
-                                       if (IsRef) {
-                                               ec.Report.Error (1628, loc,
-                                                       "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
-                                                       Name, am.ContainerType);
-                                       }
-
-                                       if (pi.Parameter.HasAddressTaken)
-                                               AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
-
-                                       if (ec.IsVariableCapturingRequired && !b.Toplevel.IsExpressionTree) {
-                                               AnonymousMethodStorey storey = pi.Block.CreateAnonymousMethodStorey (ec);
-                                               storey.CaptureParameter (ec, this);
-                                       }
+                       //
+                       // If we are referencing a parameter from the external block
+                       // flag it for capturing
+                       //
+                       if (ec.MustCaptureVariable (pi)) {
+                               if (Parameter.HasAddressTaken)
+                                       AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
 
-                                       return true;
+                               if (IsRef) {
+                                       ec.Report.Error (1628, loc,
+                                               "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
+                                               Name, ec.CurrentAnonymousMethod.ContainerType);
                                }
 
-                               b = b.Parent;
+                               if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
+                                       AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
+                                       storey.CaptureParameter (ec, this);
+                               }
                        }
 
                        return true;
@@ -4769,6 +4832,7 @@ namespace Mono.CSharp {
                protected override void CloneTo (CloneContext clonectx, Expression target)
                {
                        // Nothing to clone
+                       return;
                }
 
                public override Expression CreateExpressionTree (ResolveContext ec)
@@ -4842,31 +4906,40 @@ namespace Mono.CSharp {
                protected Arguments arguments;
                protected 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, Arguments arguments)
                {
-                       SimpleName sn = expr as SimpleName;
-                       if (sn != null)
-                               this.expr = sn.GetMethodGroup ();
-                       else
-                               this.expr = expr;
-                       
+                       this.expr = expr;               
                        this.arguments = arguments;
                        if (expr != null)
                                loc = expr.Location;
                }
 
-               public Invocation (Expression expr, Arguments arguments, bool arguments_resolved)
-                       : this (expr, arguments)
+               #region Properties
+               public Arguments Arguments {
+                       get {
+                               return arguments;
+                       }
+               }
+               
+               public Expression Expression {
+                       get {
+                               return expr;
+                       }
+               }
+               #endregion
+
+               protected override void CloneTo (CloneContext clonectx, Expression t)
                {
-                       this.arguments_resolved = arguments_resolved;
+                       Invocation target = (Invocation) t;
+
+                       if (arguments != null)
+                               target.arguments = arguments.Clone (clonectx);
+
+                       target.expr = expr.Clone (clonectx);
                }
 
+
                public override Expression CreateExpressionTree (ResolveContext ec)
                {
                        Expression instance = mg.IsInstance ?
@@ -4877,15 +4950,21 @@ namespace Mono.CSharp {
                                instance,
                                mg.CreateExpressionTree (ec));
 
-                       if (mg.IsBase)
-                               MemberExpr.Error_BaseAccessInExpressionTree (ec, loc);
-
                        return CreateExpressionFactoryCall (ec, "Call", args);
                }
 
                protected override Expression DoResolve (ResolveContext ec)
                {
-                       Expression member_expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
+                       Expression member_expr;
+                       var atn = expr as ATypeNameExpression;
+                       if (atn != null) {
+                               member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
+                               if (member_expr != null)
+                                       member_expr = member_expr.Resolve (ec);
+                       } else {
+                               member_expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
+                       }
+
                        if (member_expr == null)
                                return null;
 
@@ -4893,7 +4972,7 @@ namespace Mono.CSharp {
                        // Next, evaluate all the expressions in the argument list
                        //
                        bool dynamic_arg = false;
-                       if (arguments != null && !arguments_resolved)
+                       if (arguments != null)
                                arguments.Resolve (ec, out dynamic_arg);
 
                        TypeSpec expr_type = member_expr.Type;
@@ -4917,14 +4996,9 @@ namespace Mono.CSharp {
                                                        return null;
                                                }
 
-                                               mg = ec.LookupExtensionMethod (me.Type, me.Name, -1, loc);
-                                               if (mg == null) {
-                                                       ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
+                                               ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
                                                                member_expr.GetSignatureForError ());
-                                                       return null;
-                                               }
-
-                                               ((ExtensionMethodGroupExpr) mg).ExtensionExpression = me.InstanceExpression;
+                                               return null;
                                        }
                                }
 
@@ -4943,14 +5017,6 @@ namespace Mono.CSharp {
                                type = method.ReturnType;
                        }
                
-                       //
-                       // Only base will allow this invocation to happen.
-                       //
-                       if (mg.IsBase && method.IsAbstract){
-                               Error_CannotCallAbstractBase (ec, TypeManager.CSharpSignature (method));
-                               return null;
-                       }
-
                        if (arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == Destructor.MetadataName) {
                                if (mg.IsBase)
                                        ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
@@ -4992,20 +5058,24 @@ namespace Mono.CSharp {
                                        return null;
                                }
 
-                               args = arguments;
-
-                               if (mg.IsStatic != mg.IsInstance) {
-                                       if (args == null)
-                                               args = new Arguments (1);
+                               if (arguments == null)
+                                       args = new Arguments (1);
+                               else
+                                       args = arguments;
 
-                                       if (mg.IsStatic) {
-                                               args.Insert (0, new Argument (new TypeOf (new TypeExpression (mg.DeclaringType, loc), loc).Resolve (ec), Argument.AType.DynamicTypeName));
+                               MemberAccess ma = expr as MemberAccess;
+                               if (ma != null) {
+                                       var left_type = ma.LeftExpression as TypeExpr;
+                                       if (left_type != null) {
+                                               args.Insert (0, new Argument (new TypeOf (left_type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
                                        } else {
-                                               MemberAccess ma = expr as MemberAccess;
-                                               if (ma != null)
-                                                       args.Insert (0, new Argument (ma.Left.Resolve (ec)));
-                                               else
-                                                       args.Insert (0, new Argument (new This (loc).Resolve (ec)));
+                                               args.Insert (0, new Argument (ma.LeftExpression.Resolve (ec)));
+                                       }
+                               } else {        // is SimpleName
+                                       if (ec.IsStatic) {
+                                               args.Insert (0, new Argument (new TypeOf (new TypeExpression (ec.CurrentType, loc), loc).Resolve (ec), Argument.AType.DynamicTypeName));
+                                       } else {
+                                               args.Insert (0, new Argument (new This (loc).Resolve (ec)));
                                        }
                                }
                        }
@@ -5015,7 +5085,35 @@ namespace Mono.CSharp {
 
                protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
                {
-                       return mg.OverloadResolve (ec, ref arguments, false, loc);
+                       return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
+               }
+
+               static Type[] GetVarargsTypes (MethodSpec mb, Arguments arguments)
+               {
+                       AParametersCollection pd = mb.Parameters;
+
+                       Argument a = arguments[pd.Count - 1];
+                       Arglist list = (Arglist) a.Expr;
+
+                       return list.ArgumentTypes;
+               }
+
+               //
+               // If a member is a method or event, or if it is a constant, field or property of either a delegate type
+               // or the type dynamic, then the member is invocable
+               //
+               public static bool IsMemberInvocable (MemberSpec member)
+               {
+                       switch (member.Kind) {
+                       case MemberKind.Event:
+                               return true;
+                       case MemberKind.Field:
+                       case MemberKind.Property:
+                               var m = member as IInterfaceMemberSpec;
+                               return m.MemberType.IsDelegate || m.MemberType == InternalType.Dynamic;
+                       default:
+                               return false;
+                       }
                }
 
                public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
@@ -5023,7 +5121,7 @@ namespace Mono.CSharp {
                        if (!method.IsReservedMethod)
                                return false;
 
-                       if (ec.HasSet (ResolveContext.Options.InvokeSpecialName))
+                       if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
                                return false;
 
                        ec.Report.SymbolRelatedToPreviousError (method);
@@ -5033,14 +5131,32 @@ namespace Mono.CSharp {
                        return true;
                }
 
-               static Type[] GetVarargsTypes (MethodSpec mb, Arguments arguments)
+               //
+               // Used to decide whether call or callvirt is needed
+               //
+               static bool IsVirtualCallRequired (Expression instance, MethodSpec method)
                {
-                       AParametersCollection pd = mb.Parameters;
-                       
-                       Argument a = arguments [pd.Count - 1];
-                       Arglist list = (Arglist) a.Expr;
+                       //
+                       // There are 2 scenarious where we emit callvirt
+                       //
+                       // Case 1: A method is virtual and it's not used to call base
+                       // Case 2: A method instance expression can be null. In this casen callvirt ensures
+                       // correct NRE exception when the method is called
+                       //
+                       var decl_type = method.DeclaringType;
+                       if (decl_type.IsStruct || decl_type.IsEnum)
+                               return false;
 
-                       return list.ArgumentTypes;
+                       if (instance is BaseThis)
+                               return false;
+
+                       //
+                       // It's non-virtual and will never be null
+                       //
+                       if (!method.IsVirtual && (instance is This || instance is New || instance is ArrayCreation || instance is DelegateCreation || instance is TypeOf))
+                               return false;
+
+                       return true;
                }
 
                /// <remarks>
@@ -5058,11 +5174,10 @@ namespace Mono.CSharp {
                ///
                ///   Arguments is the list of arguments to pass to the method or constructor.
                /// </remarks>
-               public static void EmitCall (EmitContext ec, bool is_base,
-                                            Expression instance_expr,
+               public static void EmitCall (EmitContext ec, Expression instance_expr,
                                             MethodSpec method, Arguments Arguments, Location loc)
                {
-                       EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
+                       EmitCall (ec, instance_expr, method, Arguments, loc, false, false);
                }
                
                // `dup_args' leaves an extra copy of the arguments on the stack
@@ -5071,15 +5186,12 @@ namespace Mono.CSharp {
                // and then another with `omit_args' set to true, and the two calls
                // would have the same set of arguments. However, each argument would
                // only have been evaluated once.
-               public static void EmitCall (EmitContext ec, bool is_base,
-                                            Expression instance_expr,
+               public static void EmitCall (EmitContext ec, Expression instance_expr,
                                             MethodSpec method, Arguments Arguments, Location loc,
                                             bool dup_args, bool omit_args)
                {
                        LocalTemporary this_arg = null;
 
-                       TypeSpec decl_type = method.DeclaringType;
-
                        // Speed up the check by not doing it on not allowed targets
                        if (method.ReturnType == TypeManager.void_type && method.IsConditionallyExcluded (loc))
                                return;
@@ -5093,10 +5205,10 @@ namespace Mono.CSharp {
                        } else {
                                iexpr_type = instance_expr.Type;
 
-                               if (is_base || decl_type.IsStruct || decl_type.IsEnum || (instance_expr is This && !method.IsVirtual)) {
-                                       call_op = OpCodes.Call;
-                               } else {
+                               if (IsVirtualCallRequired (instance_expr, method)) {
                                        call_op = OpCodes.Callvirt;
+                               } else {
+                                       call_op = OpCodes.Call;
                                }
 
                                //
@@ -5108,8 +5220,8 @@ namespace Mono.CSharp {
                                        //
                                        // Push the instance expression
                                        //
-                                       if ((iexpr_type.IsStruct && (call_op == OpCodes.Callvirt || (call_op == OpCodes.Call && decl_type == iexpr_type))) ||
-                                               iexpr_type.IsGenericParameter || TypeManager.IsNullableType (decl_type)) {
+                                       if ((iexpr_type.IsStruct && (call_op == OpCodes.Callvirt || (call_op == OpCodes.Call && method.DeclaringType == iexpr_type))) ||
+                                               iexpr_type.IsGenericParameter || TypeManager.IsNullableType (method.DeclaringType)) {
                                                //
                                                // If the expression implements IMemoryLocation, then
                                                // we can optimize and use AddressOf on the
@@ -5186,19 +5298,9 @@ namespace Mono.CSharp {
                                ec.Emit (OpCodes.Pop);
                }
 
-               protected override void CloneTo (CloneContext clonectx, Expression t)
-               {
-                       Invocation target = (Invocation) t;
-
-                       if (arguments != null)
-                               target.arguments = arguments.Clone (clonectx);
-
-                       target.expr = expr.Clone (clonectx);
-               }
-
                public override SLE.Expression MakeExpression (BuilderContext ctx)
                {
-                       return MakeExpression (ctx, mg.InstanceExpression, (MethodSpec) mg, arguments);
+                       return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
                }
 
                public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
@@ -5208,11 +5310,12 @@ namespace Mono.CSharp {
                }
        }
 
-       /// <summary>
-       ///    Implements the new expression 
-       /// </summary>
-       public class New : ExpressionStatement, IMemoryLocation {
-               protected Arguments Arguments;
+       //
+       // Implements simple new expression 
+       //
+       public class New : ExpressionStatement, IMemoryLocation
+       {
+               protected Arguments arguments;
 
                //
                // During bootstrap, it contains the RequestedType,
@@ -5221,50 +5324,68 @@ namespace Mono.CSharp {
                //
                protected Expression RequestedType;
 
-               protected MethodGroupExpr method;
+               protected MethodSpec method;
 
                public New (Expression requested_type, Arguments arguments, Location l)
                {
                        RequestedType = requested_type;
-                       Arguments = arguments;
+                       this.arguments = arguments;
                        loc = l;
                }
 
+               #region Properties
+               public Arguments Arguments {
+                       get {
+                               return arguments;
+                       }
+               }
+
+               //
+               // Returns true for resolved `new S()'
+               //
+               public bool IsDefaultStruct {
+                       get {
+                               return arguments == null && type.IsStruct && GetType () == typeof (New);
+                       }
+               }
+
+               #endregion
+
                /// <summary>
                /// Converts complex core type syntax like 'new int ()' to simple constant
                /// </summary>
-               public static Constant Constantify (TypeSpec t)
+               public static Constant Constantify (TypeSpec t, Location loc)
                {
                        if (t == TypeManager.int32_type)
-                               return new IntConstant (0, Location.Null);
+                               return new IntConstant (0, loc);
                        if (t == TypeManager.uint32_type)
-                               return new UIntConstant (0, Location.Null);
+                               return new UIntConstant (0, loc);
                        if (t == TypeManager.int64_type)
-                               return new LongConstant (0, Location.Null);
+                               return new LongConstant (0, loc);
                        if (t == TypeManager.uint64_type)
-                               return new ULongConstant (0, Location.Null);
+                               return new ULongConstant (0, loc);
                        if (t == TypeManager.float_type)
-                               return new FloatConstant (0, Location.Null);
+                               return new FloatConstant (0, loc);
                        if (t == TypeManager.double_type)
-                               return new DoubleConstant (0, Location.Null);
+                               return new DoubleConstant (0, loc);
                        if (t == TypeManager.short_type)
-                               return new ShortConstant (0, Location.Null);
+                               return new ShortConstant (0, loc);
                        if (t == TypeManager.ushort_type)
-                               return new UShortConstant (0, Location.Null);
+                               return new UShortConstant (0, loc);
                        if (t == TypeManager.sbyte_type)
-                               return new SByteConstant (0, Location.Null);
+                               return new SByteConstant (0, loc);
                        if (t == TypeManager.byte_type)
-                               return new ByteConstant (0, Location.Null);
+                               return new ByteConstant (0, loc);
                        if (t == TypeManager.char_type)
-                               return new CharConstant ('\0', Location.Null);
+                               return new CharConstant ('\0', loc);
                        if (t == TypeManager.bool_type)
-                               return new BoolConstant (false, Location.Null);
+                               return new BoolConstant (false, loc);
                        if (t == TypeManager.decimal_type)
-                               return new DecimalConstant (0, Location.Null);
+                               return new DecimalConstant (0, loc);
                        if (TypeManager.IsEnumType (t))
-                               return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t)), t);
+                               return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
                        if (TypeManager.IsNullableType (t))
-                               return Nullable.LiftedNull.Create (t, Location.Null);
+                               return Nullable.LiftedNull.Create (t, loc);
 
                        return null;
                }
@@ -5287,7 +5408,7 @@ namespace Mono.CSharp {
                        if (real_class == null)
                                return null;
 
-                       New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
+                       New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
                        Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
                        return cast.Resolve (ec);
                }
@@ -5300,8 +5421,7 @@ namespace Mono.CSharp {
                                args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
                        } else {
                                args = Arguments.CreateForExpressionTree (ec,
-                                       Arguments,
-                                       method.CreateExpressionTree (ec));
+                                       arguments, new TypeOfMethod (method, loc));
                        }
 
                        return CreateExpressionFactoryCall (ec, "New", args);
@@ -5309,25 +5429,12 @@ namespace Mono.CSharp {
                
                protected override Expression DoResolve (ResolveContext ec)
                {
-                       //
-                       // The New DoResolve might be called twice when initializing field
-                       // expressions (see EmitFieldInitializers, the call to
-                       // GetInitializerExpression will perform a resolve on the expression,
-                       // and later the assign will trigger another resolution
-                       //
-                       // This leads to bugs (#37014)
-                       //
-                       if (type != null){
-                               if (RequestedType is NewDelegate)
-                                       return RequestedType;
-                               return this;
-                       }
-
                        TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
                        if (texpr == null)
                                return null;
 
                        type = texpr.Type;
+                       eclass = ExprClass.Value;
 
                        if (type.IsPointer) {
                                ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
@@ -5335,14 +5442,14 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       if (Arguments == null) {
-                               Constant c = Constantify (type);
+                       if (arguments == null) {
+                               Constant c = Constantify (type, RequestedType.Location);
                                if (c != null)
                                        return ReducedExpression.Create (c.Resolve (ec), this);
                        }
 
                        if (TypeManager.IsDelegateType (type)) {
-                               return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
+                               return (new NewDelegate (type, arguments, loc)).Resolve (ec);
                        }
 
                        var tparam = type as TypeParameterSpec;
@@ -5353,7 +5460,7 @@ namespace Mono.CSharp {
                                                TypeManager.CSharpName (type));
                                }
 
-                               if ((Arguments != null) && (Arguments.Count != 0)) {
+                               if ((arguments != null) && (arguments.Count != 0)) {
                                        ec.Report.Error (417, loc,
                                                "`{0}': cannot provide arguments when creating an instance of a variable type",
                                                TypeManager.CSharpName (type));
@@ -5367,7 +5474,6 @@ namespace Mono.CSharp {
                                        }
                                }
 
-                               eclass = ExprClass.Value;
                                return this;
                        }
 
@@ -5389,43 +5495,24 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       bool is_struct = TypeManager.IsStruct (type);
-                       eclass = ExprClass.Value;
-
                        //
-                       // SRE returns a match for .ctor () on structs (the object constructor), 
-                       // so we have to manually ignore it.
+                       // Any struct always defines parameterless constructor
                        //
-                       if (is_struct && Arguments == null)
+                       if (type.IsStruct && arguments == null)
                                return this;
 
-                       // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
-                       Expression ml = MemberLookupFinal (ec, type, type, ConstructorInfo.ConstructorName, 0,
-                               MemberKind.Constructor, BindingRestriction.AccessibleOnly | BindingRestriction.DeclaredOnly, loc);
-
                        bool dynamic;
-                       if (Arguments != null) {
-                               Arguments.Resolve (ec, out dynamic);
+                       if (arguments != null) {
+                               arguments.Resolve (ec, out dynamic);
                        } else {
                                dynamic = false;
                        }
 
-                       if (ml == null)
-                               return null;
-
-                       method = ml as MethodGroupExpr;
-                       if (method == null) {
-                               ml.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
-                               return null;
-                       }
-
-                       method = method.OverloadResolve (ec, ref Arguments, false, loc);
-                       if (method == null)
-                               return null;
+                       method = ConstructorLookup (ec, type, ref arguments, loc);
 
                        if (dynamic) {
-                               Arguments.Insert (0, new Argument (new TypeOf (texpr, loc).Resolve (ec), Argument.AType.DynamicTypeName));
-                               return new DynamicConstructorBinder (type, Arguments, loc).Resolve (ec);
+                               arguments.Insert (0, new Argument (new TypeOf (texpr, loc).Resolve (ec), Argument.AType.DynamicTypeName));
+                               return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
                        }
 
                        return this;
@@ -5506,8 +5593,8 @@ namespace Mono.CSharp {
                                vr.EmitLoad (ec);
                        }
                        
-                       if (Arguments != null)
-                               Arguments.Emit (ec);
+                       if (arguments != null)
+                               arguments.Emit (ec);
 
                        if (is_value_type) {
                                if (method == null) {
@@ -5516,7 +5603,7 @@ namespace Mono.CSharp {
                                }
 
                                if (vr != null) {
-                                       ec.Emit (OpCodes.Call, method.BestCandidate);
+                                       ec.Emit (OpCodes.Call, method);
                                        return false;
                                }
                        }
@@ -5524,7 +5611,7 @@ namespace Mono.CSharp {
                        if (type is TypeParameterSpec)
                                return DoEmitTypeParameter (ec);                        
 
-                       ec.Emit (OpCodes.Newobj, method.BestCandidate);
+                       ec.Emit (OpCodes.Newobj, method);
                        return true;
                }
 
@@ -5552,12 +5639,6 @@ namespace Mono.CSharp {
                                ec.Emit (OpCodes.Pop);
                }
 
-               public virtual bool HasInitializer {
-                       get {
-                               return false;
-                       }
-               }
-
                public void AddressOf (EmitContext ec, AddressOp mode)
                {
                        EmitAddressOf (ec, mode);
@@ -5589,10 +5670,10 @@ namespace Mono.CSharp {
                        if (method == null) {
                                ec.Emit (OpCodes.Initobj, type);
                        } else {
-                               if (Arguments != null)
-                                       Arguments.Emit (ec);
+                               if (arguments != null)
+                                       arguments.Emit (ec);
 
-                               ec.Emit (OpCodes.Call, method.BestCandidate);
+                               ec.Emit (OpCodes.Call, method);
                        }
                        
                        value_target.AddressOf (ec, mode);
@@ -5604,20 +5685,27 @@ namespace Mono.CSharp {
                        New target = (New) t;
 
                        target.RequestedType = RequestedType.Clone (clonectx);
-                       if (Arguments != null){
-                               target.Arguments = Arguments.Clone (clonectx);
+                       if (arguments != null){
+                               target.arguments = arguments.Clone (clonectx);
                        }
                }
 
                public override SLE.Expression MakeExpression (BuilderContext ctx)
                {
-                       return SLE.Expression.New ((ConstructorInfo) method.BestCandidate.GetMetaInfo (), Arguments.MakeExpression (Arguments, ctx));
+                       return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
                }
        }
 
+       //
+       // Array initializer expression, the expression is allowed in
+       // variable or field initialization only which makes it tricky as
+       // the type has to be infered based on the context either from field
+       // type or variable type (think of multiple declarators)
+       //
        public class ArrayInitializer : Expression
        {
                List<Expression> elements;
+               BlockVariableDeclaration variable;
 
                public ArrayInitializer (List<Expression> init, Location loc)
                {
@@ -5626,9 +5714,8 @@ namespace Mono.CSharp {
                }
 
                public ArrayInitializer (int count, Location loc)
+                       : this (new List<Expression> (count), loc)
                {
-                       elements = new List<Expression> (count);
-                       this.loc = loc;
                }
 
                public ArrayInitializer (Location loc)
@@ -5636,6 +5723,29 @@ namespace Mono.CSharp {
                {
                }
 
+               #region Properties
+
+               public int Count {
+                       get { return elements.Count; }
+               }
+
+               public Expression this [int index] {
+                       get {
+                               return elements [index];
+                       }
+               }
+
+               public BlockVariableDeclaration VariableDeclaration {
+                       get {
+                               return variable;
+                       }
+                       set {
+                               variable = value;
+                       }
+               }
+
+               #endregion
+
                public void Add (Expression expr)
                {
                        elements.Add (expr);
@@ -5655,23 +5765,30 @@ namespace Mono.CSharp {
                                target.elements.Add (element.Clone (clonectx));
                }
 
-               public int Count {
-                       get { return elements.Count; }
-               }
-
                protected override Expression DoResolve (ResolveContext rc)
                {
-                       throw new NotImplementedException ();
+                       var current_field = rc.CurrentMemberDefinition as FieldBase;
+                       TypeExpression type;
+                       if (current_field != null) {
+                               type = new TypeExpression (current_field.MemberType, current_field.Location);
+                       } else if (variable != null) {
+                               if (variable.TypeExpression is VarExpr) {
+                                       rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
+                                       return EmptyExpression.Null;
+                               }
+
+                               type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
+                       } else {
+                               throw new NotImplementedException ("Unexpected array initializer context");
+                       }
+
+                       return new ArrayCreation (type, this).Resolve (rc);
                }
 
                public override void Emit (EmitContext ec)
                {
                        throw new InternalErrorException ("Missing Resolve call");
                }
-
-               public Expression this [int index] {
-                       get { return elements [index]; }
-               }
        }
 
        /// <summary>
@@ -5940,11 +6057,6 @@ namespace Mono.CSharp {
                //
                bool ResolveArrayType (ResolveContext ec)
                {
-                       if (requested_base_type is VarExpr) {
-                               ec.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
-                               return false;
-                       }
-                       
                        //
                        // Lookup the type
                        //
@@ -6253,9 +6365,10 @@ namespace Mono.CSharp {
                                return;
 
                        // Emit static initializer for arrays which have contain more than 2 items and
-                       // the static initializer will initialize at least 25% of array values.
+                       // the static initializer will initialize at least 25% of array values or there
+                       // is more than 10 items to be initialized
                        // NOTE: const_initializers_count does not contain default constant values.
-                       if (const_initializers_count > 2 && const_initializers_count * 4 > (array_data.Count) &&
+                       if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
                                (TypeManager.IsPrimitiveType (array_element_type) || TypeManager.IsEnumType (array_element_type))) {
                                EmitStaticInitializers (ec);
 
@@ -6284,7 +6397,10 @@ namespace Mono.CSharp {
                                        return;
                                }
 
-                               enc.Encode (type);
+                               if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
+                                       Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
+                                       return;
+                               }
                        }
 
                        // Single dimensional array of 0 size
@@ -6328,6 +6444,8 @@ namespace Mono.CSharp {
        //
        class ImplicitlyTypedArrayCreation : ArrayCreation
        {
+               TypeInferenceContext best_type_inference;
+
                public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
                        : base (null, rank, initializers, loc)
                {                       
@@ -6345,14 +6463,19 @@ namespace Mono.CSharp {
 
                        dimensions = rank.Dimension;
 
+                       best_type_inference = new TypeInferenceContext ();
+
                        if (!ResolveInitializers (ec))
                                return null;
 
-                       if (array_element_type == null || array_element_type == TypeManager.null_type ||
-                               array_element_type == TypeManager.void_type || array_element_type == InternalType.AnonymousMethod ||
-                               array_element_type == InternalType.MethodGroup ||
+                       best_type_inference.FixAllTypes (ec);
+                       array_element_type = best_type_inference.InferredTypeArguments[0];
+                       best_type_inference = null;
+
+                       if (array_element_type == null || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
                                arguments.Count != rank.Dimension) {
-                               Error_NoBestType (ec);
+                               ec.Report.Error (826, loc,
+                                       "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
                                return null;
                        }
 
@@ -6368,19 +6491,13 @@ namespace Mono.CSharp {
                        return this;
                }
 
-               void Error_NoBestType (ResolveContext ec)
-               {
-                       ec.Report.Error (826, loc,
-                               "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
-               }
-
                //
                // Converts static initializer only
                //
                void UnifyInitializerElement (ResolveContext ec)
                {
                        for (int i = 0; i < array_data.Count; ++i) {
-                               Expression e = (Expression)array_data[i];
+                               Expression e = array_data[i];
                                if (e != null)
                                        array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
                        }
@@ -6389,27 +6506,10 @@ namespace Mono.CSharp {
                protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
                {
                        element = element.Resolve (ec);
-                       if (element == null)
-                               return null;
-                       
-                       if (array_element_type == null) {
-                               if (element.Type != TypeManager.null_type)
-                                       array_element_type = element.Type;
-
-                               return element;
-                       }
-
-                       if (Convert.ImplicitConversionExists (ec, element, array_element_type)) {
-                               return element;
-                       }
-
-                       if (Convert.ImplicitConversionExists (ec, new TypeExpression (array_element_type, loc), element.Type)) {
-                               array_element_type = element.Type;
-                               return element;
-                       }
+                       if (element != null)
+                               best_type_inference.AddCommonTypeBound (element.Type);
 
-                       Error_NoBestType (ec);
-                       return null;
+                       return element;
                }
        }       
        
@@ -6476,6 +6576,20 @@ namespace Mono.CSharp {
                        this.loc = loc;
                }
 
+               #region Properties
+
+               public override string Name {
+                       get { return "this"; }
+               }
+
+               public override bool IsRef {
+                       get { return type.IsStruct; }
+               }
+
+               protected override ILocalVariable Variable {
+                       get { return ThisVariable.Instance; }
+               }
+
                public override VariableInfo VariableInfo {
                        get { return variable_info; }
                }
@@ -6484,6 +6598,21 @@ namespace Mono.CSharp {
                        get { return false; }
                }
 
+               #endregion
+
+               protected virtual void Error_ThisNotAvailable (ResolveContext ec)
+               {
+                       if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
+                               ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
+                       } else if (ec.CurrentAnonymousMethod != null) {
+                               ec.Report.Error (1673, loc,
+                                       "Anonymous methods inside structs cannot access instance members of `this'. " +
+                                       "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
+                       } else {
+                               ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
+                       }
+               }
+
                public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
                {
                        if (ae == null)
@@ -6501,14 +6630,6 @@ namespace Mono.CSharp {
                        return null;
                }
 
-               public override bool IsRef {
-                       get { return type.IsStruct; }
-               }
-
-               protected override ILocalVariable Variable {
-                       get { return ThisVariable.Instance; }
-               }
-
                public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
                {
                        if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
@@ -6523,35 +6644,25 @@ namespace Mono.CSharp {
                        return true;
                }
 
-               public bool ResolveBase (ResolveContext ec)
+               public virtual void ResolveBase (ResolveContext ec)
                {
-                       eclass = ExprClass.Variable;
-                       type = ec.CurrentType;
-
                        if (!IsThisAvailable (ec, false)) {
-                               if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
-                                       ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
-                               } else if (ec.CurrentAnonymousMethod != null) {
-                                       ec.Report.Error (1673, loc,
-                                               "Anonymous methods inside structs cannot access instance members of `this'. " +
-                                               "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
-                               } else {
-                                       ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
-                               }
+                               Error_ThisNotAvailable (ec);
                        }
 
                        var block = ec.CurrentBlock;
                        if (block != null) {
-                               if (block.Toplevel.ThisVariable != null)
-                                       variable_info = block.Toplevel.ThisVariable.VariableInfo;
+                               if (block.ParametersBlock.TopBlock.ThisVariable != null)
+                                       variable_info = block.ParametersBlock.TopBlock.ThisVariable.VariableInfo;
 
                                AnonymousExpression am = ec.CurrentAnonymousMethod;
                                if (am != null && ec.IsVariableCapturingRequired) {
                                        am.SetHasThisAccess ();
                                }
                        }
-                       
-                       return true;
+
+                       eclass = ExprClass.Variable;
+                       type = ec.CurrentType;
                }
 
                //
@@ -6585,8 +6696,7 @@ namespace Mono.CSharp {
 
                override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
                {
-                       if (!ResolveBase (ec))
-                               return null;
+                       ResolveBase (ec);
 
                        if (variable_info != null)
                                variable_info.SetAssigned (ec);
@@ -6608,10 +6718,6 @@ namespace Mono.CSharp {
                        throw new NotImplementedException ();
                }
 
-               public override string Name {
-                       get { return "this"; }
-               }
-
                public override bool Equals (object obj)
                {
                        This t = obj as This;
@@ -6652,7 +6758,7 @@ namespace Mono.CSharp {
                        eclass = ExprClass.Variable;
                        type = TypeManager.runtime_argument_handle_type;
 
-                       if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.Toplevel.Parameters.HasArglist) {
+                       if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
                                ec.Report.Error (190, loc,
                                        "The __arglist construct is valid only within a variable argument method");
                        }
@@ -6779,13 +6885,6 @@ namespace Mono.CSharp {
 
                        typearg = texpr.Type;
 
-                       //
-                       // Get generic type definition for unbounded type arguments
-                       //
-                       var tne = QueriedType as ATypeNameExpression;
-                       if (tne != null && typearg.IsGeneric && !tne.HasTypeArguments)
-                               typearg = typearg.GetDefinition ();
-
                        if (typearg == TypeManager.void_type && !(QueriedType is TypeExpression)) {
                                ec.Report.Error (673, loc, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
                        } else if (typearg.IsPointer && !ec.IsUnsafe){
@@ -6796,6 +6895,7 @@ namespace Mono.CSharp {
                        }
 
                        type = TypeManager.type_type;
+                       QueriedType = texpr;
 
                        return DoResolveBase ();
                }
@@ -6813,6 +6913,42 @@ namespace Mono.CSharp {
                        return this;
                }
 
+               static bool ContainsDynamicType (TypeSpec type)
+               {
+                       if (type == InternalType.Dynamic)
+                               return true;
+
+                       var element_container = type as ElementTypeSpec;
+                       if (element_container != null)
+                               return ContainsDynamicType (element_container.Element);
+
+                       foreach (var t in type.TypeArguments) {
+                               if (ContainsDynamicType (t)) {
+                                       return true;
+                               }
+                       }
+
+                       return false;
+               }
+
+               static bool ContainsTypeParameter (TypeSpec type)
+               {
+                       if (type.Kind == MemberKind.TypeParameter)
+                               return true;
+
+                       var element_container = type as ElementTypeSpec;
+                       if (element_container != null)
+                               return ContainsTypeParameter (element_container.Element);
+
+                       foreach (var t in type.TypeArguments) {
+                               if (ContainsTypeParameter (t)) {
+                                       return true;
+                               }
+                       }
+
+                       return false;
+               }
+
                public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
                {
                        // Target type is not System.Type therefore must be object
@@ -6820,28 +6956,25 @@ namespace Mono.CSharp {
                        if (targetType != type)
                                enc.Encode (type);
 
-/*
-                       var gi = typearg as InflatedTypeSpec;
-                       if (gi != null) {
-                               // TODO: This has to be recursive, handle arrays, etc.
-                               // I could probably do it after CustomAttribute encoder rewrite
-                               foreach (var ta in gi.TypeArguments) {
-                                       if (ta.IsGenericParameter) {
-                                               ec.Report.SymbolRelatedToPreviousError (typearg);
-                                               ec.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
-                                                                TypeManager.CSharpName (typearg));
-                                               value = null;
-                                               return false;
+                       if (!(QueriedType is GenericOpenTypeExpr)) {
+                               var gt = typearg;
+                               while (gt != null) {
+                                       if (ContainsTypeParameter (gt)) {
+                                               rc.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
+                                                       typearg.GetSignatureForError ());
+                                               return;
                                        }
+
+                                       gt = gt.DeclaringType;
                                }
-                       }
- */
 
-                       if (!enc.EncodeTypeName (typearg)) {
-                               rc.Compiler.Report.SymbolRelatedToPreviousError (typearg);
-                               rc.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
-                                       TypeManager.CSharpName (typearg));
+                               if (ContainsDynamicType (typearg)) {
+                                       Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
+                                       return;
+                               }
                        }
+
+                       enc.EncodeTypeName (typearg);
                }
 
                public override void Emit (EmitContext ec)
@@ -7126,7 +7259,7 @@ namespace Mono.CSharp {
                public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
                {
                        if (alias == GlobalAlias) {
-                               expr = GlobalRootNamespace.Instance;
+                               expr = ec.Compiler.GlobalRootNamespace;
                                return base.ResolveAsTypeStep (ec, silent);
                        }
 
@@ -7175,6 +7308,11 @@ namespace Mono.CSharp {
                        return alias + "::" + name;
                }
 
+               public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
+               {
+                       return DoResolve (rc);
+               }
+
                protected override void CloneTo (CloneContext clonectx, Expression t)
                {
                        // Nothing 
@@ -7184,7 +7322,8 @@ namespace Mono.CSharp {
        /// <summary>
        ///   Implements the member access expression
        /// </summary>
-       public class MemberAccess : ATypeNameExpression {
+       public class MemberAccess : ATypeNameExpression
+       {
                protected Expression expr;
 
                public MemberAccess (Expression expr, string id)
@@ -7211,179 +7350,216 @@ namespace Mono.CSharp {
                        this.expr = expr;
                }
 
-               Expression DoResolve (ResolveContext ec, Expression right_side)
+               public Expression LeftExpression {
+                       get {
+                               return expr;
+                       }
+               }
+
+               protected override Expression DoResolve (ResolveContext ec)
                {
-                       if (type != null)
-                               throw new Exception ();
+                       return DoResolveName (ec, null);
+               }
 
-                       //
-                       // Resolve the expression with flow analysis turned off, we'll do the definite
-                       // assignment checks later.  This is because we don't know yet what the expression
-                       // will resolve to - it may resolve to a FieldExpr and in this case we must do the
-                       // definite assignment check on the actual field and not on the whole struct.
-                       //
+               public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
+               {
+                       return DoResolveName (ec, right_side);
+               }
+
+               Expression DoResolveName (ResolveContext rc, Expression right_side)
+               {
+                       Expression e = LookupNameExpression (rc, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
+                       if (e == null)
+                               return null;
 
-                       SimpleName original = expr as SimpleName;
-                       Expression expr_resolved;
+                       if (right_side != null) {
+                               if (e is TypeExpr) {
+                                       e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
+                                       return null;
+                               }
+
+                               e = e.ResolveLValue (rc, right_side);
+                       } else {
+                               e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type);
+                       }
+
+                       return e;
+               }
+
+               public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
+               {
+                       var sn = expr as SimpleName;
                        const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
 
-                       using (ec.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
-                               if (original != null) {
-                                       expr_resolved = original.DoResolve (ec, true);
-                                       if (expr_resolved != null) {
-                                               // Ugly, simulate skipped Resolve
-                                               if (expr_resolved is ConstantExpr) {
-                                                       expr_resolved = expr_resolved.Resolve (ec);
-                                               } else if (expr_resolved is FieldExpr || expr_resolved is PropertyExpr) {
-                                                       // nothing yet
-                                               } else if ((flags & expr_resolved.ExprClassToResolveFlags) == 0) {
-                                                       expr_resolved.Error_UnexpectedKind (ec, flags, expr.Location);
-                                                       expr_resolved = null;
+                       //
+                       // Resolve the expression with flow analysis turned off, we'll do the definite
+                       // assignment checks later.  This is because we don't know yet what the expression
+                       // will resolve to - it may resolve to a FieldExpr and in this case we must do the
+                       // definite assignment check on the actual field and not on the whole struct.
+                       //
+                       using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
+                               if (sn != null) {
+                                       expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
+
+                                       // Call resolve on expression which does have type set as we need expression type
+                                       // TODO: I should probably ensure that the type is always set and leave resolve for the final
+                                       if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) {
+                                               using (rc.With (ResolveContext.Options.DoFlowAnalysis, false)) {
+                                                       expr = expr.Resolve (rc);
                                                }
+                                       } else if (expr is TypeParameterExpr) {
+                                               expr.Error_UnexpectedKind (rc, flags, expr.Location);
+                                               expr = null;
                                        }
                                } else {
-                                       expr_resolved = expr.Resolve (ec, flags);
+                                       expr = expr.Resolve (rc, flags);
                                }
                        }
 
-                       if (expr_resolved == null)
+                       if (expr == null)
                                return null;
 
-                       Namespace ns = expr_resolved as Namespace;
+                       Namespace ns = expr as Namespace;
                        if (ns != null) {
-                               FullNamedExpression retval = ns.Lookup (ec.Compiler, Name, Arity, loc);
+                               FullNamedExpression retval = ns.Lookup (rc.Compiler, Name, Arity, loc);
 
-                               if (retval == null)
-                                       ns.Error_NamespaceDoesNotExist (loc, Name, Arity, ec);
-                               else if (HasTypeArguments)
-                                       retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (ec, false);
+                               if (retval == null) {
+                                       ns.Error_NamespaceDoesNotExist (loc, Name, Arity, rc);
+                                       return null;
+                               }
+
+                               if (HasTypeArguments)
+                                       return new GenericTypeExpr (retval.Type, targs, loc);
 
                                return retval;
                        }
 
-                       TypeSpec expr_type = expr_resolved.Type;
+                       MemberExpr me;
+                       TypeSpec expr_type = expr.Type;
                        if (expr_type == InternalType.Dynamic) {
-                               Arguments args = new Arguments (1);
-                               args.Add (new Argument (expr_resolved.Resolve (ec)));
-                               expr = new DynamicMemberBinder (Name, args, loc);
-                               if (right_side != null)
-                                       return expr.DoResolveLValue (ec, right_side);
+                               me = expr as MemberExpr;
+                               if (me != null)
+                                       me.ResolveInstanceExpression (rc);
 
-                               return expr.Resolve (ec);
+                               Arguments args = new Arguments (1);
+                               args.Add (new Argument (expr));
+                               return new DynamicMemberBinder (Name, args, loc);
                        }
 
-
                        const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
                                MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
 
                        if ((expr_type.Kind & dot_kinds) == 0 || expr_type == TypeManager.void_type) {
-                               Unary.Error_OperatorCannotBeApplied (ec, loc, ".", expr_type);
+                               if (expr_type == InternalType.Null && rc.Compiler.IsRuntimeBinder)
+                                       rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
+                               else
+                                       Unary.Error_OperatorCannotBeApplied (rc, loc, ".", expr_type);
                                return null;
                        }
 
-                       var arity = HasTypeArguments ? targs.Count : -1;
-
-                       var member_lookup = MemberLookup (ec.Compiler,
-                               ec.CurrentType, expr_type, expr_type, Name, arity, BindingRestriction.NoOverrides, loc);
-
-                       if (member_lookup == null) {
-                               expr = expr_resolved.Resolve (ec);
-
-                               ExprClass expr_eclass = expr.eclass;
+                       var current_type = rc.CurrentType;
+                       var lookup_arity = Arity;
+                       bool errorMode = false;
+                       Expression member_lookup;
+                       while (true) {
+                               member_lookup = MemberLookup (errorMode ? null : rc, current_type, expr_type, Name, lookup_arity, restrictions, loc);
+                               if (member_lookup == null) {
+                                       //
+                                       // Try to look for extension method when member lookup failed
+                                       //
+                                       if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
+                                               NamespaceEntry scope = null;
+                                               var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity, ref scope);
+                                               if (methods != null) {
+                                                       var emg = new ExtensionMethodGroupExpr (methods, scope, expr, loc);
+                                                       if (HasTypeArguments) {
+                                                               if (!targs.Resolve (rc))
+                                                                       return null;
+
+                                                               emg.SetTypeArguments (rc, targs);
+                                                       }
+
+                                                       // TODO: Should it really skip the checks bellow
+                                                       return emg.Resolve (rc);
+                                               }
+                                       }
+                               }
 
-                               //
-                               // 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.LookupExtensionMethod (expr_type, Name, arity, loc);
-                                       if (ex_method_lookup != null) {
-                                               ex_method_lookup.ExtensionExpression = expr;
-
-                                               if (HasTypeArguments) {
-                                                       if (!targs.Resolve (ec))
-                                                               return null;
+                               if (errorMode) {
+                                       if (member_lookup == null) {
+                                               if (expr is TypeExpr)
+                                                       base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
+                                               else
+                                                       Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
 
-                                                       ex_method_lookup.SetTypeArguments (ec, targs);
-                                               }
+                                               return null;
+                                       }
 
-                                               return ex_method_lookup.Resolve (ec);
+                                       if (member_lookup is MethodGroupExpr) {
+                                               // Leave it to overload resolution to report correct error
+                                       } else {
+                                               // TODO: rc.SymbolRelatedToPreviousError
+                                               ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
                                        }
+                                       break;
                                }
 
-                               member_lookup = Error_MemberLookupFailed (ec,
-                                       ec.CurrentType, expr_type, expr_type, Name, arity, null,
-                                       MemberKind.All, BindingRestriction.AccessibleOnly);
-                               if (member_lookup == null)
-                                       return null;
+                               if (member_lookup != null)
+                                       break;
+
+                               current_type = null;
+                               lookup_arity = 0;
+                               restrictions &= ~MemberLookupRestrictions.InvocableOnly;
+                               errorMode = true;
                        }
 
-                       MemberExpr me;
                        TypeExpr texpr = member_lookup as TypeExpr;
                        if (texpr != null) {
-                               if (!(expr_resolved is TypeExpr)) {
-                                       me = expr_resolved as MemberExpr;
-                                       if (me == null || me.ProbeIdenticalTypeName (ec, expr_resolved, original) == expr_resolved) {
-                                               ec.Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
+                               if (!(expr is TypeExpr)) {
+                                       me = expr as MemberExpr;
+                                       if (me == null || me.ProbeIdenticalTypeName (rc, expr, sn) == expr) {
+                                               rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
                                                        Name, member_lookup.GetSignatureForError ());
                                                return null;
                                        }
                                }
 
-                               if (!texpr.CheckAccessLevel (ec.MemberContext)) {
-                                       ec.Report.SymbolRelatedToPreviousError (member_lookup.Type);
-                                       ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type), ec.Report);
+                               if (!texpr.Type.IsAccessible (rc.CurrentType)) {
+                                       rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
+                                       ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
                                        return null;
                                }
 
                                if (HasTypeArguments) {
-                                       var ct = new GenericTypeExpr (member_lookup.Type, targs, loc);
-                                       return ct.ResolveAsTypeStep (ec, false);
+                                       return new GenericTypeExpr (member_lookup.Type, targs, loc);
                                }
 
                                return member_lookup;
                        }
 
-                       me = (MemberExpr) member_lookup;
+                       me = member_lookup as MemberExpr;
 
-                       if (original != null && me.IsStatic)
-                               expr_resolved = me.ProbeIdenticalTypeName (ec, expr_resolved, original);
+                       if (sn != null && me.IsStatic)
+                               expr = me.ProbeIdenticalTypeName (rc, expr, sn);
 
-                       me = me.ResolveMemberAccess (ec, expr_resolved, original);
+                       me = me.ResolveMemberAccess (rc, expr, sn);
 
-                       if (HasTypeArguments) {
-                               if (!targs.Resolve (ec))
+                       if (Arity > 0) {
+                               if (!targs.Resolve (rc))
                                        return null;
 
-                               me.SetTypeArguments (ec, targs);
+                               me.SetTypeArguments (rc, targs);
                        }
 
-                       if (original != null && (!TypeManager.IsValueType (expr_type) || me is PropertyExpr)) {
+                       if (sn != null && (!TypeManager.IsValueType (expr_type) || me is PropertyExpr)) {
                                if (me.IsInstance) {
-                                       LocalVariableReference var = expr_resolved as LocalVariableReference;
-                                       if (var != null && !var.VerifyAssigned (ec))
+                                       LocalVariableReference var = expr as LocalVariableReference;
+                                       if (var != null && !var.VerifyAssigned (rc))
                                                return null;
                                }
                        }
 
-                       // The following DoResolve/DoResolveLValue will do the definite assignment
-                       // check.
-
-                       if (right_side != null)
-                               return me.DoResolveLValue (ec, right_side);
-                       else
-                               return me.Resolve (ec);
-               }
-
-               protected override Expression DoResolve (ResolveContext ec)
-               {
-                       return DoResolve (ec, null);
-               }
-
-               public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
-               {
-                       return DoResolve (ec, right_side);
+                       return me;
                }
 
                public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
@@ -7432,14 +7608,17 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       bool extra_check;
-                       if (!IsMemberAccessible (rc.CurrentType ?? InternalType.FakeInternalType, nested, out extra_check)) {
-                               ErrorIsInaccesible (loc, nested.GetSignatureForError (), rc.Compiler.Report);
+                       if (!nested.IsAccessible (rc.CurrentType ?? InternalType.FakeInternalType)) {
+                               ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
                        }
                        
                        TypeExpr texpr;
-                       if (HasTypeArguments) {
-                               texpr = new GenericTypeExpr (nested, targs, loc);
+                       if (Arity > 0) {
+                               if (HasTypeArguments) {
+                                       texpr = new GenericTypeExpr (nested, targs, loc);
+                               } else {
+                                       texpr = new GenericOpenTypeExpr (nested, loc);
+                               }
                        } else {
                                texpr = new TypeExpression (nested, loc);
                        }
@@ -7456,27 +7635,22 @@ namespace Mono.CSharp {
                                return;
                        }
 
-                       var member_lookup = MemberLookup (rc.Compiler,
-                               rc.CurrentType, expr_type, expr_type, identifier, -1,
-                                       MemberKind.All, BindingRestriction.None, loc);
-
-                       if (member_lookup == null) {
-                               rc.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
-                                                 Name, expr_type.GetSignatureForError ());
-                       } else {
-                               // TODO: Report.SymbolRelatedToPreviousError
-                               member_lookup.Error_UnexpectedKind (rc.Compiler.Report, null, "type", loc);
+                       var any_other_member = MemberLookup (null, rc.CurrentType, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
+                       if (any_other_member != null) {
+                               any_other_member.Error_UnexpectedKind (rc.Compiler.Report, null, "type", loc);
+                               return;
                        }
+
+                       rc.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
+                               Name, expr_type.GetSignatureForError ());
                }
 
                protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
                {
-                       if (RootContext.Version > LanguageVersion.ISO_2 && !ec.Compiler.IsRuntimeBinder &&
-                               ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
-                               ec.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);
+                       if (RootContext.Version > LanguageVersion.ISO_2 && !ec.Compiler.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
+                               ec.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?)",
+                                       type.GetSignatureForError (), name);
                                return;
                        }
 
@@ -7488,12 +7662,6 @@ namespace Mono.CSharp {
                        return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
                }
 
-               public Expression Left {
-                       get {
-                               return expr;
-                       }
-               }
-
                protected override void CloneTo (CloneContext clonectx, Expression t)
                {
                        MemberAccess target = (MemberAccess) t;
@@ -7629,13 +7797,43 @@ namespace Mono.CSharp {
                public Arguments Arguments;
                public Expression Expr;
 
-               public ElementAccess (Expression e, Arguments args)
+               public ElementAccess (Expression e, Arguments args, Location loc)
                {
                        Expr = e;
-                       loc  = e.Location;
+                       this.loc = loc;
                        this.Arguments = args;
                }
 
+               //
+               // We perform some simple tests, and then to "split" the emit and store
+               // code we create an instance of a different class, and return that.
+               //
+               Expression CreateAccessExpression (ResolveContext ec)
+               {
+                       if (type.IsArray)
+                               return (new ArrayAccess (this, loc));
+
+                       if (type.IsPointer)
+                               return MakePointerAccess (ec, type);
+
+                       FieldExpr fe = Expr as FieldExpr;
+                       if (fe != null) {
+                               var ff = fe.Spec as FixedFieldSpec;
+                               if (ff != null) {
+                                       return MakePointerAccess (ec, ff.ElementType);
+                               }
+                       }
+
+                       var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
+                       if (indexers != null || type == InternalType.Dynamic) {
+                               return new IndexerExpr (indexers, this);
+                       }
+
+                       ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
+                               type.GetSignatureForError ());
+                       return null;
+               }
+
                public override Expression CreateExpressionTree (ResolveContext ec)
                {
                        Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
@@ -7644,7 +7842,7 @@ namespace Mono.CSharp {
                        return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
                }
 
-               Expression MakePointerAccess (ResolveContext ec, TypeSpec t)
+               Expression MakePointerAccess (ResolveContext ec, TypeSpec type)
                {
                        if (Arguments.Count != 1){
                                ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
@@ -7654,8 +7852,8 @@ namespace Mono.CSharp {
                        if (Arguments [0] is NamedArgument)
                                Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
 
-                       Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), t, loc);
-                       return new Indirection (p, loc).Resolve (ec);
+                       Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), type, loc);
+                       return new Indirection (p, loc);
                }
                
                protected override Expression DoResolve (ResolveContext ec)
@@ -7664,32 +7862,14 @@ namespace Mono.CSharp {
                        if (Expr == null)
                                return null;
 
-                       //
-                       // We perform some simple tests, and then to "split" the emit and store
-                       // code we create an instance of a different class, and return that.
-                       //
-                       // I am experimenting with this pattern.
-                       //
-                       TypeSpec t = Expr.Type;
+                       type = Expr.Type;
 
-                       if (t == TypeManager.array_type){
-                               ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
+                       // TODO: Create 1 result for Resolve and ResolveLValue ?
+                       var res = CreateAccessExpression (ec);
+                       if (res == null)
                                return null;
-                       }
-                       
-                       if (t.IsArray)
-                               return (new ArrayAccess (this, loc)).Resolve (ec);
-                       if (t.IsPointer)
-                               return MakePointerAccess (ec, t);
 
-                       FieldExpr fe = Expr as FieldExpr;
-                       if (fe != null) {
-                               var ff = fe.Spec as FixedFieldSpec;
-                               if (ff != null) {
-                                       return MakePointerAccess (ec, ff.ElementType);
-                               }
-                       }
-                       return (new IndexerAccess (this, loc)).Resolve (ec);
+                       return res.Resolve (ec);
                }
 
                public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
@@ -7699,16 +7879,12 @@ namespace Mono.CSharp {
                                return null;
 
                        type = Expr.Type;
-                       if (type.IsArray)
-                               return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
-
-                       if (type.IsPointer)
-                               return MakePointerAccess (ec, type);
 
-                       if (Expr.eclass != ExprClass.Variable && TypeManager.IsStruct (type))
-                               Error_CannotModifyIntermediateExpressionValue (ec);
+                       var res = CreateAccessExpression (ec);
+                       if (res == null)
+                               return null;
 
-                       return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
+                       return res.ResolveLValue (ec, right_side);
                }
                
                public override void Emit (EmitContext ec)
@@ -7903,14 +8079,16 @@ namespace Mono.CSharp {
                        ec.EmitArrayAddress (ac);
                }
 
-#if NET_4_0
-               public SLE.Expression MakeAssignExpression (BuilderContext ctx)
+               public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
                {
+#if NET_4_0
                        return SLE.Expression.ArrayAccess (
                                ea.Expr.MakeExpression (ctx),
                                Arguments.MakeExpression (ea.Arguments, ctx));
-               }
+#else
+                       throw new NotImplementedException ();
 #endif
+               }
 
                public override SLE.Expression MakeExpression (BuilderContext ctx)
                {
@@ -7920,264 +8098,65 @@ namespace Mono.CSharp {
                }
        }
 
-       /// <summary>
-       ///   Expressions that represent an indexer call.
-       /// </summary>
-       public class IndexerAccess : Expression, IDynamicAssign
+       //
+       // Indexer access expression
+       //
+       class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
        {
-               class IndexerMethodGroupExpr : MethodGroupExpr
-               {
-                       IEnumerable<IndexerSpec> candidates;
-
-                       public IndexerMethodGroupExpr (IEnumerable<IndexerSpec> indexers, Location loc)
-                               : base (FilterAccessors (indexers).ToList (), null, loc)
-                       {
-                               candidates = indexers;
-                       }
-
-                       public IndexerSpec BestIndexer ()
-                       {
-                               return MemberCache.FindIndexers (BestCandidate.DeclaringType, BindingRestriction.None).
-                                       Where (l => 
-                                               (l.HasGet && l.Get.MemberDefinition == BestCandidate.MemberDefinition) ||
-                                               (l.HasSet && l.Set.MemberDefinition == BestCandidate.MemberDefinition)).First ();
-                       }
-
-                       static IEnumerable<MemberSpec> FilterAccessors (IEnumerable<IndexerSpec> indexers)
-                       {
-                               foreach (IndexerSpec i in indexers) {
-                                       if (i.HasGet)
-                                               yield return i.Get;
-                                       else
-                                               yield return i.Set;
-                               }
-                       }
-
-                       protected override IList<MemberSpec> GetBaseTypeMethods (ResolveContext rc, TypeSpec type)
-                       {
-                               candidates = GetIndexersForType (type);
-                               if (candidates == null)
-                                       return null;
-
-                               return FilterAccessors (candidates).ToList ();
-                       }
-
-                       public override string Name {
-                               get {
-                                       return "this";
-                               }
-                       }
-
-                       protected override int GetApplicableParametersCount (MethodSpec method, AParametersCollection 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.
-                               //
-                               
-                               if (method.Name [0] == 'g')
-                                       return parameters.Count;
-
-                               return parameters.Count - 1;
-                       }
-               }
-
-               //
-               // Points to our "data" repository
-               //
-               IndexerSpec spec;
-               bool is_base_indexer;
-               bool prepared;
-               LocalTemporary temp;
                LocalTemporary prepared_value;
-               Expression set_expr;
-
-               protected TypeSpec indexer_type;
-               protected TypeSpec current_type;
-               protected Expression instance_expr;
-               protected Arguments arguments;
+               IList<MemberSpec> indexers;
+               Arguments arguments;
                
-               public IndexerAccess (ElementAccess ea, Location loc)
-                       : this (ea.Expr, false, loc)
+               public IndexerExpr (IList<MemberSpec> indexers, ElementAccess ea)
+                       : base (ea.Location)
                {
+                       this.indexers = indexers;
+                       this.InstanceExpression = ea.Expr;
                        this.arguments = ea.Arguments;
                }
 
-               protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
-                                        Location loc)
-               {
-                       this.instance_expr = instance_expr;
-                       this.is_base_indexer = is_base_indexer;
-                       this.loc = loc;
-               }
-
-               static string GetAccessorName (bool isSet)
-               {
-                       return isSet ? "set" : "get";
-               }
-
-               public override Expression CreateExpressionTree (ResolveContext ec)
-               {
-                       Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
-                               instance_expr.CreateExpressionTree (ec),
-                               new TypeOfMethod (spec.Get, loc));
-
-                       return CreateExpressionFactoryCall (ec, "Call", args);
-               }
-
-               static IEnumerable<IndexerSpec> GetIndexersForType (TypeSpec lookup_type)
-               {
-                       return MemberCache.FindIndexers (lookup_type, BindingRestriction.AccessibleOnly | BindingRestriction.NoOverrides);
-               }
-
-               protected virtual void CommonResolve (ResolveContext ec)
-               {
-                       indexer_type = instance_expr.Type;
-                       current_type = ec.CurrentType;
-               }
-
-               protected override Expression DoResolve (ResolveContext ec)
-               {
-                       return ResolveAccessor (ec, null);
-               }
-
-               public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
-               {
-                       if (right_side == EmptyExpression.OutAccess.Instance) {
-                               right_side.DoResolveLValue (ec, this);
-                               return null;
-                       }
-
-                       // if the indexer returns a value type, and we try to set a field in it
-                       if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
-                               Error_CannotModifyIntermediateExpressionValue (ec);
+               #region Properties
+               protected override TypeSpec DeclaringType {
+                       get {
+                               return best_candidate.DeclaringType;
                        }
-
-                       return ResolveAccessor (ec, right_side);
                }
 
-               Expression ResolveAccessor (ResolveContext ec, Expression right_side)
-               {
-                       CommonResolve (ec);
-
-                       bool dynamic;
-
-                       arguments.Resolve (ec, out dynamic);
-
-                       if (indexer_type == InternalType.Dynamic) {
-                               dynamic = true;
-                       } else {
-                               var ilist = GetIndexersForType (indexer_type);
-                               if (ilist == null) {
-                                       ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
-                                                         TypeManager.CSharpName (indexer_type));
-                                       return null;
-                               }
-
-                               var mg = new IndexerMethodGroupExpr (ilist, loc) {
-                                       InstanceExpression = instance_expr
-                               };
-
-                               if (is_base_indexer)
-                                       mg.QueriedBaseType = current_type;
-
-                               mg = mg.OverloadResolve (ec, ref arguments, false, loc) as IndexerMethodGroupExpr;
-                               if (mg == null)
-                                       return null;
-
-                               if (!dynamic)
-                                       spec = mg.BestIndexer ();
-                       }
-
-                       if (dynamic) {
-                               Arguments args = new Arguments (arguments.Count + 1);
-                               if (is_base_indexer) {
-                                       ec.Report.Error (1972, loc, "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
-                               } else {
-                                       args.Add (new Argument (instance_expr));
-                               }
-                               args.AddRange (arguments);
-
-                               var expr = new DynamicIndexBinder (args, loc);
-                               if (right_side != null)
-                                       return expr.ResolveLValue (ec, right_side);
-
-                               return expr.Resolve (ec);
-                       }
-
-                       type = spec.MemberType;
-                       if (type.IsPointer && !ec.IsUnsafe)
-                               UnsafeError (ec, loc);
-
-                       MethodSpec accessor;
-                       if (right_side == null) {
-                               accessor = spec.Get;
-                       } else {
-                               accessor = spec.Set;
-                               if (!spec.HasSet && spec.HasGet) {
-                                       ec.Report.SymbolRelatedToPreviousError (spec);
-                                       ec.Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
-                                               spec.GetSignatureForError ());
-                                       return null;
-                               }
-
-                               set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
-                       }
-
-                       if (accessor == null || accessor.Kind == MemberKind.FakeMethod) {
-                               ec.Report.SymbolRelatedToPreviousError (spec);
-                               ec.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
-                                       spec.GetSignatureForError (), GetAccessorName (right_side != null));
-                               return null;
+               public override bool IsInstance {
+                       get {
+                               return true;
                        }
+               }
 
-                       //
-                       // Only base will allow this invocation to happen.
-                       //
-                       if (spec.IsAbstract && this is BaseIndexerAccess) {
-                               Error_CannotCallAbstractBase (ec, spec.GetSignatureForError ());
+               public override bool IsStatic {
+                       get {
+                               return false;
                        }
+               }
 
-                       bool must_do_cs1540_check;
-                       if (!IsMemberAccessible (ec.CurrentType, accessor, out must_do_cs1540_check)) {
-                               if (spec.HasDifferentAccessibility) {
-                                       ec.Report.SymbolRelatedToPreviousError (accessor);
-                                       ec.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
-                                               TypeManager.GetFullNameSignature (spec), GetAccessorName (right_side != null));
-                               } else {
-                                       ec.Report.SymbolRelatedToPreviousError (spec);
-                                       ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (spec), ec.Report);
-                               }
+               public override string Name {
+                       get {
+                               return "this";
                        }
+               }
 
-                       instance_expr.CheckMarshalByRefAccess (ec);
+               #endregion
 
-                       if (must_do_cs1540_check && (instance_expr != EmptyExpression.Null) &&
-                           !TypeManager.IsInstantiationOfSameGenericType (instance_expr.Type, ec.CurrentType) &&
-                           !TypeManager.IsNestedChildOf (ec.CurrentType, instance_expr.Type) &&
-                           !TypeManager.IsSubclassOf (instance_expr.Type, ec.CurrentType)) {
-                               ec.Report.SymbolRelatedToPreviousError (accessor);
-                               Error_CannotAccessProtected (ec, loc, spec, instance_expr.Type, ec.CurrentType);
-                               return null;
-                       }
+               public override Expression CreateExpressionTree (ResolveContext ec)
+               {
+                       Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
+                               InstanceExpression.CreateExpressionTree (ec),
+                               new TypeOfMethod (Getter, loc));
 
-                       eclass = ExprClass.IndexerAccess;
-                       return this;
+                       return CreateExpressionFactoryCall (ec, "Call", args);
                }
 
-               public override void Emit (EmitContext ec)
-               {
-                       Emit (ec, false);
-               }
-               
-               public void Emit (EmitContext ec, bool leave_copy)
+               public override void Emit (EmitContext ec, bool leave_copy)
                {
                        if (prepared) {
                                prepared_value.Emit (ec);
                        } else {
-                               Invocation.EmitCall (ec, is_base_indexer, instance_expr, spec.Get,
-                                       arguments, loc, false, false);
+                               Invocation.EmitCall (ec, InstanceExpression, Getter, arguments, loc, false, false);
                        }
 
                        if (leave_copy) {
@@ -8187,18 +8166,13 @@ namespace Mono.CSharp {
                        }
                }
                
-               //
-               // source is ignored, because we already have a copy of it from the
-               // LValue resolution and we have already constructed a pre-cached
-               // version of the arguments (ea.set_arguments);
-               //
-               public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
+               public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
                {
                        prepared = prepare_for_load;
-                       Expression value = set_expr;
+                       Expression value = source;
 
                        if (prepared) {
-                               Invocation.EmitCall (ec, is_base_indexer, instance_expr, spec.Get,
+                               Invocation.EmitCall (ec, InstanceExpression, Getter,
                                        arguments, loc, true, false);
 
                                prepared_value = new LocalTemporary (type);
@@ -8221,190 +8195,171 @@ namespace Mono.CSharp {
                        if (!prepared)
                                arguments.Add (new Argument (value));
 
-                       Invocation.EmitCall (ec, is_base_indexer, instance_expr, spec.Set, arguments, loc, false, prepared);
+                       Invocation.EmitCall (ec, InstanceExpression, Setter, arguments, loc, false, prepared);
                        
                        if (temp != null) {
                                temp.Emit (ec);
                                temp.Release (ec);
                        }
                }
-               
+
                public override string GetSignatureForError ()
                {
-                       return spec.GetSignatureForError ();
+                       return best_candidate.GetSignatureForError ();
                }
-
-#if NET_4_0
-               public SLE.Expression MakeAssignExpression (BuilderContext ctx)
+               
+               public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
                {
-                       var value = new[] { set_expr.MakeExpression (ctx) };
+                       var value = new[] { source.MakeExpression (ctx) };
                        var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
-
+#if NET_4_0
                        return SLE.Expression.Block (
-                                       SLE.Expression.Call (instance_expr.MakeExpression (ctx), (MethodInfo) spec.Set.GetMetaInfo (), args),
+                                       SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
                                        value [0]);
-               }
+#else
+                       return args.First ();
 #endif
+               }
 
                public override SLE.Expression MakeExpression (BuilderContext ctx)
                {
                        var args = Arguments.MakeExpression (arguments, ctx);
-                       return SLE.Expression.Call (instance_expr.MakeExpression (ctx), (MethodInfo) spec.Get.GetMetaInfo (), args);
+                       return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
                }
 
-               protected override void CloneTo (CloneContext clonectx, Expression t)
+               protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
                {
-                       IndexerAccess target = (IndexerAccess) t;
+                       if (best_candidate != null)
+                               return this;
 
-                       if (arguments != null)
-                               target.arguments = arguments.Clone (clonectx);
+                       eclass = ExprClass.IndexerAccess;
 
-                       if (instance_expr != null)
-                               target.instance_expr = instance_expr.Clone (clonectx);
-               }
-       }
+                       bool dynamic;
+                       arguments.Resolve (rc, out dynamic);
 
-       /// <summary>
-       ///   The base operator for method names
-       /// </summary>
-       public class BaseAccess : Expression {
-               public readonly string Identifier;
-               TypeArguments args;
+                       if (indexers == null && InstanceExpression.Type == InternalType.Dynamic) {
+                               dynamic = true;
+                       } else {
+                               var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
+                               res.BaseMembersProvider = this;
+
+                               // TODO: Do I need 2 argument sets?
+                               best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
+                               if (best_candidate != null)
+                                       type = best_candidate.MemberType;
+                               else if (!res.BestCandidateIsDynamic)
+                                       return null;
+                       }
 
-               public BaseAccess (string member, Location l)
-               {
-                       this.Identifier = member;
-                       loc = l;
-               }
+                       //
+                       // It has dynamic arguments
+                       //
+                       if (dynamic) {
+                               Arguments args = new Arguments (arguments.Count + 1);
+                               if (IsBase) {
+                                       rc.Report.Error (1972, loc,
+                                               "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
+                               } else {
+                                       args.Add (new Argument (InstanceExpression));
+                               }
+                               args.AddRange (arguments);
 
-               public BaseAccess (string member, TypeArguments args, Location l)
-                       : this (member, l)
-               {
-                       this.args = args;
+                               best_candidate = null;
+                               return new DynamicIndexBinder (args, loc);
+                       }
+
+                       ResolveInstanceExpression (rc);
+                       CheckProtectedMemberAccess (rc, best_candidate);
+                       return this;
                }
 
-               public override Expression CreateExpressionTree (ResolveContext ec)
+               protected override void CloneTo (CloneContext clonectx, Expression t)
                {
-                       throw new NotSupportedException ("ET");
+                       IndexerExpr target = (IndexerExpr) t;
+
+                       if (arguments != null)
+                               target.arguments = arguments.Clone (clonectx);
                }
 
-               protected override Expression DoResolve (ResolveContext ec)
+               public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
                {
-                       Expression c = CommonResolve (ec);
+                       Error_TypeArgumentsCannotBeUsed (ec.Report, "indexer", GetSignatureForError (), loc);
+               }
 
-                       if (c == null)
-                               return null;
+               #region IBaseMembersProvider Members
 
-                       //
-                       // MethodGroups use this opportunity to flag an error on lacking ()
-                       //
-                       if (!(c is MethodGroupExpr))
-                               return c.Resolve (ec);
-                       return c;
+               IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
+               {
+                       return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
                }
 
-               public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
+               MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
                {
-                       Expression c = CommonResolve (ec);
-
-                       if (c == null)
-                               return null;
+                       return null;
+               }
 
-                       //
-                       // MethodGroups use this opportunity to flag an error on lacking ()
-                       //
-                       if (! (c is MethodGroupExpr))
-                               return c.DoResolveLValue (ec, right_side);
+               #endregion
+       }
 
-                       return c;
+       //
+       // A base access expression
+       //
+       public class BaseThis : This
+       {
+               public BaseThis (Location loc)
+                       : base (loc)
+               {
                }
 
-               Expression CommonResolve (ResolveContext ec)
+               public BaseThis (TypeSpec type, Location loc)
+                       : base (loc)
                {
-                       Expression member_lookup;
-                       TypeSpec current_type = ec.CurrentType;
-                       TypeSpec base_type = current_type.BaseType;
-
-                       if (!This.IsThisAvailable (ec, false)) {
-                               if (ec.IsStatic) {
-                                       ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
-                               } else {
-                                       ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
-                               }
-                               return null;
-                       }
-
-                       var arity = args == null ? -1 : args.Count;
-                       member_lookup = MemberLookup (ec.Compiler, ec.CurrentType, null, base_type, Identifier, arity,
-                                                     MemberKind.All, BindingRestriction.AccessibleOnly | BindingRestriction.NoOverrides, loc);
-                       if (member_lookup == null) {
-                               Error_MemberLookupFailed (ec, ec.CurrentType, base_type, base_type, Identifier, arity,
-                                       null, MemberKind.All, BindingRestriction.AccessibleOnly);
-                               return null;
-                       }
+                       this.type = type;
+                       eclass = ExprClass.Variable;
+               }
 
-                       MemberExpr me = member_lookup as MemberExpr;
-                       if (me == null){
-                               if (member_lookup is TypeExpression){
-                                       ec.Report.Error (582, loc, "{0}: Can not reference a type through an expression, try `{1}' instead",
-                                                        Identifier, member_lookup.GetSignatureForError ());
-                               } else {
-                                       ec.Report.Error (582, loc, "{0}: Can not reference a {1} through an expression", 
-                                                        Identifier, member_lookup.ExprClassName);
-                               }
-                               
-                               return null;
-                       }
-                       
-                       me.QueriedBaseType = base_type;
+               #region Properties
 
-                       if (args != null) {
-                               args.Resolve (ec);
-                               me.SetTypeArguments (ec, args);
+               public override string Name {
+                       get {
+                               return "base";
                        }
-
-                       return me;
                }
 
-               public override void Emit (EmitContext ec)
-               {
-                       throw new Exception ("Should never be called"); 
-               }
+               #endregion
 
-               protected override void CloneTo (CloneContext clonectx, Expression t)
+               public override Expression CreateExpressionTree (ResolveContext ec)
                {
-                       BaseAccess target = (BaseAccess) t;
-
-                       if (args != null)
-                               target.args = args.Clone ();
+                       ec.Report.Error (831, loc, "An expression tree may not contain a base access");
+                       return base.CreateExpressionTree (ec);
                }
-       }
 
-       /// <summary>
-       ///   The base indexer operator
-       /// </summary>
-       public class BaseIndexerAccess : IndexerAccess {
-               public BaseIndexerAccess (Arguments args, Location loc)
-                       : base (null, true, loc)
+               public override void Emit (EmitContext ec)
                {
-                       this.arguments = args;
+                       base.Emit (ec);
+
+                       if (ec.CurrentType.IsStruct) {
+                               ec.Emit (OpCodes.Ldobj, ec.CurrentType);
+                               ec.Emit (OpCodes.Box, ec.CurrentType);
+                       }
                }
 
-               protected override void CommonResolve (ResolveContext ec)
+               protected override void Error_ThisNotAvailable (ResolveContext ec)
                {
-                       instance_expr = ec.GetThis (loc);
-
-                       current_type = ec.CurrentType.BaseType;
-                       indexer_type = current_type;
+                       if (ec.IsStatic) {
+                               ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
+                       } else {
+                               ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
+                       }
                }
 
-               public override Expression CreateExpressionTree (ResolveContext ec)
+               public override void ResolveBase (ResolveContext ec)
                {
-                       MemberExpr.Error_BaseAccessInExpressionTree (ec, loc);
-                       return base.CreateExpressionTree (ec);
+                       base.ResolveBase (ec);
+                       type = ec.CurrentType.BaseType;
                }
        }
-       
+
        /// <summary>
        ///   This class exists solely to pass the Type around and to be a dummy
        ///   that can be passed to the conversion functions (this is used by
@@ -8434,6 +8389,9 @@ namespace Mono.CSharp {
                public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
                public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
                public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
+               public static readonly EmptyExpression EventAddition = new EmptyExpression ();
+               public static readonly EmptyExpression EventSubtraction = new EmptyExpression ();
+               public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
 
                static EmptyExpression temp = new EmptyExpression ();
                public static EmptyExpression Grab ()
@@ -8687,8 +8645,10 @@ namespace Mono.CSharp {
                                        UnsafeError (ec.Compiler.Report, loc);
                                }
 
-                               type = PointerContainer.MakeType (type);
-                               single_spec = single_spec.Next;
+                               do {
+                                       type = PointerContainer.MakeType (type);
+                                       single_spec = single_spec.Next;
+                               } while (single_spec != null && single_spec.IsPointer);
                        }
 
                        if (single_spec != null && single_spec.Dimension > 0) {
@@ -8929,15 +8889,48 @@ namespace Mono.CSharp {
                {
                        if (source == null)
                                return EmptyExpressionStatement.Instance;
-                       
-                       MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
-                               Name, 0, MemberKind.Field | MemberKind.Property, BindingRestriction.AccessibleOnly | BindingRestriction.InstanceOnly, loc) as MemberExpr;
 
-                       if (me == null)
-                               return null;
+                       var t = ec.CurrentInitializerVariable.Type;
+                       if (t == InternalType.Dynamic) {
+                               Arguments args = new Arguments (1);
+                               args.Add (new Argument (ec.CurrentInitializerVariable));
+                               target = new DynamicMemberBinder (Name, args, loc);
+                       } else {
+
+                               var member = MemberLookup (ec, ec.CurrentType, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
+                               if (member == null) {
+                                       member = Expression.MemberLookup (null, ec.CurrentType, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
+
+                                       if (member != null) {
+                                               // TODO: ec.Report.SymbolRelatedToPreviousError (member);
+                                               ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
+                                               return null;
+                                       }
+                               }
+
+                               if (member == null) {
+                                       Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
+                                       return null;
+                               }
+
+                               if (!(member is PropertyExpr || member is FieldExpr)) {
+                                       ec.Report.Error (1913, loc,
+                                               "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
+                                               member.GetSignatureForError ());
+
+                                       return null;
+                               }
+
+                               var me = member as MemberExpr;
+                               if (me.IsStatic) {
+                                       ec.Report.Error (1914, loc,
+                                               "Static field or property `{0}' cannot be assigned in an object initializer",
+                                               me.GetSignatureForError ());
+                               }
 
-                       target = me;
-                       me.InstanceExpression = ec.CurrentInitializerVariable;
+                               target = me;
+                               me.InstanceExpression = ec.CurrentInitializerVariable;
+                       }
 
                        if (source is CollectionOrObjectInitializers) {
                                Expression previous = ec.CurrentInitializerVariable;
@@ -8952,33 +8945,9 @@ namespace Mono.CSharp {
                                return this;
                        }
 
-                       Expression expr = base.DoResolve (ec);
-                       if (expr == null)
-                               return null;
-
-                       //
-                       // Ignore field initializers with default value
-                       //
-                       Constant c = source as Constant;
-                       if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
-                               return EmptyExpressionStatement.Instance.Resolve (ec);
-
-                       return expr;
-               }
-
-               protected override MemberExpr Error_MemberLookupFailed (ResolveContext ec, TypeSpec type, IList<MemberSpec> members)
-               {
-                       var member = members.First ();
-                       if (member.Kind != MemberKind.Property && member.Kind != MemberKind.Field)
-                               ec.Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
-                                       "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
-                       else
-                               ec.Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
-                                       TypeManager.GetFullNameSignature (member));
-
-                       return null;
+                       return base.DoResolve (ec);
                }
-               
+       
                public override void EmitStatement (EmitContext ec)
                {
                        if (source is CollectionOrObjectInitializers)
@@ -9116,7 +9085,7 @@ namespace Mono.CSharp {
                {
                        List<string> element_names = null;
                        for (int i = 0; i < initializers.Count; ++i) {
-                               Expression initializer = (Expression) initializers [i];
+                               Expression initializer = initializers [i];
                                ElementInitializer element_initializer = initializer as ElementInitializer;
 
                                if (i == 0) {
@@ -9127,7 +9096,9 @@ namespace Mono.CSharp {
                                                initializer.Resolve (ec);
                                                throw new InternalErrorException ("This line should never be reached");
                                        } else {
-                                               if (!ec.CurrentInitializerVariable.Type.ImplementsInterface (TypeManager.ienumerable_type)) {
+                                               var t = ec.CurrentInitializerVariable.Type;
+                                               // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
+                                               if (!t.ImplementsInterface (TypeManager.ienumerable_type, false) && t != InternalType.Dynamic) {
                                                        ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
                                                                "object initializer because type `{1}' does not implement `{2}' interface",
                                                                ec.CurrentInitializerVariable.GetSignatureForError (),
@@ -9243,7 +9214,7 @@ namespace Mono.CSharp {
                CollectionOrObjectInitializers initializers;
                IMemoryLocation instance;
 
-               public NewInitialize (Expression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
+               public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
                        : base (requested_type, arguments, l)
                {
                        this.initializers = initializers;
@@ -9328,12 +9299,6 @@ namespace Mono.CSharp {
 
                        return left_on_stack;
                }
-
-               public override bool HasInitializer {
-                       get {
-                               return !initializers.IsEmpty;
-                       }
-               }
        }
 
        public class NewAnonymousType : New
@@ -9393,12 +9358,12 @@ namespace Mono.CSharp {
                        foreach (Property p in anonymous_type.Properties)
                                init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
 
-                       var ctor_args = new ArrayInitializer (Arguments.Count, loc);
-                       foreach (Argument a in Arguments)
+                       var ctor_args = new ArrayInitializer (arguments.Count, loc);
+                       foreach (Argument a in arguments)
                                ctor_args.Add (a.CreateExpressionTree (ec));
 
                        Arguments args = new Arguments (3);
-                       args.Add (new Argument (method.CreateExpressionTree (ec)));
+                       args.Add (new Argument (new TypeOfMethod (method, loc)));
                        args.Add (new Argument (new ArrayCreation (TypeManager.expression_type_expr, ctor_args, loc)));
                        args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
 
@@ -9419,7 +9384,7 @@ namespace Mono.CSharp {
                        }
 
                        bool error = false;
-                       Arguments = new Arguments (parameters.Count);
+                       arguments = new Arguments (parameters.Count);
                        TypeExpression [] t_args = new TypeExpression [parameters.Count];
                        for (int i = 0; i < parameters.Count; ++i) {
                                Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
@@ -9428,7 +9393,7 @@ namespace Mono.CSharp {
                                        continue;
                                }
 
-                               Arguments.Add (new Argument (e));
+                               arguments.Add (new Argument (e));
                                t_args [i] = new TypeExpression (e.Type, e.Location);
                        }
 
@@ -9485,7 +9450,7 @@ namespace Mono.CSharp {
                        }
 
                        type = e.Type;
-                       if (type == TypeManager.void_type || type == TypeManager.null_type ||
+                       if (type == TypeManager.void_type || type == InternalType.Null ||
                                type == InternalType.AnonymousMethod || type.IsPointer) {
                                Error_InvalidInitializer (ec, e.GetSignatureForError ());
                                return null;