2008-09-17 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / expression.cs
index 496cb7153ce5cb730ae6e583bbbece288a215191..b3a88cccca53b401678513fbbfe2904bc8d030a2 100644 (file)
@@ -3,7 +3,7 @@
 //
 // Author:
 //   Miguel de Icaza (miguel@ximian.com)
-//   Marek Safar (marek.safar@seznam.cz)
+//   Marek Safar (marek.safar@gmail.com)
 //
 // Copyright 2001, 2002, 2003 Ximian, Inc.
 // Copyright 2003-2008 Novell, Inc.
@@ -54,6 +54,11 @@ namespace Mono.CSharp {
                        return CreateExpressionFactoryCall ("Call", args);
                }
 
+               protected override void CloneTo (CloneContext context, Expression target)
+               {
+                       // Nothing to clone
+               }
+               
                public override Expression DoResolve (EmitContext ec)
                {
                        //
@@ -67,31 +72,17 @@ namespace Mono.CSharp {
                        mg.EmitCall (ec, arguments);
                }
 
-               [Obsolete ("It may not be compatible with expression trees")]
-               static public UserOperatorCall MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
-                                                        Expression e, Location loc)
-               {
-                       ArrayList args;
-                       
-                       args = new ArrayList (1);
-                       Argument a = new Argument (e, Argument.AType.Expression);
-
-                        // We need to resolve the arguments before sending them in !
-                        if (!a.Resolve (ec, loc))
-                                return null;
-
-                        args.Add (a);
-                       mg = mg.OverloadResolve (ec, ref args, false, loc);
-
-                       if (mg == null)
-                               return null;
-
-                       return new UserOperatorCall (mg, args, null, loc);
-               }
-
                public MethodGroupExpr Method {
                        get { return mg; }
                }
+
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       foreach (Argument a in arguments)
+                               a.Expr.MutateHoistedGenericType (storey);
+
+                       mg.MutateHoistedGenericType (storey);
+               }
        }
 
        public class ParenthesizedExpression : Expression
@@ -101,6 +92,12 @@ namespace Mono.CSharp {
                public ParenthesizedExpression (Expression expr)
                {
                        this.Expr = expr;
+                       this.loc = expr.Location;
+               }
+
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       throw new NotSupportedException ("ET");
                }
 
                public override Expression DoResolve (EmitContext ec)
@@ -114,13 +111,6 @@ namespace Mono.CSharp {
                        throw new Exception ("Should not happen");
                }
 
-               public override Location Location
-               {
-                       get {
-                               return Expr.Location;
-                       }
-               }
-
                protected override void CloneTo (CloneContext clonectx, Expression t)
                {
                        ParenthesizedExpression target = (ParenthesizedExpression) t;
@@ -138,11 +128,11 @@ namespace Mono.CSharp {
                        AddressOf,  TOP
                }
 
-               public static readonly string [] oper_names;
                static Type [] [] predefined_operators;
 
                public readonly Operator Oper;
                public Expression Expr;
+               Expression enum_conversion;
 
                public Unary (Operator op, Expression expr, Location loc)
                {
@@ -151,23 +141,15 @@ namespace Mono.CSharp {
                        this.loc = loc;
                }
 
-               static Unary ()
-               {
-                       oper_names = new string [(int)Operator.TOP];
-
-                       oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
-                       oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
-                       oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
-                       oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
-                       oper_names [(int) Operator.AddressOf] = "op_AddressOf";
-               }
-
                // <summary>
                //   This routine will attempt to simplify the unary expression when the
                //   argument is a constant.
                // </summary>
                Constant TryReduceConstant (EmitContext ec, Constant e)
                {
+                       if (e is EmptyConstantCast)
+                               return TryReduceConstant (ec, ((EmptyConstantCast) e).child);
+                       
                        if (e is SideEffectConstant) {
                                Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
                                return r == null ? null : new SideEffectConstant (r, e, r.Location);
@@ -321,6 +303,8 @@ namespace Mono.CSharp {
 
                protected Expression ResolveOperator (EmitContext ec, Expression expr)
                {
+                       eclass = ExprClass.Value;
+
                        if (predefined_operators == null)
                                CreatePredefinedOperatorsTable ();
 
@@ -343,19 +327,25 @@ namespace Mono.CSharp {
                        //
                        // E operator ~(E x);
                        //
-                       if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type)) {
-                               best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, TypeManager.GetEnumUnderlyingType (expr_type)));
-                               if (best_expr == null)
-                                       return null;
-
-                               Expr = EmptyCast.Create (best_expr, expr_type);
-                               type = Expr.Type;
-                               return this;
-                       }
+                       if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
+                               return ResolveEnumOperator (ec, expr);
 
                        return ResolveUserType (ec, expr);
                }
 
+               protected virtual Expression ResolveEnumOperator (EmitContext ec, Expression expr)
+               {
+                       Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
+                       Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
+                       if (best_expr == null)
+                               return null;
+
+                       Expr = best_expr;
+                       enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
+                       type = expr.Type;
+                       return EmptyCast.Create (this, type);
+               }
+
                public override Expression CreateExpressionTree (EmitContext ec)
                {
                        return CreateExpressionTree (ec, null);
@@ -365,6 +355,9 @@ namespace Mono.CSharp {
                {
                        string method_name;
                        switch (Oper) {
+                       case Operator.AddressOf:
+                               Error_PointerInsideExpressionTree ();
+                               return null;
                        case Operator.UnaryNegation:
                                if (ec.CheckState && user_op == null && !IsFloat (type))
                                        method_name = "NegateChecked";
@@ -449,16 +442,7 @@ namespace Mono.CSharp {
 
                public override Expression DoResolve (EmitContext ec)
                {
-                       eclass = ExprClass.Value;
-
                        if (Oper == Operator.AddressOf) {
-                               Expr = Expr.DoResolveLValue (ec, new EmptyExpression ());
-
-                               if (Expr == null || Expr.eclass != ExprClass.Variable){
-                                       Error (211, "Cannot take the address of the given expression");
-                                       return null;
-                               }
-
                                return ResolveAddressOf (ec);
                        }
 
@@ -544,6 +528,12 @@ namespace Mono.CSharp {
                                throw new Exception ("This should not happen: Operator = "
                                                     + Oper.ToString ());
                        }
+
+                       //
+                       // Same trick as in Binary expression
+                       //
+                       if (enum_conversion != null)
+                               enum_conversion.Emit (ec);
                }
 
                public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
@@ -591,10 +581,20 @@ namespace Mono.CSharp {
                        throw new NotImplementedException (oper.ToString ());
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       type = storey.MutateType (type);
+                       Expr.MutateHoistedGenericType (storey);
+               }
+
                Expression ResolveAddressOf (EmitContext ec)
                {
-                       if (!ec.InUnsafe) {
+                       if (!ec.InUnsafe)
                                UnsafeError (loc);
+
+                       Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
+                       if (Expr == null || Expr.eclass != ExprClass.Variable) {
+                               Error (211, "Cannot take the address of the given expression");
                                return null;
                        }
 
@@ -602,43 +602,39 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       IVariable variable = Expr as IVariable;
-                       bool is_fixed = variable != null && variable.VerifyFixed ();
+                       IVariableReference vr = Expr as IVariableReference;
+                       bool is_fixed;
+                       if (vr != null) {
+                               VariableInfo vi = vr.VariableInfo;
+                               if (vi != null) {
+                                       if (vi.LocalInfo != null)
+                                               vi.LocalInfo.Used = true;
 
-                       if (!ec.InFixedInitializer && !is_fixed) {
-                               Error (212, "You can only take the address of unfixed expression inside " +
-                                          "of a fixed statement initializer");
-                               return null;
-                       }
+                                       //
+                                       // A variable is considered definitely assigned if you take its address.
+                                       //
+                                       vi.SetAssigned (ec);
+                               }
 
-                       if (ec.InFixedInitializer && is_fixed) {
-                               Error (213, "You cannot use the fixed statement to take the address of an already fixed expression");
-                               return null;
-                       }
+                               is_fixed = vr.IsFixedVariable;
+                               vr.SetHasAddressTaken ();
 
-                       LocalVariableReference lr = Expr as LocalVariableReference;
-                       if (lr != null) {
-                               if (lr.local_info.IsCaptured) {
-                                       AnonymousMethod.Error_AddressOfCapturedVar (lr.Name, loc);
-                                       return null;
+                               if (vr.IsHoisted) {
+                                       AnonymousMethodExpression.Error_AddressOfCapturedVar (vr, loc);
                                }
-                               lr.local_info.AddressTaken = true;
-                               lr.local_info.Used = true;
-                       }
-
-                       ParameterReference pr = Expr as ParameterReference;
-                       if ((pr != null) && pr.Parameter.IsCaptured) {
-                               AnonymousMethod.Error_AddressOfCapturedVar (pr.Name, loc);
-                               return null;
+                       } else {
+                               //
+                               // A pointer-indirection is always fixed
+                               //
+                               is_fixed = Expr is Indirection;
                        }
 
-                       // According to the specs, a variable is considered definitely assigned if you take
-                       // its address.
-                       if ((variable != null) && (variable.VariableInfo != null)) {
-                               variable.VariableInfo.SetAssigned (ec);
+                       if (!is_fixed && !ec.InFixedInitializer) {
+                               Error (212, "You can only take the address of unfixed expression inside of a fixed statement initializer");
                        }
 
                        type = TypeManager.GetPointerType (Expr.Type);
+                       eclass = ExprClass.Value;
                        return this;
                }
 
@@ -659,7 +655,21 @@ namespace Mono.CSharp {
                //
                protected virtual Expression ResolveUserOperator (EmitContext ec, Expression expr)
                {
-                       string op_name = oper_names [(int) Oper];
+                       CSharp.Operator.OpType op_type;
+                       switch (Oper) {
+                       case Operator.LogicalNot:
+                               op_type = CSharp.Operator.OpType.LogicalNot; break;
+                       case Operator.OnesComplement:
+                               op_type = CSharp.Operator.OpType.OnesComplement; break;
+                       case Operator.UnaryNegation:
+                               op_type = CSharp.Operator.OpType.UnaryNegation; break;
+                       case Operator.UnaryPlus:
+                               op_type = CSharp.Operator.OpType.UnaryPlus; break;
+                       default:
+                               throw new InternalErrorException (Oper.ToString ());
+                       }
+
+                       string op_name = CSharp.Operator.GetMetadataName (op_type);
                        MethodGroupExpr user_op = MemberLookup (ec.ContainerType, expr.Type, op_name, MemberTypes.Method, AllBindingFlags, expr.Location) as MethodGroupExpr;
                        if (user_op == null)
                                return null;
@@ -744,7 +754,7 @@ namespace Mono.CSharp {
        // after semantic analysis (this is so we can take the address
        // of an indirection).
        //
-       public class Indirection : Expression, IMemoryLocation, IAssignMethod, IVariable {
+       public class Indirection : Expression, IMemoryLocation, IAssignMethod {
                Expression expr;
                LocalTemporary temporary;
                bool prepared;
@@ -754,6 +764,18 @@ namespace Mono.CSharp {
                        this.expr = expr;
                        loc = l;
                }
+
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       Error_PointerInsideExpressionTree ();
+                       return null;
+               }
+               
+               protected override void CloneTo (CloneContext clonectx, Expression t)
+               {
+                       Indirection target = (Indirection) t;
+                       target.expr = expr.Clone (clonectx);
+               }               
                
                public override void Emit (EmitContext ec)
                {
@@ -821,29 +843,20 @@ namespace Mono.CSharp {
                                return null;
                        }
 
+                       if (expr.Type == TypeManager.void_ptr_type) {
+                               Error (242, "The operation in question is undefined on void pointers");
+                               return null;
+                       }
+
                        type = TypeManager.GetElementType (expr.Type);
                        eclass = ExprClass.Variable;
                        return this;
                }
-               
+
                public override string ToString ()
                {
                        return "*(" + expr + ")";
                }
-
-               #region IVariable Members
-
-               public VariableInfo VariableInfo {
-                       get { return null; }
-               }
-
-               public bool VerifyFixed ()
-               {
-                       // A pointer-indirection is always fixed.
-                       return true;
-               }
-
-               #endregion
        }
        
        /// <summary>
@@ -923,30 +936,37 @@ namespace Mono.CSharp {
 
                Expression ResolveOperator (EmitContext ec)
                {
-                       Type expr_type = expr.Type;
+                       type = expr.Type;
 
                        //
                        // Step 1: Perform Operator Overload location
                        //
-                       Expression mg;
+                       MethodGroupExpr mg;
                        string op_name;
                        
                        if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
-                               op_name = "op_Increment";
-                       else 
-                               op_name = "op_Decrement";
+                               op_name = Operator.GetMetadataName (Operator.OpType.Increment);
+                       else
+                               op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
 
-                       mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
+                       mg = MemberLookup (ec.ContainerType, type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
 
                        if (mg != null) {
-                               method = UserOperatorCall.MakeSimpleCall (
-                                       ec, (MethodGroupExpr) mg, expr, loc);
+                               ArrayList args = new ArrayList (1);
+                               args.Add (new Argument (expr, Argument.AType.Expression));
+                               mg = mg.OverloadResolve (ec, ref args, false, loc);
+                               if (mg == null)
+                                       return null;
+
+                               method = new UserOperatorCall (mg, args, null, loc);
+                               Convert.ImplicitConversionRequired (ec, method, type, loc);
+                               return this;
+                       }
 
-                               type = method.Type;
-                       } else if (!IsIncrementableNumber (expr_type)) {
+                       if (!IsIncrementableNumber (type)) {
                                Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
-                                      TypeManager.CSharpName (expr_type) + "'");
-                                  return null;
+                                          TypeManager.CSharpName (type) + "'");
+                               return null;
                        }
 
                        //
@@ -954,20 +974,10 @@ namespace Mono.CSharp {
                        // should be an expression that is classified as a variable,
                        // a property access or an indexer access
                        //
-                       type = expr_type;
-                       if (expr.eclass == ExprClass.Variable){
-                               LocalVariableReference var = expr as LocalVariableReference;
-                               if ((var != null) && var.IsReadOnly) {
-                                       Error (1604, "cannot assign to `" + var.Name + "' because it is readonly");
-                                       return null;
-                               }
-                       } else if (expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess){
-                               expr = expr.ResolveLValue (ec, this, Location);
-                               if (expr == null)
-                                       return null;
+                       if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
+                               expr = expr.ResolveLValue (ec, expr, Location);
                        } else {
                                Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
-                               return null;
                        }
 
                        return this;
@@ -1019,39 +1029,19 @@ namespace Mono.CSharp {
                                
                                if (n == 0)
                                        ig.Emit (OpCodes.Sizeof, et);
-                               else
+                               else {
                                        IntConstant.EmitInt (ig, n);
+                                       ig.Emit (OpCodes.Conv_I);
+                               }
                        } else 
                                ig.Emit (OpCodes.Ldc_I4_1);
 
                        //
                        // Now emit the operation
                        //
-                       if (ec.CheckState){
-                               if (t == TypeManager.int32_type ||
-                                   t == TypeManager.int64_type){
-                                       if ((mode & Mode.IsDecrement) != 0)
-                                               ig.Emit (OpCodes.Sub_Ovf);
-                                       else
-                                               ig.Emit (OpCodes.Add_Ovf);
-                               } else if (t == TypeManager.uint32_type ||
-                                          t == TypeManager.uint64_type){
-                                       if ((mode & Mode.IsDecrement) != 0)
-                                               ig.Emit (OpCodes.Sub_Ovf_Un);
-                                       else
-                                               ig.Emit (OpCodes.Add_Ovf_Un);
-                               } else {
-                                       if ((mode & Mode.IsDecrement) != 0)
-                                               ig.Emit (OpCodes.Sub_Ovf);
-                                       else
-                                               ig.Emit (OpCodes.Add_Ovf);
-                               }
-                       } else {
-                               if ((mode & Mode.IsDecrement) != 0)
-                                       ig.Emit (OpCodes.Sub);
-                               else
-                                       ig.Emit (OpCodes.Add);
-                       }
+
+                       Binary.Operator op = (mode & Mode.IsDecrement) != 0 ? Binary.Operator.Subtraction : Binary.Operator.Addition;
+                       Binary.EmitOperatorOpcode (ec, op, t);
 
                        if (t == TypeManager.sbyte_type){
                                if (ec.CheckState)
@@ -1152,6 +1142,11 @@ namespace Mono.CSharp {
                        expr = expr.Resolve (ec);
                        if (expr == null)
                                return null;
+
+                       if ((probe_type_expr.Type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
+                               Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
+                                       OperatorName);
+                       }
                        
                        if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
                                Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
@@ -1168,6 +1163,12 @@ namespace Mono.CSharp {
                        return this;
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       expr.MutateHoistedGenericType (storey);
+                       probe_type_expr.MutateHoistedGenericType (storey);
+               }
+
                protected abstract string OperatorName { get; }
 
                protected override void CloneTo (CloneContext clonectx, Expression t)
@@ -1184,6 +1185,8 @@ namespace Mono.CSharp {
        ///   Implementation of the `is' operator.
        /// </summary>
        public class Is : Probe {
+               Nullable.Unwrap expr_unwrap;
+
                public Is (Expression expr, Expression probe_type, Location l)
                        : base (expr, probe_type, l)
                {
@@ -1200,6 +1203,10 @@ namespace Mono.CSharp {
                public override void Emit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
+                       if (expr_unwrap != null) {
+                               expr_unwrap.EmitCheck (ec);
+                               return;
+                       }
 
                        expr.Emit (ec);
                        ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
@@ -1210,9 +1217,12 @@ namespace Mono.CSharp {
                public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
                {
                        ILGenerator ig = ec.ig;
-
-                       expr.Emit (ec);
-                       ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
+                       if (expr_unwrap != null) {
+                               expr_unwrap.EmitCheck (ec);
+                       } else {
+                               expr.Emit (ec);
+                               ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
+                       }                       
                        ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
                }
                
@@ -1236,14 +1246,14 @@ namespace Mono.CSharp {
                        Type d = expr.Type;
                        bool d_is_nullable = false;
 
-                       if (expr is Constant) {
-                               //
-                               // If E is a method group or the null literal, of if the type of E is a reference
-                               // type or a nullable type and the value of E is null, the result is false
-                               //
-                               if (expr.IsNull)
-                                       return CreateConstantResult (false);
-                       } else if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
+                       //
+                       // If E is a method group or the null literal, or if the type of E is a reference
+                       // type or a nullable type and the value of E is null, the result is false
+                       //
+                       if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
+                               return CreateConstantResult (false);
+
+                       if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
                                d = TypeManager.GetTypeArguments (d) [0];
                                d_is_nullable = true;
                        }
@@ -1262,8 +1272,10 @@ namespace Mono.CSharp {
                                        //
                                        // D and T are the same value types but D can be null
                                        //
-                                       if (d_is_nullable && !t_is_nullable)
-                                               return Nullable.HasValue.Create (expr, ec);
+                                       if (d_is_nullable && !t_is_nullable) {
+                                               expr_unwrap = Nullable.Unwrap.Create (expr, ec);
+                                               return this;
+                                       }
                                        
                                        //
                                        // The result is true if D and T are the same value types
@@ -1313,10 +1325,12 @@ namespace Mono.CSharp {
                                        return CreateConstantResult (false);
 
                                if (constraints.IsValueType && !d.IsValueType)
-                                       return CreateConstantResult (false);
+                                       return CreateConstantResult (TypeManager.IsEqual (d, t));
                        }
 
-                       expr = new BoxedCast (expr, d);
+                       if (!TypeManager.IsReferenceType (expr.Type))
+                               expr = new BoxedCast (expr, d);
+
                        return this;
 #else
                        return null;
@@ -1363,13 +1377,6 @@ namespace Mono.CSharp {
 #endif
                }
 
-               static void Error_CannotConvertType (Type source, Type target, Location loc)
-               {
-                       Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
-                               TypeManager.CSharpName (source),
-                               TypeManager.CSharpName (target));
-               }
-               
                public override Expression DoResolve (EmitContext ec)
                {
                        if (resolved_type == null) {
@@ -1383,38 +1390,19 @@ namespace Mono.CSharp {
                        eclass = ExprClass.Value;
                        Type etype = expr.Type;
 
-                       if (type.IsValueType && !TypeManager.IsNullableType (type)) {
-                               Report.Error (77, loc, "The `as' operator cannot be used with a non-nullable value type `{0}'",
-                                             TypeManager.CSharpName (type));
-                               return null;
-                       
-                       }
-
-#if GMCS_SOURCE
-                       //
-                       // If the type is a type parameter, ensure
-                       // that it is constrained by a class
-                       //
-                       TypeParameterExpr tpe = probe_type_expr as TypeParameterExpr;
-                       if (tpe != null){
-                               GenericConstraints constraints = tpe.TypeParameter.GenericConstraints;
-                               bool error = false;
-                               
-                               if (constraints == null)
-                                       error = true;
-                               else {
-                                       if (!constraints.HasClassConstraint)
-                                               if ((constraints.Attributes & GenericParameterAttributes.ReferenceTypeConstraint) == 0)
-                                                       error = true;
-                               }
-                               if (error){
+                       if (!TypeManager.IsReferenceType (type) && !TypeManager.IsNullableType (type)) {
+                               if (probe_type_expr is TypeParameterExpr) {
                                        Report.Error (413, loc,
-                                                     "The as operator requires that the `{0}' type parameter be constrained by a class",
-                                                     probe_type_expr.GetSignatureForError ());
-                                       return null;
+                                               "The `as' operator cannot be used with a non-reference type parameter `{0}'",
+                                               probe_type_expr.GetSignatureForError ());
+                               } else {
+                                       Report.Error (77, loc,
+                                               "The `as' operator cannot be used with a non-nullable value type `{0}'",
+                                               TypeManager.CSharpName (type));
                                }
+                               return null;
                        }
-#endif
+
                        if (expr.IsNull && TypeManager.IsNullableType (type)) {
                                return Nullable.LiftedNull.CreateFromExpression (this);
                        }
@@ -1441,7 +1429,9 @@ namespace Mono.CSharp {
                                return this;
                        }
 
-                       Error_CannotConvertType (etype, type, loc);
+                       Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
+                               TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
+
                        return null;
                }
 
@@ -1449,9 +1439,9 @@ namespace Mono.CSharp {
                        get { return "as"; }
                }
        
-               public override bool GetAttributableValue (Type value_type, out object value)
+               public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
                {
-                       return expr.GetAttributableValue (value_type, out value);
+                       return expr.GetAttributableValue (ec, value_type, out value);
                }
        }
        
@@ -1475,9 +1465,6 @@ namespace Mono.CSharp {
                        this.target_type = cast_type;
                        this.expr = expr;
                        this.loc = loc;
-
-                       if (target_type == TypeManager.system_void_expr)
-                               Error_VoidInvalidInTheContext (loc);
                }
 
                public Expression TargetType {
@@ -1488,6 +1475,11 @@ namespace Mono.CSharp {
                        get { return expr; }
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       throw new NotSupportedException ("ET");
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        expr = expr.Resolve (ec);
@@ -1565,23 +1557,24 @@ namespace Mono.CSharp {
 
                        type = texpr.Type;
 
-                       if (type == TypeManager.void_type) {
-                               Error_VoidInvalidInTheContext (loc);
-                               return null;
+                       if ((type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
+                               Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
                        }
 
-                       if (TypeManager.IsGenericParameter (type)) {
-                               GenericConstraints constraints = TypeManager.GetTypeParameterConstraints(type);
-                               if (constraints != null && constraints.IsReferenceType)
-                                       return new EmptyConstantCast (new NullLiteral (Location), type);
-                       } else {
-                               Constant c = New.Constantify (type);
-                               if (c != null)
-                                       return new EmptyConstantCast (c, type);
+                       if (type.IsPointer)
+                               return new NullLiteral (Location).ConvertImplicitly (type);
+
+                       if (TypeManager.IsReferenceType (type)) {
+                               return new EmptyConstantCast (new NullLiteral (Location), type);
 
-                               if (!TypeManager.IsValueType (type))
-                                       return new EmptyConstantCast (new NullLiteral (Location), type);
+                               // TODO: ET needs
+                               // return ReducedExpression.Create (new NullLiteral (Location), this);
                        }
+
+                       Constant c = New.Constantify (type);
+                       if (c != null)
+                               return c;
+
                        eclass = ExprClass.Variable;
                        return this;
                }
@@ -1594,6 +1587,11 @@ namespace Mono.CSharp {
                        ec.ig.Emit(OpCodes.Initobj, type);
                        temp_storage.Emit(ec);
                }
+
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       type = storey.MutateType (type);
+               }
                
                protected override void CloneTo (CloneContext clonectx, Expression t)
                {
@@ -1644,21 +1642,26 @@ namespace Mono.CSharp {
                        {
                                b.type = ReturnType;
 
-                               if (left != null)
-                                       b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
+                               b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
+                               b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
 
-                               if (right != null)
-                                       b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
+                               //
+                               // A user operators does not support multiple user conversions, but decimal type
+                               // is considered to be predefined type therefore we apply predefined operators rules
+                               // and then look for decimal user-operator implementation
+                               //
+                               if (left == TypeManager.decimal_type)
+                                       return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
 
                                return b;
                        }
 
-                       public bool IsPrimitiveApplicable (Type type)
+                       public bool IsPrimitiveApplicable (Type ltype, Type rtype)
                        {
                                //
                                // We are dealing with primitive types only
                                //
-                               return left == type;
+                               return left == ltype && ltype == rtype;
                        }
 
                        public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
@@ -1671,7 +1674,7 @@ namespace Mono.CSharp {
                                        Convert.ImplicitConversionExists (ec, rexpr, right);
                        }
 
-                       public PredefinedOperator ResolveBetterOperator (EmitContext ec, Expression lexpr, Expression rexpr, PredefinedOperator best_operator)
+                       public PredefinedOperator ResolveBetterOperator (EmitContext ec, PredefinedOperator best_operator)
                        {
                                int result = 0;
                                if (left != null && best_operator.left != null) {
@@ -1681,7 +1684,7 @@ namespace Mono.CSharp {
                                //
                                // When second arguments are same as the first one, the result is same
                                //
-                               if (left != right || best_operator.left != best_operator.right) {
+                               if (right != null && (left != right || best_operator.left != best_operator.right)) {
                                        result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
                                }
 
@@ -1763,6 +1766,11 @@ namespace Mono.CSharp {
                        {
                        }
 
+                       public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask, Type retType)
+                               : base (ltype, rtype, op_mask, retType)
+                       {
+                       }
+
                        public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
                                : base (type, op_mask, return_type)
                        {
@@ -1791,17 +1799,21 @@ namespace Mono.CSharp {
 
                        public override Expression ConvertResult (EmitContext ec, Binary b)
                        {
-                               base.ConvertResult (ec, b);
+                               if (left != null) {
+                                       b.left = EmptyCast.Create (b.left, left);
+                               } else if (right != null) {
+                                       b.right = EmptyCast.Create (b.right, right);
+                               }
 
                                Type r_type = ReturnType;
                                if (r_type == null) {
-                                       r_type = b.left.Type;
-                                       if (r_type == null)
+                                       if (left == null)
+                                               r_type = b.left.Type;
+                                       else 
                                                r_type = b.right.Type;
                                }
 
-                               return new PointerArithmetic (b.oper == Operator.Addition,
-                                       b.left, b.right, r_type, b.loc).Resolve (ec);
+                               return new PointerArithmetic (b.oper, b.left, b.right, r_type, b.loc).Resolve (ec);
                        }
                }
 
@@ -1850,36 +1862,9 @@ namespace Mono.CSharp {
                readonly bool is_compound;
                Expression enum_conversion;
 
-               // This must be kept in sync with Operator!!!
-               public static readonly string [] oper_names;
-
                static PredefinedOperator [] standard_operators;
                static PredefinedOperator [] pointer_operators;
                
-               static Binary ()
-               {
-                       oper_names = new string [18];
-
-                       oper_names [(int) (Operator.Multiply & Operator.ValuesOnlyMask)] = "op_Multiply";
-                       oper_names [(int) (Operator.Division & Operator.ValuesOnlyMask)] = "op_Division";
-                       oper_names [(int) (Operator.Modulus & Operator.ValuesOnlyMask)] = "op_Modulus";
-                       oper_names [(int) (Operator.Addition & Operator.ValuesOnlyMask)] = "op_Addition";
-                       oper_names [(int) (Operator.Subtraction & Operator.ValuesOnlyMask)] = "op_Subtraction";
-                       oper_names [(int) (Operator.LeftShift & Operator.ValuesOnlyMask)] = "op_LeftShift";
-                       oper_names [(int) (Operator.RightShift & Operator.ValuesOnlyMask)] = "op_RightShift";
-                       oper_names [(int) (Operator.LessThan & Operator.ValuesOnlyMask)] = "op_LessThan";
-                       oper_names [(int) (Operator.GreaterThan & Operator.ValuesOnlyMask)] = "op_GreaterThan";
-                       oper_names [(int) (Operator.LessThanOrEqual & Operator.ValuesOnlyMask)] = "op_LessThanOrEqual";
-                       oper_names [(int) (Operator.GreaterThanOrEqual & Operator.ValuesOnlyMask)] = "op_GreaterThanOrEqual";
-                       oper_names [(int) (Operator.Equality & Operator.ValuesOnlyMask)] = "op_Equality";
-                       oper_names [(int) (Operator.Inequality & Operator.ValuesOnlyMask)] = "op_Inequality";
-                       oper_names [(int) (Operator.BitwiseAnd & Operator.ValuesOnlyMask)] = "op_BitwiseAnd";
-                       oper_names [(int) (Operator.BitwiseOr & Operator.ValuesOnlyMask)] = "op_BitwiseOr";
-                       oper_names [(int) (Operator.ExclusiveOr & Operator.ValuesOnlyMask)] = "op_ExclusiveOr";
-                       oper_names [(int) (Operator.LogicalOr & Operator.ValuesOnlyMask)] = "op_LogicalOr";
-                       oper_names [(int) (Operator.LogicalAnd & Operator.ValuesOnlyMask)] = "op_LogicalAnd";
-               }
-
                public Binary (Operator oper, Expression left, Expression right, bool isCompound)
                        : this (oper, left, right)
                {
@@ -1972,18 +1957,12 @@ namespace Mono.CSharp {
                        return s;
                }
 
-               static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
+               public static void Error_OperatorCannotBeApplied (Expression left, Expression right, Operator oper, Location loc)
                {
-                       Error_OperatorCannotBeApplied (loc, name, TypeManager.CSharpName (l), TypeManager.CSharpName (r));
+                       new Binary (oper, left, right).Error_OperatorCannotBeApplied (left, right);
                }
 
-               public static void Error_OperatorCannotBeApplied (Location loc, string name, string left, string right)
-               {
-                       Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
-                               name, left, right);
-               }
-               
-               protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
+               public static void Error_OperatorCannotBeApplied (Expression left, Expression right, string oper, Location loc)
                {
                        string l, r;
                        // TODO: This should be handled as Type of method group in CSharpName
@@ -1997,30 +1976,207 @@ namespace Mono.CSharp {
                        else
                                r = TypeManager.CSharpName (right.Type);
 
-                       Error_OperatorCannotBeApplied (Location, OperName (oper), l, r);
+                       Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
+                               oper, l, r);
                }
-
-               public static string GetOperatorMetadataName (Operator op)
+               
+               protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
                {
-                       return oper_names [(int)(op & Operator.ValuesOnlyMask)];
+                       Error_OperatorCannotBeApplied (left, right, OperName (oper), loc);
                }
 
-               static bool IsUnsigned (Type t)
+               static string GetOperatorMetadataName (Operator op)
                {
-                       while (t.IsPointer)
-                               t = TypeManager.GetElementType (t);
+                       CSharp.Operator.OpType op_type;
+                       switch (op) {
+                       case Operator.Addition:
+                               op_type = CSharp.Operator.OpType.Addition; break;
+                       case Operator.BitwiseAnd:
+                               op_type = CSharp.Operator.OpType.BitwiseAnd; break;
+                       case Operator.BitwiseOr:
+                               op_type = CSharp.Operator.OpType.BitwiseOr; break;
+                       case Operator.Division:
+                               op_type = CSharp.Operator.OpType.Division; break;
+                       case Operator.Equality:
+                               op_type = CSharp.Operator.OpType.Equality; break;
+                       case Operator.ExclusiveOr:
+                               op_type = CSharp.Operator.OpType.ExclusiveOr; break;
+                       case Operator.GreaterThan:
+                               op_type = CSharp.Operator.OpType.GreaterThan; break;
+                       case Operator.GreaterThanOrEqual:
+                               op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
+                       case Operator.Inequality:
+                               op_type = CSharp.Operator.OpType.Inequality; break;
+                       case Operator.LeftShift:
+                               op_type = CSharp.Operator.OpType.LeftShift; break;
+                       case Operator.LessThan:
+                               op_type = CSharp.Operator.OpType.LessThan; break;
+                       case Operator.LessThanOrEqual:
+                               op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
+                       case Operator.Modulus:
+                               op_type = CSharp.Operator.OpType.Modulus; break;
+                       case Operator.Multiply:
+                               op_type = CSharp.Operator.OpType.Multiply; break;
+                       case Operator.RightShift:
+                               op_type = CSharp.Operator.OpType.RightShift; break;
+                       case Operator.Subtraction:
+                               op_type = CSharp.Operator.OpType.Subtraction; break;
+                       default:
+                               throw new InternalErrorException (op.ToString ());
+                       }
 
-                       return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
-                               t == TypeManager.ushort_type || t == TypeManager.byte_type);
+                       return CSharp.Operator.GetMetadataName (op_type);
                }
 
-               static bool IsFloat (Type t)
+               public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
                {
-                       return t == TypeManager.float_type || t == TypeManager.double_type;
-               }
+                       OpCode opcode;
+                       ILGenerator ig = ec.ig;
 
-               Expression ResolveOperator (EmitContext ec)
-               {
+                       switch (oper){
+                       case Operator.Multiply:
+                               if (ec.CheckState){
+                                       if (l == TypeManager.int32_type || l == TypeManager.int64_type)
+                                               opcode = OpCodes.Mul_Ovf;
+                                       else if (!IsFloat (l))
+                                               opcode = OpCodes.Mul_Ovf_Un;
+                                       else
+                                               opcode = OpCodes.Mul;
+                               } else
+                                       opcode = OpCodes.Mul;
+                               
+                               break;
+                               
+                       case Operator.Division:
+                               if (IsUnsigned (l))
+                                       opcode = OpCodes.Div_Un;
+                               else
+                                       opcode = OpCodes.Div;
+                               break;
+                               
+                       case Operator.Modulus:
+                               if (IsUnsigned (l))
+                                       opcode = OpCodes.Rem_Un;
+                               else
+                                       opcode = OpCodes.Rem;
+                               break;
+
+                       case Operator.Addition:
+                               if (ec.CheckState){
+                                       if (l == TypeManager.int32_type || l == TypeManager.int64_type)
+                                               opcode = OpCodes.Add_Ovf;
+                                       else if (!IsFloat (l))
+                                               opcode = OpCodes.Add_Ovf_Un;
+                                       else
+                                               opcode = OpCodes.Add;
+                               } else
+                                       opcode = OpCodes.Add;
+                               break;
+
+                       case Operator.Subtraction:
+                               if (ec.CheckState){
+                                       if (l == TypeManager.int32_type || l == TypeManager.int64_type)
+                                               opcode = OpCodes.Sub_Ovf;
+                                       else if (!IsFloat (l))
+                                               opcode = OpCodes.Sub_Ovf_Un;
+                                       else
+                                               opcode = OpCodes.Sub;
+                               } else
+                                       opcode = OpCodes.Sub;
+                               break;
+
+                       case Operator.RightShift:
+                               if (IsUnsigned (l))
+                                       opcode = OpCodes.Shr_Un;
+                               else
+                                       opcode = OpCodes.Shr;
+                               break;
+                               
+                       case Operator.LeftShift:
+                               opcode = OpCodes.Shl;
+                               break;
+
+                       case Operator.Equality:
+                               opcode = OpCodes.Ceq;
+                               break;
+
+                       case Operator.Inequality:
+                               ig.Emit (OpCodes.Ceq);
+                               ig.Emit (OpCodes.Ldc_I4_0);
+                               
+                               opcode = OpCodes.Ceq;
+                               break;
+
+                       case Operator.LessThan:
+                               if (IsUnsigned (l))
+                                       opcode = OpCodes.Clt_Un;
+                               else
+                                       opcode = OpCodes.Clt;
+                               break;
+
+                       case Operator.GreaterThan:
+                               if (IsUnsigned (l))
+                                       opcode = OpCodes.Cgt_Un;
+                               else
+                                       opcode = OpCodes.Cgt;
+                               break;
+
+                       case Operator.LessThanOrEqual:
+                               if (IsUnsigned (l) || IsFloat (l))
+                                       ig.Emit (OpCodes.Cgt_Un);
+                               else
+                                       ig.Emit (OpCodes.Cgt);
+                               ig.Emit (OpCodes.Ldc_I4_0);
+                               
+                               opcode = OpCodes.Ceq;
+                               break;
+
+                       case Operator.GreaterThanOrEqual:
+                               if (IsUnsigned (l) || IsFloat (l))
+                                       ig.Emit (OpCodes.Clt_Un);
+                               else
+                                       ig.Emit (OpCodes.Clt);
+                               
+                               ig.Emit (OpCodes.Ldc_I4_0);
+                               
+                               opcode = OpCodes.Ceq;
+                               break;
+
+                       case Operator.BitwiseOr:
+                               opcode = OpCodes.Or;
+                               break;
+
+                       case Operator.BitwiseAnd:
+                               opcode = OpCodes.And;
+                               break;
+
+                       case Operator.ExclusiveOr:
+                               opcode = OpCodes.Xor;
+                               break;
+
+                       default:
+                               throw new InternalErrorException (oper.ToString ());
+                       }
+
+                       ig.Emit (opcode);
+               }
+
+               static bool IsUnsigned (Type t)
+               {
+                       if (t.IsPointer)
+                               return true;
+
+                       return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
+                               t == TypeManager.ushort_type || t == TypeManager.byte_type);
+               }
+
+               static bool IsFloat (Type t)
+               {
+                       return t == TypeManager.float_type || t == TypeManager.double_type;
+               }
+
+               Expression ResolveOperator (EmitContext ec)
+               {
                        Type l = left.Type;
                        Type r = right.Type;
                        Expression expr;
@@ -2056,9 +2212,14 @@ namespace Mono.CSharp {
                                }
 
                                // Delegates
-                               if (oper == Operator.Addition || oper == Operator.Subtraction) {
-                                       if (TypeManager.IsDelegateType (l))
-                                               return ResolveOperatorDelegateBinary (ec, l, r);
+                               if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
+                                        (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
+                                               
+                                       expr = ResolveOperatorDelegate (ec, l, r);
+
+                                       // TODO: Can this be ambiguous
+                                       if (expr != null)
+                                               return expr;
                                }
 
                                // User operators
@@ -2166,10 +2327,10 @@ namespace Mono.CSharp {
                        // T* operator + (long y,  T *x);
                        // T* operator + (ulong y, T *x);
                        //
-                       temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask));
-                       temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask));
-                       temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask));
-                       temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask));
+                       temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
+                       temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
+                       temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
+                       temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
 
                        //
                        // long operator - (T* x, T *y)
@@ -2190,6 +2351,7 @@ namespace Mono.CSharp {
                        temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
                        temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
                        temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
+                       temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
 
                        temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
                        temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
@@ -2197,6 +2359,7 @@ namespace Mono.CSharp {
                        temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
                        temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
                        temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
+                       temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
 
                        temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
 
@@ -2377,13 +2540,14 @@ namespace Mono.CSharp {
                                                return null;
                                        }
 
-                                       if (rc != null) {
-                                               right = left;
-                                               lc = rc;
-                                       }
-
+                                       //
                                        // The result is a constant with side-effect
-                                       return new SideEffectConstant (lc, right, loc);
+                                       //
+                                       Constant side_effect = rc == null ?
+                                               new SideEffectConstant (lc, right, loc) :
+                                               new SideEffectConstant (rc, left, loc);
+
+                                       return ReducedExpression.Create (side_effect, this);
                                }
                        }
 
@@ -2419,29 +2583,48 @@ namespace Mono.CSharp {
                        return expr;
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       left.MutateHoistedGenericType (storey);
+                       right.MutateHoistedGenericType (storey);
+               }
+
                //
                // 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 ResolveOperatorDelegateBinary (EmitContext ec, Type l, Type r)
+               Expression ResolveOperatorDelegate (EmitContext ec, Type l, Type r)
                {
-                       if (((right.eclass == ExprClass.MethodGroup) || (r == TypeManager.anonymous_method_type))) {
-                               if ((RootContext.Version != LanguageVersion.ISO_1)) {
-                                       Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
+                       bool is_equality = (oper & Operator.EqualityMask) != 0;
+                       if (!TypeManager.IsEqual (l, r)) {
+                               Expression tmp;
+                               if (right.eclass == ExprClass.MethodGroup || (r == TypeManager.anonymous_method_type && !is_equality)) {
+                                       tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
                                        if (tmp == null)
                                                return null;
                                        right = tmp;
                                        r = right.Type;
-                               }
-                       } else {
-                               if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral))
+                               } else if (left.eclass == ExprClass.MethodGroup || (l == TypeManager.anonymous_method_type && !is_equality)) {
+                                       tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
+                                       if (tmp == null)
+                                               return null;
+                                       left = tmp;
+                                       l = left.Type;
+                               } else {
                                        return null;
+                               }
                        }
 
+                       //
+                       // Resolve delegate equality as a user operator
+                       //
+                       if (is_equality)
+                               return ResolveUserOperator (ec, l, r);
+
                        MethodInfo method;
                        ArrayList args = new ArrayList (2);
-
-                       args = new ArrayList (2);
                        args.Add (new Argument (left, Argument.AType.Expression));
                        args.Add (new Argument (right, Argument.AType.Expression));
 
@@ -2461,7 +2644,10 @@ namespace Mono.CSharp {
                                method = TypeManager.delegate_remove_delegate_delegate;
                        }
 
-                       return new BinaryDelegate (l, method, args);
+                       MethodGroupExpr mg = new MethodGroupExpr (new MemberInfo [] { method }, TypeManager.delegate_type, loc);
+                       mg = mg.OverloadResolve (ec, ref args, false, loc);
+
+                       return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
                }
 
                //
@@ -2469,94 +2655,143 @@ namespace Mono.CSharp {
                //
                Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
                {
-                       Expression temp;
+                       //
+                       // bool operator == (E x, E y);
+                       // bool operator != (E x, E y);
+                       // bool operator < (E x, E y);
+                       // bool operator > (E x, E y);
+                       // bool operator <= (E x, E y);
+                       // bool operator >= (E x, E y);
+                       //
+                       // E operator & (E x, E y);
+                       // E operator | (E x, E y);
+                       // E operator ^ (E x, E y);
+                       //
+                       // U operator - (E e, E f)
+                       // E operator - (E e, U x)
+                       //
+                       // E operator + (U x, E e)
+                       // E operator + (E e, U x)
+                       //
+                       if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
+                               (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
+                               return null;
 
-                       if (lenum || renum) {
-                               //
-                               // bool operator == (E x, E y);
-                               // bool operator != (E x, E y);
-                               // bool operator < (E x, E y);
-                               // bool operator > (E x, E y);
-                               // bool operator <= (E x, E y);
-                               // bool operator >= (E x, E y);
-                               //
-                               if ((oper & Operator.ComparisonMask) != 0) {
-                                       type = TypeManager.bool_type;
-                               } else if ((oper & Operator.BitwiseMask) != 0) {
-                                       type = ltype;
+                       Expression ltemp = left;
+                       Expression rtemp = right;
+                       Type underlying_type;
+                       Expression expr;
+                       
+                       if ((oper & Operator.ComparisonMask | Operator.BitwiseMask) != 0) {
+                               if (renum) {
+                                       expr = Convert.ImplicitConversion (ec, left, rtype, loc);
+                                       if (expr != null) {
+                                               left = expr;
+                                               ltype = expr.Type;
+                                       }
+                               } else if (lenum) {
+                                       expr = Convert.ImplicitConversion (ec, right, ltype, loc);
+                                       if (expr != null) {
+                                               right = expr;
+                                               rtype = expr.Type;
+                                       }
                                }
+                       }                       
 
-                               if (type != null) {
-                                       if (!TypeManager.IsEqual (ltype, rtype)) {
-                                               if (!lenum) {
-                                                       temp = Convert.ImplicitConversion (ec, left, rtype, loc);
-                                                       if (temp == null)
-                                                               return null;
-                                                       left = temp;
-                                               } else {
-                                                       temp = Convert.ImplicitConversion (ec, right, ltype, loc);
-                                                       if (temp == null)
-                                                               return null;
-                                                       right = temp;
-                                               }
-                                       }
+                       if (TypeManager.IsEqual (ltype, rtype)) {
+                               underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
 
-                                       return this;
-                               }
-                       }
+                               if (left is Constant)
+                                       left = ((Constant) left).ConvertExplicitly (false, underlying_type);
+                               else
+                                       left = EmptyCast.Create (left, underlying_type);
 
-                       Type underlying_type;
-                       if (lenum && !renum) {
-                               //
-                               // E operator + (E e, U x)
-                               // E operator - (E e, U x)
-                               //
-                               if (oper == Operator.Addition || oper == Operator.Subtraction) {
-                                       underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
-                                       temp = left;
-                                       left = EmptyCast.Create (left, underlying_type, true);
-                                       if (!DoBinaryOperatorPromotion (ec)) {
-                                               left = temp;
-                                               return null;
-                                       }
+                               if (right is Constant)
+                                       right = ((Constant) right).ConvertExplicitly (false, underlying_type);
+                               else
+                                       right = EmptyCast.Create (right, underlying_type);
+                       } else if (lenum) {
+                               underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
 
-                                       enum_conversion = Convert.ExplicitNumericConversion (
-                                               new EmptyExpression (left.Type), underlying_type);
+                               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;
 
-                                       return ResolveOperatorPredefined (ec, standard_operators, true, ltype);
+                                       right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
                                }
 
-                               return null;
-                       }
+                               if (left is Constant)
+                                       left = ((Constant) left).ConvertExplicitly (false, underlying_type);
+                               else
+                                       left = EmptyCast.Create (left, underlying_type);
 
-                       if (renum) {
-                               //
-                               // E operator + (U x, E e)
-                               //
-                               if (oper == Operator.Addition) {
-                                       underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
-                                       temp = Convert.ImplicitConversion (ec, left, underlying_type, loc);
-                                       if (temp == null)
+                       } else if (renum) {
+                               underlying_type = TypeManager.GetEnumUnderlyingType (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 = temp;
-                                       type = rtype;
-                                       return this;
+                                       left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
                                }
+
+                               if (right is Constant)
+                                       right = ((Constant) right).ConvertExplicitly (false, underlying_type);
+                               else
+                                       right = EmptyCast.Create (right, underlying_type);
+
+                       } else {
+                               return null;
                        }
 
                        //
-                       // U operator - (E e, E f)
+                       // C# specification uses explicit cast syntax which means binary promotion
+                       // should happen, however it seems that csc does not do that
                        //
-                       if (oper == Operator.Subtraction) {
-                               if (!TypeManager.IsEqual (ltype, rtype))
-                                       return null;
+                       if (!DoBinaryOperatorPromotion (ec)) {
+                               left = ltemp;
+                               right = rtemp;
+                               return null;
+                       }
 
-                               type = TypeManager.GetEnumUnderlyingType (ltype);
-                               return this;
+                       Type res_type = null;
+                       if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
+                               Type promoted_type = lenum ? left.Type : right.Type;
+                               enum_conversion = Convert.ExplicitNumericConversion (
+                                       new EmptyExpression (promoted_type), underlying_type);
+
+                               if (oper == Operator.Subtraction && renum && lenum)
+                                       res_type = underlying_type;
+                               else if (oper == Operator.Addition && renum)
+                                       res_type = rtype;
+                               else
+                                       res_type = ltype;
                        }
+                       
+                       expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
+                       if (!is_compound || expr == null)
+                               return expr;
 
-                       return null;
+                       //
+                       // TODO: Need to corectly implemented Coumpound Assigment for all operators
+                       // Section: 7.16.2
+                       //
+                       if (Convert.ImplicitConversionExists (ec, left, rtype))
+                               return expr;
+
+                       if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
+                               return null;
+
+                       expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
+                       return expr;
                }
 
                //
@@ -2639,6 +2874,8 @@ namespace Mono.CSharp {
                                        return null;
                        } else if (l.IsInterface) {
                                l = TypeManager.object_type;
+                       } else if (l.IsValueType) {
+                               return null;
                        }
 
                        if (rgen) {
@@ -2647,8 +2884,11 @@ namespace Mono.CSharp {
                                        return null;
                        } else if (r.IsInterface) {
                                r = TypeManager.object_type;
+                       } else if (r.IsValueType) {
+                               return null;
                        }
 
+
                        const string ref_comparison = "Possible unintended reference comparison. " +
                                "Consider casting the {0} side of the expression to `string' to compare the values";
 
@@ -2717,6 +2957,7 @@ namespace Mono.CSharp {
                {
                        PredefinedOperator best_operator = null;
                        Type l = left.Type;
+                       Type r = right.Type;
                        Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
 
                        foreach (PredefinedOperator po in operators) {
@@ -2724,7 +2965,7 @@ namespace Mono.CSharp {
                                        continue;
 
                                if (primitives_only) {
-                                       if (!po.IsPrimitiveApplicable (l))
+                                       if (!po.IsPrimitiveApplicable (l, r))
                                                continue;
                                } else {
                                        if (!po.IsApplicable (ec, left, right))
@@ -2739,7 +2980,7 @@ namespace Mono.CSharp {
                                        continue;
                                }
 
-                               best_operator = po.ResolveBetterOperator (ec, left, right, best_operator);
+                               best_operator = po.ResolveBetterOperator (ec, best_operator);
 
                                if (best_operator == null) {
                                        Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
@@ -2779,17 +3020,16 @@ namespace Mono.CSharp {
 
                        string op = GetOperatorMetadataName (user_oper);
 
-                       MethodGroupExpr union;
                        MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
-                       if (!TypeManager.IsEqual (r, l)) {
-                               MethodGroupExpr right_operators = MemberLookup (
-                                       ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
-                               union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
-                       } else
-                               union = left_operators;
+                       MethodGroupExpr right_operators = null;
 
-                       if (union == null)
+                       if (!TypeManager.IsEqual (r, l)) {
+                               right_operators = MemberLookup (ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
+                               if (right_operators == null && left_operators == null)
+                                       return null;
+                       } else if (left_operators == null) {
                                return null;
+                       }
 
                        ArrayList args = new ArrayList (2);
                        Argument larg = new Argument (left);
@@ -2797,15 +3037,39 @@ namespace Mono.CSharp {
                        Argument rarg = new Argument (right);
                        args.Add (rarg);
 
-                       union = union.OverloadResolve (ec, ref args, true, loc);
-                       if (union == null)
-                               return null;
-
-                       Expression oper_expr;
+                       MethodGroupExpr union;
 
-                       // TODO: CreateExpressionTree is allocated every time
-                       if (user_oper != oper) {
-                               oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
+                       //
+                       // 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;
+                       }
+
+                       union = union.OverloadResolve (ec, ref args, true, loc);
+                       if (union == null)
+                               return null;
+
+                       Expression oper_expr;
+
+                       // TODO: CreateExpressionTree is allocated every time
+                       if (user_oper != oper) {
+                               oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
                                        oper == Operator.LogicalAnd, loc).Resolve (ec);
                        } else {
                                oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
@@ -2892,7 +3156,7 @@ namespace Mono.CSharp {
                                WarnUselessComparison (type);
                }
 
-               private bool IsValueOutOfRange (long value, Type type)
+               static bool IsValueOutOfRange (long value, Type type)
                {
                        if (IsTypeUnsigned (type) && value < 0)
                                return true;
@@ -2910,6 +3174,14 @@ namespace Mono.CSharp {
                                t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
                }
 
+               static bool IsPredefinedUserOperator (Type 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 (Type type)
                {
                        return type == TypeManager.uint64_type ||
@@ -3025,7 +3297,8 @@ namespace Mono.CSharp {
                        right.Emit (ec);
 
                        Type t = left.Type;
-                       bool is_unsigned = IsUnsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
+                       bool is_float = IsFloat (t);
+                       bool is_unsigned = is_float || IsUnsigned (t);
                        
                        switch (oper){
                        case Operator.Equality:
@@ -3044,7 +3317,7 @@ namespace Mono.CSharp {
 
                        case Operator.LessThan:
                                if (on_true)
-                                       if (is_unsigned)
+                                       if (is_unsigned && !is_float)
                                                ig.Emit (OpCodes.Blt_Un, target);
                                        else
                                                ig.Emit (OpCodes.Blt, target);
@@ -3057,7 +3330,7 @@ namespace Mono.CSharp {
 
                        case Operator.GreaterThan:
                                if (on_true)
-                                       if (is_unsigned)
+                                       if (is_unsigned && !is_float)
                                                ig.Emit (OpCodes.Bgt_Un, target);
                                        else
                                                ig.Emit (OpCodes.Bgt, target);
@@ -3070,7 +3343,7 @@ namespace Mono.CSharp {
 
                        case Operator.LessThanOrEqual:
                                if (on_true)
-                                       if (is_unsigned)
+                                       if (is_unsigned && !is_float)
                                                ig.Emit (OpCodes.Ble_Un, target);
                                        else
                                                ig.Emit (OpCodes.Ble, target);
@@ -3084,7 +3357,7 @@ namespace Mono.CSharp {
 
                        case Operator.GreaterThanOrEqual:
                                if (on_true)
-                                       if (is_unsigned)
+                                       if (is_unsigned && !is_float)
                                                ig.Emit (OpCodes.Bge_Un, target);
                                        else
                                                ig.Emit (OpCodes.Bge, target);
@@ -3142,135 +3415,7 @@ namespace Mono.CSharp {
                        }
 
                        right.Emit (ec);
-
-                       OpCode opcode;
-                       
-                       switch (oper){
-                       case Operator.Multiply:
-                               if (ec.CheckState){
-                                       if (l == TypeManager.int32_type || l == TypeManager.int64_type)
-                                               opcode = OpCodes.Mul_Ovf;
-                                       else if (!IsFloat (l))
-                                               opcode = OpCodes.Mul_Ovf_Un;
-                                       else
-                                               opcode = OpCodes.Mul;
-                               } else
-                                       opcode = OpCodes.Mul;
-                               
-                               break;
-                               
-                       case Operator.Division:
-                               if (IsUnsigned (l))
-                                       opcode = OpCodes.Div_Un;
-                               else
-                                       opcode = OpCodes.Div;
-                               break;
-                               
-                       case Operator.Modulus:
-                               if (IsUnsigned (l))
-                                       opcode = OpCodes.Rem_Un;
-                               else
-                                       opcode = OpCodes.Rem;
-                               break;
-
-                       case Operator.Addition:
-                               if (ec.CheckState){
-                                       if (l == TypeManager.int32_type || l == TypeManager.int64_type)
-                                               opcode = OpCodes.Add_Ovf;
-                                       else if (!IsFloat (l))
-                                               opcode = OpCodes.Add_Ovf_Un;
-                                       else
-                                               opcode = OpCodes.Add;
-                               } else
-                                       opcode = OpCodes.Add;
-                               break;
-
-                       case Operator.Subtraction:
-                               if (ec.CheckState){
-                                       if (l == TypeManager.int32_type || l == TypeManager.int64_type)
-                                               opcode = OpCodes.Sub_Ovf;
-                                       else if (!IsFloat (l))
-                                               opcode = OpCodes.Sub_Ovf_Un;
-                                       else
-                                               opcode = OpCodes.Sub;
-                               } else
-                                       opcode = OpCodes.Sub;
-                               break;
-
-                       case Operator.RightShift:
-                               if (IsUnsigned (l))
-                                       opcode = OpCodes.Shr_Un;
-                               else
-                                       opcode = OpCodes.Shr;
-                               break;
-                               
-                       case Operator.LeftShift:
-                               opcode = OpCodes.Shl;
-                               break;
-
-                       case Operator.Equality:
-                               opcode = OpCodes.Ceq;
-                               break;
-
-                       case Operator.Inequality:
-                               ig.Emit (OpCodes.Ceq);
-                               ig.Emit (OpCodes.Ldc_I4_0);
-                               
-                               opcode = OpCodes.Ceq;
-                               break;
-
-                       case Operator.LessThan:
-                               if (IsUnsigned (l))
-                                       opcode = OpCodes.Clt_Un;
-                               else
-                                       opcode = OpCodes.Clt;
-                               break;
-
-                       case Operator.GreaterThan:
-                               if (IsUnsigned (l))
-                                       opcode = OpCodes.Cgt_Un;
-                               else
-                                       opcode = OpCodes.Cgt;
-                               break;
-
-                       case Operator.LessThanOrEqual:
-                               if (IsUnsigned (l) || IsFloat (l))
-                                       ig.Emit (OpCodes.Cgt_Un);
-                               else
-                                       ig.Emit (OpCodes.Cgt);
-                               ig.Emit (OpCodes.Ldc_I4_0);
-                               
-                               opcode = OpCodes.Ceq;
-                               break;
-
-                       case Operator.GreaterThanOrEqual:
-                               if (IsUnsigned (l) || IsFloat (l))
-                                       ig.Emit (OpCodes.Clt_Un);
-                               else
-                                       ig.Emit (OpCodes.Clt);
-                               
-                               ig.Emit (OpCodes.Ldc_I4_0);
-                               
-                               opcode = OpCodes.Ceq;
-                               break;
-
-                       case Operator.BitwiseOr:
-                               opcode = OpCodes.Or;
-                               break;
-
-                       case Operator.BitwiseAnd:
-                               opcode = OpCodes.And;
-                               break;
-
-                       case Operator.ExclusiveOr:
-                               opcode = OpCodes.Xor;
-                               break;
-
-                       default:
-                               throw new InternalErrorException (oper.ToString ());
-                       }
-
-                       ig.Emit (opcode);
+                       EmitOperatorOpcode (ec, oper, l);
 
                        //
                        // Nullable enum could require underlying type cast and we cannot simply wrap binary
@@ -3397,40 +3542,6 @@ namespace Mono.CSharp {
                        return CreateExpressionFactoryCall (method_name, args);
                }
        }
-
-       //
-       // Object created by Binary when the binary operator uses an method instead of being
-       // a binary operation that maps to a CIL binary operation.
-       //
-       public class BinaryMethod : Expression {
-               public MethodBase method;
-               public ArrayList  Arguments;
-               
-               public BinaryMethod (Type t, MethodBase m, ArrayList args)
-               {
-                       method = m;
-                       Arguments = args;
-                       type = t;
-                       eclass = ExprClass.Value;
-               }
-
-               public override Expression DoResolve (EmitContext ec)
-               {
-                       return this;
-               }
-
-               public override void Emit (EmitContext ec)
-               {
-                       ILGenerator ig = ec.ig;
-                       
-                       Invocation.EmitArguments (ec, Arguments, false, null);
-                       
-                       if (method is MethodInfo)
-                               ig.Emit (OpCodes.Call, (MethodInfo) method);
-                       else
-                               ig.Emit (OpCodes.Call, (ConstructorInfo) method);
-               }
-       }
        
        //
        // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
@@ -3535,52 +3646,14 @@ namespace Mono.CSharp {
                        if (concat != null)
                                concat.Emit (ec);
                }
-       }
-
-       //
-       // Object created with +/= on delegates
-       //
-       public class BinaryDelegate : Expression {
-               MethodInfo method;
-               ArrayList  args;
-
-               public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
-               {
-                       method = mi;
-                       this.args = args;
-                       type = t;
-                       eclass = ExprClass.Value;
-               }
-
-               public override Expression DoResolve (EmitContext ec)
-               {
-                       return this;
-               }
-
-               public override void Emit (EmitContext ec)
+               
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
                {
-                       ILGenerator ig = ec.ig;
-                       
-                       Invocation.EmitArguments (ec, args, false, null);
-                       
-                       ig.Emit (OpCodes.Call, (MethodInfo) method);
-                       ig.Emit (OpCodes.Castclass, type);
-               }
-
-               public Expression Right {
-                       get {
-                               Argument arg = (Argument) args [1];
-                               return arg.Expr;
-                       }
-               }
-
-               public bool IsAddition {
-                       get {
-                               return method == TypeManager.delegate_combine_delegate_delegate;
-                       }
-               }
+                       foreach (Argument a in arguments)
+                               a.Expr.MutateHoistedGenericType (storey);
+               }               
        }
-       
+
        //
        // User-defined conditional logical operator
        //
@@ -3599,7 +3672,7 @@ namespace Mono.CSharp {
                {
                        MethodInfo method = (MethodInfo)mg;
                        type = TypeManager.TypeToCoreType (method.ReturnType);
-                       ParameterData pd = TypeManager.GetParameterData (method);
+                       AParametersCollection pd = TypeManager.GetParameterData (method);
                        if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
                                Report.Error (217, loc,
                                        "A user-defined operator `{0}' must have parameters and return values of the same type in order to be applicable as a short circuit operator",
@@ -3642,18 +3715,24 @@ namespace Mono.CSharp {
 
        public class PointerArithmetic : Expression {
                Expression left, right;
-               bool is_add;
+               Binary.Operator op;
 
                //
                // We assume that `l' is always a pointer
                //
-               public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
+               public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
                {
                        type = t;
                        this.loc = loc;
                        left = l;
                        right = r;
-                       is_add = is_addition;
+                       this.op = op;
+               }
+
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       Error_PointerInsideExpressionTree ();
+                       return null;
                }
 
                public override Expression DoResolve (EmitContext ec)
@@ -3674,14 +3753,21 @@ namespace Mono.CSharp {
                        ILGenerator ig = ec.ig;
                        
                        // It must be either array or fixed buffer
-                       Type element = TypeManager.HasElementType (op_type) ?
-                               element = TypeManager.GetElementType (op_type) :
-                               element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
+                       Type element;
+                       if (TypeManager.HasElementType (op_type)) {
+                               element = TypeManager.GetElementType (op_type);
+                       } else {
+                               FieldExpr fe = left as FieldExpr;
+                               if (fe != null)
+                                       element = AttributeTester.GetFixedBuffer (fe.FieldInfo).ElementType;
+                               else
+                                       element = op_type;
+                       }
 
                        int size = GetTypeSize (element);
                        Type rtype = right.Type;
                        
-                       if (rtype.IsPointer){
+                       if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
                                //
                                // handle (pointer - pointer)
                                //
@@ -3702,36 +3788,50 @@ namespace Mono.CSharp {
                                // handle + and - on (pointer op int)
                                //
                                left.Emit (ec);
-                               ig.Emit (OpCodes.Conv_I);
 
                                Constant right_const = right as Constant;
-                               if (right_const != null && size != 0) {
-                                       Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
-                                       if (ex == null)
+                               if (right_const != null) {
+                                       //
+                                       // Optimize 0-based arithmetic
+                                       //
+                                       if (right_const.IsDefaultValue)
                                                return;
-                                       ex.Emit (ec);
-                               } else {
-                                       right.Emit (ec);
-                                       if (size != 1){
-                                               if (size == 0)
-                                                       ig.Emit (OpCodes.Sizeof, element);
-                                               else 
-                                                       IntLiteral.EmitInt (ig, size);
-                                               if (rtype == TypeManager.int64_type)
-                                                       ig.Emit (OpCodes.Conv_I8);
-                                               else if (rtype == TypeManager.uint64_type)
-                                                       ig.Emit (OpCodes.Conv_U8);
-                                               ig.Emit (OpCodes.Mul);
+
+                                       if (size != 0) {
+                                               right = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
+                                               if (right == null)
+                                                       return;
+                                       } else {
+                                               ig.Emit (OpCodes.Sizeof, element);
+                                               right = EmptyExpression.Null;
                                        }
                                }
-                               
-                               if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
+
+                               right.Emit (ec);
+                               if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
+                                       rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
                                        ig.Emit (OpCodes.Conv_I);
-                               
-                               if (is_add)
-                                       ig.Emit (OpCodes.Add);
-                               else
-                                       ig.Emit (OpCodes.Sub);
+                               } else if (rtype == TypeManager.uint32_type) {
+                                       ig.Emit (OpCodes.Conv_U);
+                               }
+
+                               if (right_const == null && size != 1){
+                                       if (size == 0)
+                                               ig.Emit (OpCodes.Sizeof, element);
+                                       else 
+                                               IntLiteral.EmitInt (ig, size);
+                                       if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
+                                               ig.Emit (OpCodes.Conv_I8);
+
+                                       Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
+                               }
+
+                               if (rtype == TypeManager.int64_type)
+                                       ig.Emit (OpCodes.Conv_I);
+                               else if (rtype == TypeManager.uint64_type)
+                                       ig.Emit (OpCodes.Conv_U);
+
+                               Binary.EmitOperatorOpcode (ec, op, op_type);
                        }
                }
        }
@@ -3804,59 +3904,59 @@ namespace Mono.CSharp {
                                return null;
 
                        eclass = ExprClass.Value;
-                       if (true_expr.Type == false_expr.Type) {
-                               type = true_expr.Type;
-                               if (type == TypeManager.null_type) {
-                                       // TODO: probably will have to implement ConditionalConstant
-                                       // to call method without return constant as well
-                                       Report.Warning (-101, 1, loc, "Conditional expression will always return same value");
-                                       return true_expr;
-                               }
-                       } else {
-                               Expression conv;
-                               Type true_type = true_expr.Type;
-                               Type false_type = false_expr.Type;
+                       Type true_type = true_expr.Type;
+                       Type false_type = false_expr.Type;
+                       type = true_type;
 
-                               //
-                               // First, if an implicit conversion exists from true_expr
-                               // to false_expr, then the result type is of type false_expr.Type
-                               //
-                               conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
-                               if (conv != null){
+                       //
+                       // 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)) {
+                               Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
+                               if (conv != null) {
                                        //
                                        // Check if both can convert implicitl to each other's type
                                        //
-                                       if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null){
+                                       if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
                                                Error (172,
-                                                      "Can not compute type of conditional expression " +
-                                                      "as `" + TypeManager.CSharpName (true_expr.Type) +
-                                                      "' and `" + TypeManager.CSharpName (false_expr.Type) +
-                                                      "' convert implicitly to each other");
+                                                          "Can not compute type of conditional expression " +
+                                                          "as `" + TypeManager.CSharpName (true_expr.Type) +
+                                                          "' and `" + TypeManager.CSharpName (false_expr.Type) +
+                                                          "' convert implicitly to each other");
                                                return null;
                                        }
                                        type = false_type;
                                        true_expr = conv;
-                               } else if ((conv = Convert.ImplicitConversion(ec, false_expr, true_type,loc))!= null){
-                                       type = true_type;
+                               } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
                                        false_expr = conv;
                                } else {
-                                       Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
+                                       Report.Error (173, loc,
+                                               "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
                                                true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
                                        return null;
                                }
-                       }
+                       }                       
 
                        // Dead code optimalization
-                       if (expr is BoolConstant){
-                               BoolConstant bc = (BoolConstant) expr;
-
-                               Report.Warning (429, 4, bc.Value ? false_expr.Location : true_expr.Location, "Unreachable expression code detected");
-                               return bc.Value ? true_expr : false_expr;
+                       Constant c = expr as Constant;
+                       if (c != null){
+                               bool is_false = c.IsDefaultValue;
+                               Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
+                               return ReducedExpression.Create (is_false ? false_expr : true_expr, this).Resolve (ec);
                        }
 
                        return this;
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       expr.MutateHoistedGenericType (storey);
+                       true_expr.MutateHoistedGenericType (storey);
+                       false_expr.MutateHoistedGenericType (storey);
+                       type = storey.MutateType (type);
+               }
+
                public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
                {
                        return null;
@@ -3894,16 +3994,35 @@ namespace Mono.CSharp {
                }
        }
 
-       public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation {
-               bool prepared;
+       public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
                LocalTemporary temp;
 
-               public abstract Variable Variable {
-                       get;
-               }
+               #region Abstract
+               public abstract HoistedVariable HoistedVariable { get; }
+               public abstract bool IsFixedVariable { get; }
+               public abstract bool IsRef { get; }
+               public abstract string Name { get; }
+               public abstract void SetHasAddressTaken ();
+
+               //
+               // Variable IL data, it has to be protected to encapsulate hoisted variables
+               //
+               protected abstract ILocalVariable Variable { get; }
+               
+               //
+               // Variable flow-analysis data
+               //
+               public abstract VariableInfo VariableInfo { get; }
+               #endregion
+
+               public void AddressOf (EmitContext ec, AddressOp mode)
+               {
+                       if (IsHoistedEmitRequired (ec)) {
+                               HoistedVariable.AddressOf (ec, mode);
+                               return;
+                       }
 
-               public abstract bool IsRef {
-                       get;
+                       Variable.EmitAddressOf (ec);
                }
 
                public override void Emit (EmitContext ec)
@@ -3924,16 +4043,18 @@ namespace Mono.CSharp {
                //
                public void EmitLoad (EmitContext ec)
                {
-                       Report.Debug (64, "VARIABLE EMIT LOAD", this, Variable, type, loc);
-                       if (!prepared)
-                               Variable.EmitInstance (ec);
                        Variable.Emit (ec);
                }
-               
+
                public void Emit (EmitContext ec, bool leave_copy)
                {
                        Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
 
+                       if (IsHoistedEmitRequired (ec)) {
+                               HoistedVariable.Emit (ec, leave_copy);
+                               return;
+                       }
+
                        EmitLoad (ec);
 
                        if (IsRef) {
@@ -3947,7 +4068,7 @@ namespace Mono.CSharp {
                        if (leave_copy) {
                                ec.ig.Emit (OpCodes.Dup);
 
-                               if (IsRef || Variable.NeedsTemporary) {
+                               if (IsRef) {
                                        temp = new LocalTemporary (Type);
                                        temp.Store (ec);
                                }
@@ -3960,13 +4081,9 @@ namespace Mono.CSharp {
                        Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
                                      source, loc);
 
-                       ILGenerator ig = ec.ig;
-                       prepared = prepare_for_load;
-
-                       Variable.EmitInstance (ec);
-                       if (prepare_for_load) {
-                               if (Variable.HasInstance)
-                                       ig.Emit (OpCodes.Dup);
+                       if (IsHoistedEmitRequired (ec)) {
+                               HoistedVariable.EmitAssign (ec, source, leave_copy, prepare_for_load);
+                               return;
                        }
 
                        if (IsRef)
@@ -3977,22 +4094,21 @@ namespace Mono.CSharp {
                        // HACK: variable is already emitted when source is an initializer 
                        if (source is NewInitialize) {
                                if (leave_copy) {
-                                       Variable.EmitInstance (ec);
                                        Variable.Emit (ec);
                                }
                                return;
                        }
 
                        if (leave_copy) {
-                               ig.Emit (OpCodes.Dup);
-                               if (IsRef || Variable.NeedsTemporary) {
+                               ec.ig.Emit (OpCodes.Dup);
+                               if (IsRef) {
                                        temp = new LocalTemporary (Type);
                                        temp.Store (ec);
                                }
                        }
 
                        if (IsRef)
-                               StoreFromPtr (ig, type);
+                               StoreFromPtr (ec.ig, type);
                        else
                                Variable.EmitAssign (ec);
 
@@ -4001,28 +4117,38 @@ namespace Mono.CSharp {
                                temp.Release (ec);
                        }
                }
-               
-               public void AddressOf (EmitContext ec, AddressOp mode)
+
+               public bool IsHoisted {
+                       get { return HoistedVariable != null; }
+               }
+
+               protected virtual bool IsHoistedEmitRequired (EmitContext ec)
+               {
+                       //
+                       // Default implementation return true when there is a hosted variable
+                       //
+                       return HoistedVariable != null;
+               }
+
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
                {
-                       Variable.EmitInstance (ec);
-                       Variable.EmitAddressOf (ec);
+                       type = storey.MutateType (type);
                }
        }
 
        /// <summary>
        ///   Local variables
        /// </summary>
-       public class LocalVariableReference : VariableReference, IVariable {
-               public readonly string Name;
+       public class LocalVariableReference : VariableReference {
+               readonly string name;
                public Block Block;
                public LocalInfo local_info;
                bool is_readonly;
-               Variable variable;
 
                public LocalVariableReference (Block block, string name, Location l)
                {
                        Block = block;
-                       Name = name;
+                       this.name = name;
                        loc = l;
                        eclass = ExprClass.Variable;
                }
@@ -4039,10 +4165,21 @@ namespace Mono.CSharp {
                        this.is_readonly = is_readonly;
                }
 
-               public VariableInfo VariableInfo {
+               public override VariableInfo VariableInfo {
                        get { return local_info.VariableInfo; }
                }
 
+               public override HoistedVariable HoistedVariable {
+                       get { return local_info.HoistedVariableReference; }
+               }
+
+               //              
+               // A local variable is always fixed
+               //
+               public override bool IsFixedVariable {
+                       get { return true; }
+               }
+
                public override bool IsRef {
                        get { return false; }
                }
@@ -4051,6 +4188,10 @@ namespace Mono.CSharp {
                        get { return is_readonly; }
                }
 
+               public override string Name {
+                       get { return name; }
+               }
+
                public bool VerifyAssigned (EmitContext ec)
                {
                        VariableInfo variable_info = local_info.VariableInfo;
@@ -4066,6 +4207,11 @@ namespace Mono.CSharp {
                        }
                }
 
+               public override void SetHasAddressTaken ()
+               {
+                       local_info.AddressTaken = true;
+               }
+
                public override Expression CreateExpressionTree (EmitContext ec)
                {
                        ArrayList arg = new ArrayList (1);
@@ -4073,7 +4219,7 @@ namespace Mono.CSharp {
                        return CreateExpressionFactoryCall ("Constant", arg);
                }
 
-               protected Expression DoResolveBase (EmitContext ec)
+               Expression DoResolveBase (EmitContext ec)
                {
                        type = local_info.VariableType;
 
@@ -4081,24 +4227,19 @@ namespace Mono.CSharp {
                        if (e != null)
                                return e.Resolve (ec);
 
-                       if (!VerifyAssigned (ec))
-                               return null;
+                       VerifyAssigned (ec);
 
                        //
                        // If we are referencing a variable from the external block
                        // flag it for capturing
                        //
                        if (ec.MustCaptureVariable (local_info)) {
-                               if (local_info.AddressTaken){
-                                       AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
-                                       return null;
-                               }
+                               if (local_info.AddressTaken)
+                                       AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
 
-                               if (!ec.IsInProbingMode)
-                               {
-                                       ScopeInfo scope = local_info.Block.CreateScopeInfo ();
-                                       variable = scope.AddLocal (local_info);
-                                       type = variable.Type;
+                               if (ec.IsVariableCapturingRequired) {
+                                       AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
+                                       storey.CaptureLocalVariable (ec, local_info);
                                }
                        }
 
@@ -4146,25 +4287,19 @@ namespace Mono.CSharp {
                                        code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
                                } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
                                        code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
+                               } else if (right_side == EmptyExpression.UnaryAddress) {
+                                       code = 459; msg = "Cannot take the address of {1} `{0}'";
                                } else {
                                        code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
                                }
                                Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
-                               return null;
-                       }
-
-                       if (VariableInfo != null)
+                       } else if (VariableInfo != null) {
                                VariableInfo.SetAssigned (ec);
+                       }
 
                        return DoResolveBase (ec);
                }
 
-               public bool VerifyFixed ()
-               {
-                       // A local Variable is always fixed.
-                       return true;
-               }
-
                public override int GetHashCode ()
                {
                        return Name.GetHashCode ();
@@ -4179,8 +4314,8 @@ namespace Mono.CSharp {
                        return Name == lvr.Name && Block == lvr.Block;
                }
 
-               public override Variable Variable {
-                       get { return variable != null ? variable : local_info.Variable; }
+               protected override ILocalVariable Variable {
+                       get { return local_info; }
                }
 
                public override string ToString ()
@@ -4202,49 +4337,51 @@ namespace Mono.CSharp {
        ///   This represents a reference to a parameter in the intermediate
        ///   representation.
        /// </summary>
-       public class ParameterReference : VariableReference, IVariable {
+       public class ParameterReference : VariableReference {
                readonly ToplevelParameterInfo pi;
                readonly ToplevelBlock referenced;
-               Variable variable;
-
-               public bool is_ref, is_out;
 
-               public bool IsOut {
-                       get { return is_out; }
+               public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
+               {
+                       this.pi = pi;
+                       this.referenced = referenced;
+                       this.loc = loc;
                }
 
                public override bool IsRef {
-                       get { return is_ref; }
+                       get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
                }
 
-               public string Name {
-                       get { return Parameter.Name; }
+               bool HasOutModifier {
+                       get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
                }
 
-               public Parameter Parameter {
-                       get { return pi.Parameter; }
+               public override HoistedVariable HoistedVariable {
+                       get { return pi.Parameter.HoistedVariableReference; }
                }
 
-               public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
-               {
-                       this.pi = pi;
-                       this.referenced = referenced;
-                       this.loc = loc;
-                       eclass = ExprClass.Variable;
+               //
+               // A ref or out parameter is classified as a moveable variable, even 
+               // if the argument given for the parameter is a fixed variable
+               //              
+               public override bool IsFixedVariable {
+                       get { return !IsRef; }
                }
 
-               public VariableInfo VariableInfo {
-                       get { return pi.VariableInfo; }
+               public override string Name {
+                       get { return Parameter.Name; }
                }
 
-               public override Variable Variable {
-                       get { return variable != null ? variable : Parameter.Variable; }
+               public Parameter Parameter {
+                       get { return pi.Parameter; }
                }
 
-               public bool VerifyFixed ()
-               {
-                       // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
-                       return Parameter.ModFlags == Parameter.Modifier.NONE;
+               public override VariableInfo VariableInfo {
+                       get { return pi.VariableInfo; }
+               }
+
+               protected override ILocalVariable Variable {
+                       get { return Parameter; }
                }
 
                public bool IsAssigned (EmitContext ec, Location loc)
@@ -4253,68 +4390,54 @@ namespace Mono.CSharp {
                        if (ec.IsInProbingMode)
                                return true;
                        
-                       if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (VariableInfo))
+                       if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
                                return true;
 
                        Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
                        return false;
                }
 
-               public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
+               public override void SetHasAddressTaken ()
                {
-                       if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (VariableInfo, field_name))
-                               return true;
-
-                       Report.Error (170, loc, "Use of possibly unassigned field `{0}'", field_name);
-                       return false;
+                       Parameter.HasAddressTaken = true;
                }
 
-               public void SetAssigned (EmitContext ec)
+               void SetAssigned (EmitContext ec)
                {
-                       if (is_out && ec.DoFlowAnalysis)
+                       if (HasOutModifier && ec.DoFlowAnalysis)
                                ec.CurrentBranching.SetAssigned (VariableInfo);
                }
 
-               public void SetFieldAssigned (EmitContext ec, string field_name)
+               bool DoResolveBase (EmitContext ec)
                {
-                       if (is_out && ec.DoFlowAnalysis)
-                               ec.CurrentBranching.SetFieldAssigned (VariableInfo, field_name);
-               }
-
-               protected bool DoResolveBase (EmitContext ec)
-               {
-                       Parameter par = Parameter;
-                       if (!par.Resolve (ec)) {
-                               //TODO:
-                       }
-
-                       type = par.ParameterType;
-                       Parameter.Modifier mod = par.ModFlags;
-                       is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
-                       is_out = (mod & Parameter.Modifier.OUT) == Parameter.Modifier.OUT;
+                       type = pi.ParameterType;
                        eclass = ExprClass.Variable;
 
-                       AnonymousContainer am = ec.CurrentAnonymousMethod;
+                       AnonymousExpression am = ec.CurrentAnonymousMethod;
                        if (am == null)
                                return true;
 
                        ToplevelBlock declared = pi.Block;
-                       if (is_ref && declared != referenced) {
-                               Report.Error (1628, Location,
-                                             "Cannot use ref or out parameter `{0}' inside an " +
-                                             "anonymous method block", par.Name);
-                               return false;
+                       if (declared != referenced) {
+                               if (IsRef) {
+                                       Report.Error (1628, loc,
+                                               "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
+                                               Name, am.ContainerType);
+                                       return false;
+                               }
+                       } else {
+                               if (!am.IsIterator)
+                                       return true;
                        }
 
-                       if (!am.IsIterator && declared == referenced)
-                               return true;
+                       if (ec.IsVariableCapturingRequired) {
+                               if (pi.Parameter.HasAddressTaken)
+                                       AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
 
-                       // Don't capture aruments when the probing is on
-                       if (!ec.IsInProbingMode) {
-                               ScopeInfo scope = declared.CreateScopeInfo ();
-                               variable = scope.AddParameter (par, pi.Index);
-                               type = variable.Type;
+                               AnonymousMethodStorey storey = declared.CreateAnonymousMethodStorey (ec);
+                               storey.CaptureParameter (ec, this);
                        }
+
                        return true;
                }
 
@@ -4331,9 +4454,17 @@ namespace Mono.CSharp {
 
                        return Name == pr.Name && referenced == pr.referenced;
                }
+               
+               protected override void CloneTo (CloneContext clonectx, Expression target)
+               {
+                       // Nothing to clone
+               }
 
                public override Expression CreateExpressionTree (EmitContext ec)
                {
+                       if (IsHoistedEmitRequired (ec))
+                               return HoistedVariable.CreateExpressionTree (ec);
+
                        return Parameter.ExpressionTreeVariableReference ();
                }
 
@@ -4354,7 +4485,7 @@ namespace Mono.CSharp {
                        if (!DoResolveBase (ec))
                                return null;
 
-                       if (is_out && ec.DoFlowAnalysis &&
+                       if (HasOutModifier && ec.DoFlowAnalysis &&
                            (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
                                return null;
 
@@ -4386,11 +4517,6 @@ namespace Mono.CSharp {
                        } else
                                ig.Emit (OpCodes.Ldarg, x);
                }
-               
-               public override string ToString ()
-               {
-                       return "ParameterReference[" + Name + "]";
-               }
        }
        
        /// <summary>
@@ -4422,12 +4548,7 @@ namespace Mono.CSharp {
                }
 
                public Type Type {
-                       get {
-                               if (ArgType == AType.Ref || ArgType == AType.Out)
-                                       return TypeManager.GetReferenceType (Expr.Type);
-                               else
-                                       return Expr.Type;
-                       }
+                       get { return Expr.Type; }
                }
 
                public Parameter.Modifier Modifier
@@ -4451,7 +4572,7 @@ namespace Mono.CSharp {
                        if (Expr.eclass == ExprClass.MethodGroup)
                                return Expr.ExprClassName;
 
-                       return Expr.GetSignatureForError ();
+                       return TypeManager.CSharpName (Expr.Type);
                }               
 
                public bool ResolveMethodGroup (EmitContext ec)
@@ -4471,6 +4592,9 @@ namespace Mono.CSharp {
 
                public bool Resolve (EmitContext ec, Location loc)
                {
+                       if (Expr == null)
+                               return false;
+
                        using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
                                // Verify that the argument is readable
                                if (ArgType != AType.Out)
@@ -4559,13 +4683,29 @@ namespace Mono.CSharp {
                                return CreateExpressionFactoryCall ("Quote", args);
                        }
 
-                       args = new ArrayList (Arguments == null ? 2 : Arguments.Count + 2);
+                       ExtensionMethodGroupExpr emg = mg as ExtensionMethodGroupExpr;
+
+                       int arg_count = Arguments == null ? 2 : Arguments.Count + 2;
+                       if (emg != null)
+                               ++arg_count;
+                       args = new ArrayList (arg_count);
+
                        if (mg.IsInstance)
                                args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
                        else
                                args.Add (new Argument (new NullLiteral (loc)));
 
                        args.Add (new Argument (mg.CreateExpressionTree (ec)));
+
+                       //
+                       // Use extension argument when exists
+                       //
+                       if (emg != null) {
+                               Expression e = emg.ExtensionExpression.CreateExpressionTree (ec);
+                               if (e != null)
+                                       args.Add (new Argument (e));
+                       }
+
                        if (Arguments != null) {
                                foreach (Argument a in Arguments) {
                                        Expression e = a.Expr.CreateExpressionTree (ec);
@@ -4574,6 +4714,9 @@ namespace Mono.CSharp {
                                }
                        }
 
+                       if (mg.IsBase)
+                               MemberExpr.Error_BaseAccessInExpressionTree (loc);
+
                        return CreateExpressionFactoryCall ("Call", args);
                }
 
@@ -4668,9 +4811,7 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       if (IsSpecialMethodInvocation (method)) {
-                               return null;
-                       }
+                       IsSpecialMethodInvocation (method, loc);
                        
                        if (mg.InstanceExpression != null)
                                mg.InstanceExpression.CheckMarshalByRefAccess (ec);
@@ -4684,7 +4825,7 @@ namespace Mono.CSharp {
                        return mg.OverloadResolve (ec, ref Arguments, false, loc);
                }
 
-               bool IsSpecialMethodInvocation (MethodBase method)
+               public static bool IsSpecialMethodInvocation (MethodBase method, Location loc)
                {
                        if (!TypeManager.IsSpecialMethod (method))
                                return false;
@@ -4745,11 +4886,8 @@ namespace Mono.CSharp {
 
                static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
                {
-                       ParameterData pd = TypeManager.GetParameterData (mb);
-
-                       if (arguments == null)
-                               return new Type [0];
-
+                       AParametersCollection pd = TypeManager.GetParameterData (mb);
+                       
                        Argument a = (Argument) arguments [pd.Count - 1];
                        Arglist list = (Arglist) a.Expr;
 
@@ -4759,7 +4897,7 @@ namespace Mono.CSharp {
                /// <summary>
                /// This checks the ConditionalAttribute on the method 
                /// </summary>
-               public static bool IsMethodExcluded (MethodBase method)
+               public static bool IsMethodExcluded (MethodBase method, Location loc)
                {
                        if (method.IsConstructor)
                                return false;
@@ -4775,7 +4913,7 @@ namespace Mono.CSharp {
                                return false;
                        }
 
-                       return AttributeTester.IsConditionalMethodExcluded (method);
+                       return AttributeTester.IsConditionalMethodExcluded (method, loc);
                }
 
                /// <remarks>
@@ -4832,7 +4970,7 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       if (IsMethodExcluded (method))
+                       if (IsMethodExcluded (method, loc))
                                return;
                        
                        bool is_static = method.IsStatic;
@@ -4934,7 +5072,7 @@ namespace Mono.CSharp {
                        else
                                ig.Emit (call_op, (ConstructorInfo) method);
                }
-               
+
                public override void Emit (EmitContext ec)
                {
                        mg.EmitCall (ec, Arguments);
@@ -4963,8 +5101,20 @@ namespace Mono.CSharp {
 
                        target.expr = expr.Clone (clonectx);
                }
+
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       mg.MutateHoistedGenericType (storey);
+                       if (Arguments != null) {
+                               foreach (Argument a in Arguments)
+                                       a.Expr.MutateHoistedGenericType (storey);
+                       }
+               }
        }
 
+       //
+       // It's either a cast or delegate invocation
+       //
        public class InvocationOrCast : ExpressionStatement
        {
                Expression expr;
@@ -4977,15 +5127,28 @@ namespace Mono.CSharp {
                        this.loc = expr.Location;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       throw new NotSupportedException ("ET");
+               }
+
                public override Expression DoResolve (EmitContext ec)
+               {
+                       Expression e = ResolveCore (ec);
+                       if (e == null)
+                               return null;
+
+                       return e.Resolve (ec);
+               }
+
+               Expression ResolveCore (EmitContext ec)
                {
                        //
                        // First try to resolve it as a cast.
                        //
-                       TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
-                       if ((te != null) && (te.eclass == ExprClass.Type)) {
-                               Cast cast = new Cast (te, argument, loc);
-                               return cast.Resolve (ec);
+                       TypeExpr te = expr.ResolveAsBaseTerminal (ec, true);
+                       if (te != null) {
+                               return new Cast (te, argument, loc);
                        }
 
                        //
@@ -4999,11 +5162,15 @@ namespace Mono.CSharp {
                        //
                        // Ok, so it's a Cast.
                        //
-                       if (expr.eclass == ExprClass.Type) {
-                               Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
-                               return cast.Resolve (ec);
+                       if (expr.eclass == ExprClass.Type || expr.eclass == ExprClass.TypeParameter) {
+                               return new Cast (expr, argument, loc);
                        }
 
+                       if (expr.eclass == ExprClass.Namespace) {
+                               expr.Error_UnexpectedKind (null, "type", loc);
+                               return null;
+                       }                       
+
                        //
                        // It's a delegate invocation.
                        //
@@ -5012,45 +5179,24 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       ArrayList args = new ArrayList ();
+                       ArrayList args = new ArrayList (1);
                        args.Add (new Argument (argument, Argument.AType.Expression));
-                       DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
-                       return invocation.Resolve (ec);
+                       return new DelegateInvocation (expr, args, loc);
                }
 
                public override ExpressionStatement ResolveStatement (EmitContext ec)
                {
-                       //
-                       // First try to resolve it as a cast.
-                       //
-                       TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
-                       if ((te != null) && (te.eclass == ExprClass.Type)) {
-                               Error_InvalidExpressionStatement ();
+                       Expression e = ResolveCore (ec);
+                       if (e == null)
                                return null;
-                       }
 
-                       //
-                       // This can either be a type or a delegate invocation.
-                       // Let's just resolve it and see what we'll get.
-                       //
-                       expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
-                       if ((expr == null) || (expr.eclass == ExprClass.Type)) {
+                       ExpressionStatement s = e as ExpressionStatement;
+                       if (s == null) {
                                Error_InvalidExpressionStatement ();
                                return null;
                        }
 
-                       //
-                       // It's a delegate invocation.
-                       //
-                       if (!TypeManager.IsDelegateType (expr.Type)) {
-                               Error (149, "Method name expected");
-                               return null;
-                       }
-
-                       ArrayList args = new ArrayList ();
-                       args.Add (new Argument (argument, Argument.AType.Expression));
-                       DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
-                       return invocation.ResolveStatement (ec);
+                       return s.ResolveStatement (ec);
                }
 
                public override void Emit (EmitContext ec)
@@ -5076,7 +5222,7 @@ namespace Mono.CSharp {
        // This class is used to "disable" the code generation for the
        // temporary variable when initializing value types.
        //
-       class EmptyAddressOf : EmptyExpression, IMemoryLocation {
+       sealed class EmptyAddressOf : EmptyExpression, IMemoryLocation {
                public void AddressOf (EmitContext ec, AddressOp Mode)
                {
                        // nothing
@@ -5256,11 +5402,6 @@ namespace Mono.CSharp {
 
                        type = texpr.Type;
 
-                       if (type == TypeManager.void_type) {
-                               Error_VoidInvalidInTheContext (loc);
-                               return null;
-                       }
-
                        if (type.IsPointer) {
                                Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
                                        TypeManager.CSharpName (type));
@@ -5274,11 +5415,7 @@ namespace Mono.CSharp {
                        }
 
                        if (TypeManager.IsDelegateType (type)) {
-                               RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
-                               if (RequestedType != null)
-                                       if (!(RequestedType is DelegateCreation))
-                                               throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
-                               return RequestedType;
+                               return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
                        }
 
 #if GMCS_SOURCE
@@ -5472,7 +5609,12 @@ namespace Mono.CSharp {
                                 }
                                 return false;
                        } else {
-                               ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
+                               ConstructorInfo ci = (ConstructorInfo) method;
+#if MS_COMPATIBLE
+                               if (TypeManager.IsGenericType (type))
+                                       ci = TypeBuilder.GetConstructor (type, ci);
+#endif
+                               ig.Emit (OpCodes.Newobj, ci);
                                return true;
                        }
                }
@@ -5552,6 +5694,19 @@ namespace Mono.CSharp {
                                }
                        }
                }
+
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       if (method != null) {
+                               method.MutateHoistedGenericType (storey);
+                               if (Arguments != null) {
+                                       foreach (Argument a in Arguments)
+                                               a.Expr.MutateHoistedGenericType (storey);
+                               }
+                       }
+
+                       type = storey.MutateType (type);
+               }
        }
 
        /// <summary>
@@ -5595,7 +5750,7 @@ namespace Mono.CSharp {
                        this.rank = rank;
                        loc = l;
 
-                       arguments = new ArrayList ();
+                       arguments = new ArrayList (exprs.Count);
 
                        foreach (Expression e in exprs) {
                                arguments.Add (new Argument (e, Argument.AType.Expression));
@@ -5638,7 +5793,7 @@ namespace Mono.CSharp {
 
                                Constant c = a.Expr as Constant;
                                if (c != null) {
-                                       c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
+                                       c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Expr.Location);
                                }
 
                                if (c == null) {
@@ -5713,25 +5868,36 @@ namespace Mono.CSharp {
                {
                        ArrayList args;
 
-                       if (dimensions != 1) {
-                               if (initializers != null) {
-                                       Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
-                                       return null;
-                               }
-
+                       if (array_data == null) {
                                args = new ArrayList (arguments.Count + 1);
                                args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
-                               foreach (Argument a in arguments)
+                               foreach (Argument a in arguments) {
+                                       if (arguments.Count == 1) {
+                                               Constant c = a.Expr as Constant;
+                                               if (c.IsDefaultValue)
+                                                       return CreateExpressionFactoryCall ("NewArrayInit", args);
+                                       }
                                        args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
+                               }
 
                                return CreateExpressionFactoryCall ("NewArrayBounds", args);
                        }
 
+                       if (dimensions > 1) {
+                               Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
+                               return null;
+                       }
+
                        args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
                        args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
                        if (array_data != null) {
-                               foreach (Expression e in array_data)
+                               for (int i = 0; i < array_data.Count; ++i) {
+                                       Expression e = (Expression) array_data [i];
+                                       if (e == null)
+                                               e = Convert.ImplicitConversion (ec, (Expression) initializers [i], array_element_type, loc);
+
                                        args.Add (new Argument (e.CreateExpressionTree (ec)));
+                               }
                        }
 
                        return CreateExpressionFactoryCall ("NewArrayInit", args);
@@ -5760,12 +5926,22 @@ namespace Mono.CSharp {
 
                }
 
+               Expression first_emit;
+               LocalTemporary first_emit_temp;
+
                protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
                {
                        element = element.Resolve (ec);
                        if (element == null)
                                return null;
 
+                       if (element is CompoundAssign.Helper) {
+                               if (first_emit != null)
+                                       throw new InternalErrorException ("Can only handle one mutator at a time");
+                               first_emit = element;
+                               element = first_emit_temp = new LocalTemporary (element.Type);
+                       }
+
                        return Convert.ImplicitConversionRequired (
                                ec, element, array_element_type, loc);
                }
@@ -5805,6 +5981,11 @@ namespace Mono.CSharp {
                                Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
                                return false;
                        }
+
+                       if (requested_base_type is VarExpr) {
+                               Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
+                               return false;
+                       }
                        
                        StringBuilder array_qualifier = new StringBuilder (rank);
 
@@ -5842,11 +6023,6 @@ namespace Mono.CSharp {
 
                        if (!ResolveArrayType (ec))
                                return null;
-                       
-                       if ((array_element_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
-                               Report.Error (719, loc, "`{0}': array elements cannot be of static type",
-                                       TypeManager.CSharpName (array_element_type));
-                       }
 
                        //
                        // First step is to validate the initializers and fill
@@ -6040,6 +6216,21 @@ namespace Mono.CSharp {
                        return data;
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       array_element_type = storey.MutateType (array_element_type);
+                       type = storey.MutateType (type);
+                       if (arguments != null) {
+                               foreach (Argument a in arguments)
+                                       a.Expr.MutateHoistedGenericType (storey);
+                       }
+                       
+                       if (array_data != null) {
+                               foreach (Expression e in array_data)
+                                       e.MutateHoistedGenericType (storey);
+                       }
+               }
+
                //
                // Emits the initializers for the array
                //
@@ -6162,6 +6353,11 @@ namespace Mono.CSharp {
                {
                        ILGenerator ig = ec.ig;
 
+                       if (first_emit != null) {
+                               first_emit.Emit (ec);
+                               first_emit_temp.Store (ec);
+                       }
+
                        foreach (Argument a in arguments)
                                a.Emit (ec);
 
@@ -6185,14 +6381,17 @@ namespace Mono.CSharp {
                                        EmitDynamicInitializers (ec, false);
                        } else {
                                EmitDynamicInitializers (ec, true);
-                       }                               
+                       }
+
+                       if (first_emit_temp != null)
+                               first_emit_temp.Release (ec);
                }
 
-               public override bool GetAttributableValue (Type value_type, out object value)
+               public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
                {
                        if (arguments.Count != 1) {
                                // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
-                               return base.GetAttributableValue (null, out value);
+                               return base.GetAttributableValue (ec, null, out value);
                        }
 
                        if (array_data == null) {
@@ -6202,7 +6401,7 @@ namespace Mono.CSharp {
                                        return true;
                                }
                                // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
-                               return base.GetAttributableValue (null, out value);
+                               return base.GetAttributableValue (ec, null, out value);
                        }
                        
                        Array ret = Array.CreateInstance (array_element_type, array_data.Count);
@@ -6215,7 +6414,7 @@ namespace Mono.CSharp {
                                if (e == null) 
                                        continue;
 
-                               if (!e.GetAttributableValue (array_element_type, out element_value)) {
+                               if (!e.GetAttributableValue (ec, array_element_type, out element_value)) {
                                        value = null;
                                        return false;
                                }
@@ -6283,7 +6482,7 @@ namespace Mono.CSharp {
                        if (array_element_type == null || array_element_type == TypeManager.null_type ||
                                array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
                                arguments.Count != dimensions) {
-                               Report.Error (826, loc, "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
+                               Error_NoBestType ();
                                return null;
                        }
 
@@ -6299,6 +6498,12 @@ namespace Mono.CSharp {
                        return this;
                }
 
+               void Error_NoBestType ()
+               {
+                       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
                //
@@ -6331,8 +6536,8 @@ namespace Mono.CSharp {
                                return element;
                        }
 
-                       element.Error_ValueCannotBeConverted (ec, element.Location, array_element_type, false);
-                       return element;
+                       Error_NoBestType ();
+                       return null;
                }
        }       
        
@@ -6345,24 +6550,53 @@ namespace Mono.CSharp {
                {
                }
 
+               public CompilerGeneratedThis (Type type, Location loc)
+                       : base (loc)
+               {
+                       this.type = type;
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        eclass = ExprClass.Variable;
-                       type = ec.ContainerType;
-                       variable = new SimpleThis (type);
+                       if (type == null)
+                               type = ec.ContainerType;
                        return this;
                }
+
+               public override HoistedVariable HoistedVariable {
+                       get { return null; }
+               }
        }
        
        /// <summary>
        ///   Represents the `this' construct
        /// </summary>
 
-       public class This : VariableReference, IVariable
+       public class This : VariableReference
        {
+               sealed class ThisVariable : ILocalVariable
+               {
+                       public static readonly ILocalVariable Instance = new ThisVariable ();
+
+                       public void Emit (EmitContext ec)
+                       {
+                               ec.ig.Emit (OpCodes.Ldarg_0);
+                       }
+
+                       public void EmitAssign (EmitContext ec)
+                       {
+                               throw new InvalidOperationException ();
+                       }
+
+                       public void EmitAddressOf (EmitContext ec)
+                       {
+                               ec.ig.Emit (OpCodes.Ldarg_0);
+                       }
+               }
+
                Block block;
                VariableInfo variable_info;
-               protected Variable variable;
                bool is_struct;
 
                public This (Block block, Location loc)
@@ -6376,25 +6610,63 @@ namespace Mono.CSharp {
                        this.loc = loc;
                }
 
-               public VariableInfo VariableInfo {
+               public override VariableInfo VariableInfo {
                        get { return variable_info; }
                }
 
-               public bool VerifyFixed ()
+               public override bool IsFixedVariable {
+                       get { return !TypeManager.IsValueType (type); }
+               }
+
+               protected override bool IsHoistedEmitRequired (EmitContext ec)
                {
-                       return !TypeManager.IsValueType (Type);
+                       //
+                       // Handle 'this' differently, it cannot be assigned hence
+                       // when we are not inside anonymous method we can emit direct access 
+                       //
+                       return ec.CurrentAnonymousMethod != null && base.IsHoistedEmitRequired (ec);
+               }
+
+               public override HoistedVariable HoistedVariable {
+                       get { return TopToplevelBlock.HoistedThisVariable; }
                }
 
                public override bool IsRef {
                        get { return is_struct; }
                }
 
-               public override Variable Variable {
-                       get { return variable; }
+               protected override ILocalVariable Variable {
+                       get { return ThisVariable.Instance; }
+               }
+
+               // TODO: Move to ToplevelBlock
+               ToplevelBlock TopToplevelBlock {
+                       get {
+                               ToplevelBlock tl = block.Toplevel;
+                               while (tl.Parent != null) tl = tl.Parent.Toplevel;
+                               return tl;
+                       }
+               }
+
+               public static bool IsThisAvailable (EmitContext ec)
+               {
+                       if (ec.IsStatic || ec.IsInFieldInitializer)
+                               return false;
+
+                       if (ec.CurrentAnonymousMethod == null)
+                               return true;
+
+                       if (ec.TypeContainer is Struct && ec.CurrentIterator == null)
+                               return false;
+
+                       return true;
                }
 
                public bool ResolveBase (EmitContext ec)
                {
+                       if (eclass != ExprClass.Invalid)
+                               return true;
+
                        eclass = ExprClass.Variable;
 
                        if (ec.TypeContainer.CurrentType != null)
@@ -6402,38 +6674,36 @@ namespace Mono.CSharp {
                        else
                                type = ec.ContainerType;
 
-                       is_struct = ec.TypeContainer is Struct;
-
-                       if (ec.IsStatic) {
-                               Error (26, "Keyword `this' is not valid in a static property, " +
-                                      "static method, or static field initializer");
-                               return false;
+                       if (!IsThisAvailable (ec)) {
+                               if (ec.IsStatic) {
+                                       Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer");
+                               } else {
+                                       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");
+                               }
                        }
 
+                       is_struct = ec.TypeContainer is Struct;
+
                        if (block != null) {
                                if (block.Toplevel.ThisVariable != null)
                                        variable_info = block.Toplevel.ThisVariable.VariableInfo;
 
-                               AnonymousContainer am = ec.CurrentAnonymousMethod;
-                               if (is_struct && (am != null) && !am.IsIterator) {
-                                       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.");
-                               }
-
-                               RootScopeInfo host = block.Toplevel.RootScope;
-                               if ((host != null) && !ec.IsConstructor &&
-                                   (!is_struct || host.IsIterator)) {
-                                       variable = host.CaptureThis ();
-                                       type = variable.Type;
-                                       is_struct = false;
+                               AnonymousExpression am = ec.CurrentAnonymousMethod;
+                               if (am != null) {
+                                       //
+                                       // this is hoisted to very top level block
+                                       //
+                                       if (ec.IsVariableCapturingRequired) {
+                                               // TODO: it could be optimized
+                                               AnonymousMethodStorey scope = TopToplevelBlock.Explicit.CreateAnonymousMethodStorey (ec);
+                                               if (HoistedVariable == null) {
+                                                       TopToplevelBlock.HoistedThisVariable = scope.CaptureThis (ec, this);
+                                               }
+                                       }
                                }
                        }
-
-                       if (variable == null)
-                               variable = new SimpleThis (type);
                        
                        return true;
                }
@@ -6480,19 +6750,28 @@ namespace Mono.CSharp {
 
                        if (variable_info != null)
                                variable_info.SetAssigned (ec);
-                       
+
                        if (ec.TypeContainer is Class){
-                               Error (1604, "Cannot assign to 'this' because it is read-only");
-                               return null;
+                               if (right_side == EmptyExpression.UnaryAddress)
+                                       Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
+                               else if (right_side == EmptyExpression.OutAccess)
+                                       Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
+                               else
+                                       Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
                        }
 
                        return this;
                }
+
                public override int GetHashCode()
                {
                        return block.GetHashCode ();
                }
 
+               public override string Name {
+                       get { return "this"; }
+               }
+
                public override bool Equals (object obj)
                {
                        This t = obj as This;
@@ -6502,53 +6781,21 @@ namespace Mono.CSharp {
                        return block == t.block;
                }
 
-               protected class SimpleThis : Variable
+               protected override void CloneTo (CloneContext clonectx, Expression t)
                {
-                       Type type;
-
-                       public SimpleThis (Type type)
-                       {
-                               this.type = type;
-                       }
-
-                       public override Type Type {
-                               get { return type; }
-                       }
-
-                       public override bool HasInstance {
-                               get { return false; }
-                       }
-
-                       public override bool NeedsTemporary {
-                               get { return false; }
-                       }
-
-                       public override void EmitInstance (EmitContext ec)
-                       {
-                               // Do nothing.
-                       }
-
-                       public override void Emit (EmitContext ec)
-                       {
-                               ec.ig.Emit (OpCodes.Ldarg_0);
-                       }
-
-                       public override void EmitAssign (EmitContext ec)
-                       {
-                               throw new InvalidOperationException ();
-                       }
+                       This target = (This) t;
 
-                       public override void EmitAddressOf (EmitContext ec)
-                       {
-                               ec.ig.Emit (OpCodes.Ldarg_0);
-                       }
+                       target.block = clonectx.LookupBlock (block);
                }
 
-               protected override void CloneTo (CloneContext clonectx, Expression t)
+               public void RemoveHoisting ()
                {
-                       This target = (This) t;
+                       TopToplevelBlock.HoistedThisVariable = null;
+               }
 
-                       target.block = clonectx.LookupBlock (block);
+               public override void SetHasAddressTaken ()
+               {
+                       // Nothing
                }
        }
 
@@ -6562,12 +6809,17 @@ namespace Mono.CSharp {
                        this.loc = loc;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       throw new NotSupportedException ("ET");
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        eclass = ExprClass.Variable;
                        type = TypeManager.runtime_argument_handle_type;
 
-                       if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs
+                       if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.Parameters.HasArglist
                        {
                                Error (190, "The __arglist construct is valid only within " +
                                       "a variable argument method");
@@ -6640,6 +6892,12 @@ namespace Mono.CSharp {
                                arg.Emit (ec);
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       foreach (Argument arg in Arguments)
+                               arg.Expr.MutateHoistedGenericType (storey);
+               }
+
                protected override void CloneTo (CloneContext clonectx, Expression t)
                {
                        Arglist target = (Arglist) t;
@@ -6650,29 +6908,6 @@ namespace Mono.CSharp {
                }
        }
 
-       //
-       // This produces the value that renders an instance, used by the iterators code
-       //
-       public class ProxyInstance : Expression, IMemoryLocation  {
-               public override Expression DoResolve (EmitContext ec)
-               {
-                       eclass = ExprClass.Variable;
-                       type = ec.ContainerType;
-                       return this;
-               }
-               
-               public override void Emit (EmitContext ec)
-               {
-                       ec.ig.Emit (OpCodes.Ldarg_0);
-
-               }
-               
-               public void AddressOf (EmitContext ec, AddressOp mode)
-               {
-                       ec.ig.Emit (OpCodes.Ldarg_0);
-               }
-       }
-
        /// <summary>
        ///   Implements the typeof operator
        /// </summary>
@@ -6739,7 +6974,7 @@ namespace Mono.CSharp {
                        ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
                }
 
-               public override bool GetAttributableValue (Type value_type, out object value)
+               public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
                {
                        if (TypeManager.ContainsGenericParameters (typearg) &&
                                !TypeManager.IsGenericTypeDefinition (typearg)) {
@@ -6758,10 +6993,13 @@ namespace Mono.CSharp {
                        return true;
                }
 
-               public Type TypeArgument
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
                {
-                       get
-                       {
+                       typearg = storey.MutateType (typearg);
+               }
+
+               public Type TypeArgument {
+                       get {
                                return typearg;
                        }
                }
@@ -6769,8 +7007,8 @@ namespace Mono.CSharp {
                protected override void CloneTo (CloneContext clonectx, Expression t)
                {
                        TypeOf target = (TypeOf) t;
-
-                       target.QueriedType = QueriedType.Clone (clonectx);
+                       if (QueriedType != null)
+                               target.QueriedType = QueriedType.Clone (clonectx);
                }
        }
 
@@ -6906,6 +7144,11 @@ namespace Mono.CSharp {
                        this.loc = loc;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       throw new NotSupportedException ("ET");
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        if (TypeManager.fieldinfo_get_field_from_handle == null) {
@@ -6942,6 +7185,12 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       Error_PointerInsideExpressionTree ();
+                       return null;
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
@@ -6952,11 +7201,6 @@ namespace Mono.CSharp {
                        if (TypeManager.IsEnumType (type_queried))
                                type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
 
-                       if (type_queried == TypeManager.void_type) {
-                               Expression.Error_VoidInvalidInTheContext (loc);
-                               return null;
-                       }
-
                        int size_of = GetTypeSize (type_queried);
                        if (size_of > 0) {
                                return new IntConstant (size_of, loc);
@@ -6998,6 +7242,7 @@ namespace Mono.CSharp {
        public class QualifiedAliasMember : MemberAccess
        {
                readonly string alias;
+               public static readonly string GlobalAlias = "global";
 
                public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
                        : base (null, identifier, targs, l)
@@ -7013,7 +7258,7 @@ namespace Mono.CSharp {
 
                public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
                {
-                       if (alias == "global") {
+                       if (alias == GlobalAlias) {
                                expr = RootNamespace.Global;
                                return base.ResolveAsTypeStep (ec, silent);
                        }
@@ -7418,7 +7663,7 @@ namespace Mono.CSharp {
                        if (Expr == null)
                                return null;
 
-                       if (Expr is Constant)
+                       if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
                                return Expr;
                        
                        eclass = Expr.eclass;
@@ -7438,6 +7683,11 @@ namespace Mono.CSharp {
                                Expr.EmitBranchable (ec, target, on_true);
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       Expr.MutateHoistedGenericType (storey);
+               }
+
                protected override void CloneTo (CloneContext clonectx, Expression t)
                {
                        CheckedExpr target = (CheckedExpr) t;
@@ -7473,7 +7723,7 @@ namespace Mono.CSharp {
                        if (Expr == null)
                                return null;
 
-                       if (Expr is Constant)
+                       if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
                                return Expr;
                        
                        eclass = Expr.eclass;
@@ -7493,6 +7743,11 @@ namespace Mono.CSharp {
                                Expr.EmitBranchable (ec, target, on_true);
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       Expr.MutateHoistedGenericType (storey);
+               }
+
                protected override void CloneTo (CloneContext clonectx, Expression t)
                {
                        UnCheckedExpr target = (UnCheckedExpr) t;
@@ -7514,16 +7769,14 @@ namespace Mono.CSharp {
                public ElementAccess (Expression e, ArrayList e_list)
                {
                        Expr = e;
-
                        loc  = e.Location;
                        
                        if (e_list == null)
                                return;
                        
-                       Arguments = new ArrayList ();
+                       Arguments = new ArrayList (e_list.Count);
                        foreach (Expression tmp in e_list)
                                Arguments.Add (new Argument (tmp, Argument.AType.Expression));
-                       
                }
 
                bool CommonResolve (EmitContext ec)
@@ -7553,17 +7806,12 @@ namespace Mono.CSharp {
 
                Expression MakePointerAccess (EmitContext ec, Type t)
                {
-                       if (t == TypeManager.void_ptr_type){
-                               Error (242, "The array index operation is not valid on void pointers");
-                               return null;
-                       }
                        if (Arguments.Count != 1){
                                Error (196, "A pointer must be indexed by only one value");
                                return null;
                        }
-                       Expression p;
 
-                       p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
+                       Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, ((Argument) Arguments [0]).Expr, t, loc).Resolve (ec);
                        if (p == null)
                                return null;
                        return new Indirection (p, loc).Resolve (ec);
@@ -7651,14 +7899,12 @@ namespace Mono.CSharp {
                ElementAccess ea;
 
                LocalTemporary temp;
-               LocalTemporary prepared_value;
 
                bool prepared;
                
                public ArrayAccess (ElementAccess ea_data, Location l)
                {
                        ea = ea_data;
-                       eclass = ExprClass.Variable;
                        loc = l;
                }
 
@@ -7685,6 +7931,9 @@ namespace Mono.CSharp {
                        }
 #endif
 
+                       if (eclass != ExprClass.Invalid)
+                               return this;
+
                        Type t = ea.Expr.Type;
                        int rank = ea.Arguments.Count;
                        if (t.GetArrayRank () != rank) {
@@ -7693,11 +7942,6 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       if (rank != 1 && TypeManager.int_getlength_int == null) {
-                               TypeManager.int_getlength_int = TypeManager.GetPredefinedMethod (
-                                       TypeManager.array_type, "GetLength", loc, TypeManager.int32_type);
-                       }
-
                        type = TypeManager.GetElementType (t);
                        if (type.IsPointer && !ec.InUnsafe) {
                                UnsafeError (ea.Location);
@@ -7860,36 +8104,13 @@ namespace Mono.CSharp {
                //
                // Load the array arguments into the stack.
                //
-               // If we have been requested to cache the values (cached_locations array
-               // initialized), then load the arguments the first time and store them
-               // in locals.  otherwise load from local variables.
-               //
-               // prepare_for_load is used in compound assignments to cache original index
-               // values ( label[idx++] += s )
-               //
-               LocalTemporary [] LoadArrayAndArguments (EmitContext ec, bool prepare_for_load)
+               void LoadArrayAndArguments (EmitContext ec)
                {
                        ea.Expr.Emit (ec);
 
-                       LocalTemporary[] indexes = null;
-                       if (prepare_for_load) {
-                               ec.ig.Emit (OpCodes.Dup);
-                               indexes = new LocalTemporary [ea.Arguments.Count];
-                       }
-
                        for (int i = 0; i < ea.Arguments.Count; ++i) {
                                ((Argument)ea.Arguments [i]).Emit (ec);
-                               if (!prepare_for_load)
-                                       continue;
-
-                               // Keep original array index value on the stack
-                               ec.ig.Emit (OpCodes.Dup);
-
-                               indexes [i] = new LocalTemporary (TypeManager.intptr_type);
-                               indexes [i].Store (ec);
                        }
-
-                       return indexes;
                }
 
                public void Emit (EmitContext ec, bool leave_copy)
@@ -7897,12 +8118,10 @@ namespace Mono.CSharp {
                        int rank = ea.Expr.Type.GetArrayRank ();
                        ILGenerator ig = ec.ig;
 
-                       if (prepared_value != null) {
-                               prepared_value.Emit (ec);
-                       } else if (prepared) {
+                       if (prepared) {
                                LoadFromPtr (ig, this.type);
                        } else {
-                               LoadArrayAndArguments (ec, false);
+                               LoadArrayAndArguments (ec);
                                EmitLoadOpcode (ig, type, rank);
                        }       
 
@@ -7923,24 +8142,13 @@ namespace Mono.CSharp {
                        int rank = ea.Expr.Type.GetArrayRank ();
                        ILGenerator ig = ec.ig;
                        Type t = source.Type;
-                       prepared = prepare_for_load && !(source is StringConcat);
+                       prepared = prepare_for_load;
 
                        if (prepared) {
                                AddressOf (ec, AddressOp.LoadStore);
                                ec.ig.Emit (OpCodes.Dup);
                        } else {
-                               LocalTemporary[] original_indexes_values = LoadArrayAndArguments (ec,
-                                       prepare_for_load && (source is StringConcat));
-
-                               if (original_indexes_values != null) {
-                                       prepared_value = new LocalTemporary (type);
-                                       EmitLoadOpcode (ig, type, rank);
-                                       prepared_value.Store (ec);
-                                       foreach (LocalTemporary lt in original_indexes_values) {
-                                               lt.Emit (ec);
-                                               lt.Release (ec);
-                                       }
-                               }
+                               LoadArrayAndArguments (ec);
                        }
 
                        if (rank == 1) {
@@ -8012,7 +8220,7 @@ namespace Mono.CSharp {
                        int rank = ea.Expr.Type.GetArrayRank ();
                        ILGenerator ig = ec.ig;
 
-                       LoadArrayAndArguments (ec, false);
+                       LoadArrayAndArguments (ec);
 
                        if (rank == 1){
                                ig.Emit (OpCodes.Ldelema, type);
@@ -8022,19 +8230,9 @@ namespace Mono.CSharp {
                        }
                }
 
-               public void EmitGetLength (EmitContext ec, int dim)
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
                {
-                       int rank = ea.Expr.Type.GetArrayRank ();
-                       ILGenerator ig = ec.ig;
-
-                       ea.Expr.Emit (ec);
-                       if (rank == 1) {
-                               ig.Emit (OpCodes.Ldlen);
-                               ig.Emit (OpCodes.Conv_I4);
-                       } else {
-                               IntLiteral.EmitInt (ig, dim);
-                               ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
-                       }
+                       type = storey.MutateType (type);
                }
        }
 
@@ -8057,7 +8255,7 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       protected override int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
+                       protected override int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
                        {
                                //
                                // Here is the trick, decrease number of arguments by 1 when only
@@ -8198,6 +8396,17 @@ namespace Mono.CSharp {
                        throw new NotImplementedException (at.ToString ());
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       ArrayList args = new ArrayList (arguments.Count + 2);
+                       args.Add (new Argument (instance_expr.CreateExpressionTree (ec)));
+                       args.Add (new Argument (new TypeOfMethodInfo (get, loc)));
+                       foreach (Argument a in arguments)
+                               args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
+
+                       return CreateExpressionFactoryCall ("Call", args);
+               }
+
                protected virtual bool CommonResolve (EmitContext ec)
                {
                        indexer_type = instance_expr.Type;
@@ -8378,6 +8587,20 @@ namespace Mono.CSharp {
                        return TypeManager.CSharpSignature (get != null ? get : set, false);
                }
 
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       if (get != null)
+                               get = storey.MutateGenericMethod (get);
+                       if (set != null)
+                               set = storey.MutateGenericMethod (set);
+
+                       instance_expr.MutateHoistedGenericType (storey);
+                       foreach (Argument a in arguments)
+                               a.Expr.MutateHoistedGenericType (storey);
+
+                       type = storey.MutateType (type);
+               }
+
                protected override void CloneTo (CloneContext clonectx, Expression t)
                {
                        IndexerAccess target = (IndexerAccess) t;
@@ -8411,6 +8634,11 @@ namespace Mono.CSharp {
                        this.args = args;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       throw new NotSupportedException ("ET");
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        Expression c = CommonResolve (ec);
@@ -8448,13 +8676,12 @@ namespace Mono.CSharp {
                        Type current_type = ec.ContainerType;
                        Type base_type = current_type.BaseType;
 
-                       if (ec.IsStatic){
-                               Error (1511, "Keyword `base' is not available in a static method");
-                               return null;
-                       }
-
-                       if (ec.IsInFieldInitializer){
-                               Error (1512, "Keyword `base' is not available in the current context");
+                       if (!This.IsThisAvailable (ec)) {
+                               if (ec.IsStatic) {
+                                       Error (1511, "Keyword `base' is not available in a static method");
+                               } else {
+                                       Error (1512, "Keyword `base' is not available in the current context");
+                               }
                                return null;
                        }
                        
@@ -8527,6 +8754,12 @@ namespace Mono.CSharp {
 
                        return true;
                }
+
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       MemberExpr.Error_BaseAccessInExpressionTree (loc);
+                       return base.CreateExpressionTree (ec);
+               }
        }
        
        /// <summary>
@@ -8540,11 +8773,12 @@ namespace Mono.CSharp {
        ///   is needed (the `New' class).
        /// </summary>
        public class EmptyExpression : Expression {
-               public static readonly EmptyExpression Null = new EmptyExpression ();
+               public static readonly Expression Null = new EmptyExpression ();
 
                public static readonly EmptyExpression OutAccess = new EmptyExpression ();
                public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
                public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
+               public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
 
                static EmptyExpression temp = new EmptyExpression ();
                public static EmptyExpression Grab ()
@@ -8573,6 +8807,11 @@ namespace Mono.CSharp {
                        eclass = ExprClass.Value;
                        loc = Location.Null;
                }
+
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       throw new NotSupportedException ("ET");
+               }
                
                public override Expression DoResolve (EmitContext ec)
                {
@@ -8613,6 +8852,11 @@ namespace Mono.CSharp {
                        loc = Location.Null;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       return null;
+               }
+
                public override void EmitStatement (EmitContext ec)
                {
                        // Do nothing
@@ -8650,7 +8894,7 @@ namespace Mono.CSharp {
 
                public override Expression CreateExpressionTree (EmitContext ec)
                {
-                       ArrayList args = new ArrayList (2);
+                       ArrayList args = new ArrayList (3);
                        args.Add (new Argument (source.CreateExpressionTree (ec)));
                        args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
                        args.Add (new Argument (new TypeOfMethodInfo (method, loc)));
@@ -8670,6 +8914,12 @@ namespace Mono.CSharp {
                        source.Emit (ec);
                        ec.ig.Emit (OpCodes.Call, method);
                }
+
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       source.MutateHoistedGenericType (storey);
+                       method = storey.MutateGenericMethod (method);
+               }
        }
 
        // <summary>
@@ -8694,17 +8944,6 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
-               public Expression RemoveNullable ()
-               {
-                       if (dim.EndsWith ("?")) {
-                               dim = dim.Substring (0, dim.Length - 1);
-                               if (dim.Length == 0)
-                                       return left;
-                       }
-
-                       return this;
-               }
-
                protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
                {
                        TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
@@ -8712,11 +8951,6 @@ namespace Mono.CSharp {
                                return null;
 
                        Type ltype = lexpr.Type;
-                       if ((ltype == TypeManager.void_type) && (dim != "*")) {
-                               Error_VoidInvalidInTheContext (loc);
-                               return null;
-                       }
-
 #if GMCS_SOURCE
                        if ((dim.Length > 0) && (dim [0] == '?')) {
                                TypeExpr nullable = new Nullable.NullableType (left, loc);
@@ -8729,10 +8963,17 @@ namespace Mono.CSharp {
                        if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
                                return null;
 
-                       if (dim != "" && dim [0] == '[' &&
-                           (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
-                               Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
-                               return null;
+                       if (dim.Length != 0 && dim [0] == '[') {
+                               if (TypeManager.IsSpecialType (ltype)) {
+                                       Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
+                                       return null;
+                               }
+
+                               if ((ltype.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
+                                       Report.SymbolRelatedToPreviousError (ltype);
+                                       Report.Error (719, loc, "Array elements cannot be of static type `{0}'", 
+                                               TypeManager.CSharpName (ltype));
+                               }
                        }
 
                        if (dim != "")
@@ -8745,7 +8986,6 @@ namespace Mono.CSharp {
 
                        if (type.IsPointer && !ec.IsInUnsafeScope){
                                UnsafeError (loc);
-                               return null;
                        }
 
                        eclass = ExprClass.Type;
@@ -8777,6 +9017,12 @@ namespace Mono.CSharp {
                        eclass = ExprClass.Value;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       Error_PointerInsideExpressionTree ();
+                       return null;
+               }
+
                public override void Emit(EmitContext ec)
                {
                        array.Emit (ec);
@@ -8819,34 +9065,24 @@ namespace Mono.CSharp {
        //
        // Encapsulates a conversion rules required for array indexes
        //
-       public class ArrayIndexCast : Expression
+       public class ArrayIndexCast : TypeCast
        {
-               Expression expr;
-
                public ArrayIndexCast (Expression expr)
+                       : base (expr, expr.Type)
                {
-                       this.expr = expr;
-                       this.loc = expr.Location;
                }
 
                public override Expression CreateExpressionTree (EmitContext ec)
                {
                        ArrayList args = new ArrayList (2);
-                       args.Add (new Argument (expr.CreateExpressionTree (ec)));
+                       args.Add (new Argument (child.CreateExpressionTree (ec)));
                        args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
                        return CreateExpressionFactoryCall ("ConvertChecked", args);
                }
 
-               public override Expression DoResolve (EmitContext ec)
-               {
-                       type = expr.Type;
-                       eclass = expr.eclass;
-                       return this;
-               }
-
                public override void Emit (EmitContext ec)
                {
-                       expr.Emit (ec);
+                       child.Emit (ec);
                                
                        if (type == TypeManager.int32_type)
                                return;
@@ -8862,45 +9098,6 @@ namespace Mono.CSharp {
                }
        }
 
-       //
-       // Used by the fixed statement
-       //
-       public class StringPtr : Expression {
-               LocalBuilder b;
-               
-               public StringPtr (LocalBuilder b, Location l)
-               {
-                       this.b = b;
-                       eclass = ExprClass.Value;
-                       type = TypeManager.char_ptr_type;
-                       loc = l;
-               }
-
-               public override Expression DoResolve (EmitContext ec)
-               {
-                       // This should never be invoked, we are born in fully
-                       // initialized state.
-
-                       return this;
-               }
-
-               public override void Emit (EmitContext ec)
-               {
-                       if (TypeManager.int_get_offset_to_string_data == null) {
-                               // TODO: Move to resolve !!
-                               TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedMethod (
-                                       TypeManager.runtime_helpers_type, "get_OffsetToStringData", loc, Type.EmptyTypes);
-                       }
-
-                       ILGenerator ig = ec.ig;
-
-                       ig.Emit (OpCodes.Ldloc, b);
-                       ig.Emit (OpCodes.Conv_I);
-                       ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
-                       ig.Emit (OpCodes.Add);
-               }
-       }
-       
        //
        // Implements the `stackalloc' keyword
        //
@@ -8916,13 +9113,18 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       throw new NotSupportedException ("ET");
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        count = count.Resolve (ec);
                        if (count == null)
                                return null;
                        
-                       if (count.Type != TypeManager.int32_type){
+                       if (count.Type != TypeManager.uint32_type){
                                count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
                                if (count == null)
                                        return null;
@@ -8958,13 +9160,15 @@ namespace Mono.CSharp {
                {
                        int size = GetTypeSize (otype);
                        ILGenerator ig = ec.ig;
-                               
+
+                       count.Emit (ec);
+
                        if (size == 0)
                                ig.Emit (OpCodes.Sizeof, otype);
                        else
                                IntConstant.EmitInt (ig, size);
-                       count.Emit (ec);
-                       ig.Emit (OpCodes.Mul);
+
+                       ig.Emit (OpCodes.Mul_Ovf_Un);
                        ig.Emit (OpCodes.Localloc);
                }
 
@@ -8988,6 +9192,12 @@ namespace Mono.CSharp {
                {
                        this.Name = name;
                }
+               
+               protected override void CloneTo (CloneContext clonectx, Expression t)
+               {
+                       ElementInitializer target = (ElementInitializer) t;
+                       target.source = source.Clone (clonectx);
+               }
 
                public override Expression CreateExpressionTree (EmitContext ec)
                {
@@ -9107,6 +9317,15 @@ namespace Mono.CSharp {
                        return CreateExpressionFactoryCall ("ElementInit", args);
                }
 
+               protected override void CloneTo (CloneContext clonectx, Expression t)
+               {
+                       CollectionElementInitializer target = (CollectionElementInitializer) t;
+
+                       target.Arguments = new ArrayList (Arguments.Count);
+                       foreach (Expression e in Arguments)
+                               target.Arguments.Add (e.Clone (clonectx));
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        if (eclass != ExprClass.Invalid)
@@ -9116,7 +9335,11 @@ namespace Mono.CSharp {
                        // for known types like List<T>, Dictionary<T, U>
                        
                        for (int i = 0; i < Arguments.Count; ++i) {
-                               Expression expr = ((Expression) Arguments [i]).Resolve (ec);
+                               Expression expr = Arguments [i] as Expression;
+                               if (expr == null)
+                                       return null;
+
+                               expr = expr.Resolve (ec);
                                if (expr == null)
                                        return null;
 
@@ -9245,6 +9468,12 @@ namespace Mono.CSharp {
                        foreach (ExpressionStatement e in initializers)
                                e.EmitStatement (ec);
                }
+
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       foreach (Expression e in initializers)
+                               e.MutateHoistedGenericType (storey);
+               }
        }
        
        //
@@ -9272,7 +9501,7 @@ namespace Mono.CSharp {
                        public override Expression CreateExpressionTree (EmitContext ec)
                        {
                                // Should not be reached
-                               throw new NotSupportedException ();
+                               throw new NotSupportedException ("ET");
                        }
 
                        public override Expression DoResolve (EmitContext ec)
@@ -9344,7 +9573,7 @@ namespace Mono.CSharp {
                        ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
                        initializers.Resolve (ec);
                        ec.CurrentInitializerVariable = previous;
-                       return this;
+                       return e;
                }
 
                public override void Emit (EmitContext ec)
@@ -9352,15 +9581,16 @@ namespace Mono.CSharp {
                        base.Emit (ec);
 
                        //
-                       // If target is a value, let's use it
+                       // If target is non-hoisted variable, let's use it
                        //
                        VariableReference variable = value_target as VariableReference;
-                       if (variable != null) {
+                       if (variable != null && variable.HoistedVariable == null) {
                                if (variable.IsRef)
                                        StoreFromPtr (ec.ig, type);
                                else
-                                       variable.Variable.EmitAssign (ec);
+                                       variable.EmitAssign (ec, EmptyExpression.Null, false, false);
                        } else {
+                               variable = null;
                                if (value_target == null || value_target_set)
                                        value_target = new LocalTemporary (type);
 
@@ -9369,8 +9599,10 @@ namespace Mono.CSharp {
 
                        initializers.Emit (ec);
 
-                       if (variable == null)
+                       if (variable == null) {
                                value_target.Emit (ec);
+                               value_target = null;
+                       }
                }
 
                public override void EmitStatement (EmitContext ec)
@@ -9396,6 +9628,12 @@ namespace Mono.CSharp {
                                return !initializers.IsEmpty;
                        }
                }
+
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       base.MutateHoistedGenericType (storey);
+                       initializers.MutateHoistedGenericType (storey);
+               }
        }
 
        public class AnonymousTypeDeclaration : Expression
@@ -9436,11 +9674,17 @@ namespace Mono.CSharp {
                        type.DefineMembers ();
                        type.Define ();
                        type.EmitType ();
+                       type.CloseType ();
 
                        RootContext.ToplevelTypes.AddAnonymousType (type);
                        return type;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       throw new NotSupportedException ("ET");
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        AnonymousTypeClass anonymous_type;
@@ -9509,6 +9753,11 @@ namespace Mono.CSharp {
                        t.initializer = initializer.Clone (clonectx);
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       throw new NotSupportedException ("ET");
+               }
+
                public override bool Equals (object o)
                {
                        AnonymousTypeParameter other = o as AnonymousTypeParameter;
@@ -9526,20 +9775,25 @@ namespace Mono.CSharp {
                        if (e == null)
                                return null;
 
+                       if (e.eclass == ExprClass.MethodGroup) {
+                               Error_InvalidInitializer (e.ExprClassName);
+                               return null;
+                       }
+
                        type = e.Type;
                        if (type == TypeManager.void_type || type == TypeManager.null_type ||
                                type == TypeManager.anonymous_method_type || type.IsPointer) {
-                               Error_InvalidInitializer (e);
+                               Error_InvalidInitializer (e.GetSignatureForError ());
                                return null;
                        }
 
                        return e;
                }
 
-               protected virtual void Error_InvalidInitializer (Expression initializer)
+               protected virtual void Error_InvalidInitializer (string initializer)
                {
                        Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
-                               Name, initializer.GetSignatureForError ());
+                               Name, initializer);
                }
 
                public override void Emit (EmitContext ec)